Add hwloc as a dependency, and use it to retrieve CPU and cache topology info on FreeBSD.
-- v7: ntdll: implement create_logical_proc_info on FreeBSD.
From: Damjan Jovanovic damjan.jov@gmail.com
Add hwloc as a dependency, and use it to retrieve CPU and cache topology info on FreeBSD. --- configure.ac | 15 ++++ dlls/ntdll/Makefile.in | 4 +- dlls/ntdll/unix/system.c | 143 +++++++++++++++++++++++++++++++++++++++ include/config.h.in | 3 + 4 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index 51572bdae66..fda3147252d 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,7 @@ AC_ARG_WITH(gphoto, AS_HELP_STRING([--without-gphoto],[do not use gphoto (Dig AC_ARG_WITH(gnutls, AS_HELP_STRING([--without-gnutls],[do not use GnuTLS (schannel support)])) AC_ARG_WITH(gssapi, AS_HELP_STRING([--without-gssapi],[do not use GSSAPI (Kerberos SSP support)])) AC_ARG_WITH(gstreamer, AS_HELP_STRING([--without-gstreamer],[do not use GStreamer (codecs support)])) +AC_ARG_WITH(hwloc, AS_HELP_STRING([--without-hwloc],[do not use hwloc (CPU/cache topology detection)])) AC_ARG_WITH(inotify, AS_HELP_STRING([--without-inotify],[do not use inotify (filesystem change notifications)])) AC_ARG_WITH(krb5, AS_HELP_STRING([--without-krb5],[do not use krb5 (Kerberos)])) AC_ARG_WITH(mingw, AS_HELP_STRING([--without-mingw],[do not use the MinGW cross-compiler])) @@ -1519,6 +1520,20 @@ fi WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"], [libgnutls ${notice_platform}development files not found, no schannel support.])
+dnl **** Check for hwloc *** +if test "x$with_hwloc" != "xno" -a `expr "$host_os" : '(freebsd).*'` = "freebsd" +then + WINE_PACKAGE_FLAGS(HWLOC,[hwloc],,,, + [AC_CHECK_HEADER([hwloc.h], + [AC_CHECK_LIB(hwloc,hwloc_topology_init, + [AC_DEFINE(HAVE_LIBHWLOC, 1, [Define to 1 if you have the 'hwloc' library (-lhwloc).])], + [HWLOC_LIBS=""], + [$HWLOC_LIBS])], + [HWLOC_LIBS=""])]) + WINE_NOTICE_WITH(hwloc,[test "$ac_cv_lib_hwloc_hwloc_topology_init" != "yes"], + [hwloc ${notice_platform}development files not found, detailed CPU info on FreeBSD won't be supported.]) +fi + dnl **** Check for SANE **** if test "x$with_sane" != "xno" then diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index f7558bb5d86..3c0dfa7a895 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -4,8 +4,8 @@ UNIXLIB = ntdll.so IMPORTLIB = ntdll IMPORTS = $(TOMCRYPT_PE_LIBS) $(MUSL_PE_LIBS) EXTRAINCL = $(TOMCRYPT_PE_CFLAGS) -UNIX_CFLAGS = $(UNWIND_CFLAGS) -UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) +UNIX_CFLAGS = $(UNWIND_CFLAGS) $(HWLOC_CFLAGS) +UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS)
EXTRADLLFLAGS = -nodefaultlibs i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000 diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 342e443f5e7..2bfb9b414b5 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -69,6 +69,10 @@ # include <mach/vm_map.h> #endif
+#if defined(HAVE_LIBHWLOC) +# include <hwloc.h> +#endif + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -1339,6 +1343,145 @@ static NTSTATUS create_logical_proc_info(void) return STATUS_SUCCESS; }
+#elif defined(__FreeBSD__) || defined(__FreeBSD__kernel__) + +#if defined(HAVE_LIBHWLOC) +static NTSTATUS add_hwloc_cache(hwloc_obj_t obj, int level) +{ + CACHE_DESCRIPTOR cache; + + memset(&cache, 0, sizeof(cache)); + cache.Level = level; + if (obj->attr) + { + cache.Associativity = obj->attr->cache.associativity; + cache.LineSize = obj->attr->cache.linesize; + cache.Size = obj->attr->cache.size; + switch (obj->attr->cache.type) + { + case HWLOC_OBJ_CACHE_UNIFIED: + cache.Type = CacheUnified; + break; + case HWLOC_OBJ_CACHE_DATA: + cache.Type = CacheData; + break; + case HWLOC_OBJ_CACHE_INSTRUCTION: + cache.Type = CacheInstruction; + break; + default: + break; + } + } + if (!logical_proc_info_add_cache(hwloc_bitmap_to_ulong(obj->cpuset), &cache)) + return STATUS_NO_MEMORY; + return STATUS_SUCCESS; +} + +static NTSTATUS add_hwloc_numa_nodes(hwloc_topology_t topology) +{ + hwloc_obj_t obj; + + for (obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, 0); obj != NULL; obj = obj->next_cousin) + { + if (!logical_proc_info_add_numa_node(obj->logical_index, hwloc_bitmap_to_ulong(obj->cpuset))) + return STATUS_NO_MEMORY; + } + return STATUS_SUCCESS; +} + +static NTSTATUS traverse_hwloc_topology(hwloc_obj_t obj) +{ + int i; + NTSTATUS nt_status = STATUS_SUCCESS; + + switch (obj->type) + { + case HWLOC_OBJ_PACKAGE: + if (!logical_proc_info_add_by_id(RelationProcessorPackage, obj->logical_index, hwloc_bitmap_to_ulong(obj->cpuset))) + return STATUS_NO_MEMORY; + break; + case HWLOC_OBJ_CORE: + if (!logical_proc_info_add_by_id(RelationProcessorCore, obj->logical_index, hwloc_bitmap_to_ulong(obj->cpuset))) + return STATUS_NO_MEMORY; + break; + case HWLOC_OBJ_L1CACHE: + case HWLOC_OBJ_L1ICACHE: + nt_status = add_hwloc_cache(obj, 1); + break; + case HWLOC_OBJ_L2CACHE: + case HWLOC_OBJ_L2ICACHE: + nt_status = add_hwloc_cache(obj, 2); + break; + case HWLOC_OBJ_L3CACHE: + case HWLOC_OBJ_L3ICACHE: + nt_status = add_hwloc_cache(obj, 3); + break; + case HWLOC_OBJ_L4CACHE: + nt_status = add_hwloc_cache(obj, 4); + break; + case HWLOC_OBJ_L5CACHE: + nt_status = add_hwloc_cache(obj, 5); + break; + default: + break; + } + + for (i = 0; i < obj->arity && nt_status == STATUS_SUCCESS; i++) + nt_status = traverse_hwloc_topology(obj->children[i]); + return nt_status; +} +#endif + +static NTSTATUS create_logical_proc_info(void) +{ +#if defined(HAVE_LIBHWLOC) + NTSTATUS nt_status = STATUS_SUCCESS; + int ret; + hwloc_topology_t topology; + hwloc_obj_t root_obj; + + ret = hwloc_topology_init(&topology); + if (ret != 0) + return STATUS_NO_MEMORY; + + hwloc_topology_set_icache_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_ALL); + ret = hwloc_topology_load(topology); + if (ret != 0) + { + nt_status = STATUS_NO_MEMORY; + goto end; + } + + root_obj = hwloc_get_root_obj(topology); + if (root_obj == NULL) + { + nt_status = STATUS_NO_MEMORY; + goto end; + } + + nt_status = traverse_hwloc_topology(root_obj); + if (nt_status != STATUS_SUCCESS) + goto end; + + nt_status = add_hwloc_numa_nodes(topology); + if (nt_status != STATUS_SUCCESS) + goto end; + + if (!logical_proc_info_add_group(hwloc_get_nbobjs_by_type(topology, HWLOC_OBJ_PU), hwloc_bitmap_to_ulong(root_obj->cpuset))) + { + nt_status = STATUS_NO_MEMORY; + goto end; + } + +end: + hwloc_topology_destroy(topology); + return nt_status; +#else + FIXME("hwloc unavailable, cannot detect CPU/cache topology info\n"); + return STATUS_NOT_IMPLEMENTED; +#endif +} + #else
static NTSTATUS create_logical_proc_info(void) diff --git a/include/config.h.in b/include/config.h.in index b5b57d8fd7b..f344446bae1 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -138,6 +138,9 @@ /* Define to 1 if you have the 'gettextpo' library (-lgettextpo). */ #undef HAVE_LIBGETTEXTPO
+/* Define to 1 if you have the 'hwloc' library (-lhwloc). */ +#undef HAVE_LIBHWLOC + /* Define to 1 if you have the 'procstat' library (-lprocstat). */ #undef HAVE_LIBPROCSTAT
On Mon Oct 6 05:46:01 2025 +0000, Gerald Pfeifer wrote:
From a FreeBSD (packaging) perspective I can see this is a fine alternative. It adds two additional dependencies - devel/hwloc and devel/libpciaccess - which appear to be reasonably light. Happy to leave the choice to you. It just would be nice to either get the current patch pushed or an alternate one that you hint at. @bshanks, for the time being, is there any obstacle to the former?
I've now changed it to use hwloc instead of parsing kernel data with expat, which is simpler and shorter and adds full cache topology info.
Tested this out and it looks good to me. [devel/hwloc2](https://www.freshports.org/devel/hwloc2/) has pretty minimal dependencies (libxml2, libpciaccess, something called level-zero), provides cache info also, and is easier than parsing XML ourselves. Plus it could be used on NetBSD or other OSes if we didn't want to populate this info ourselves.