%% options %% header /** @defgroup coressrc Source for cores information */ /**@{*/ /** No information found. */ #define DK3_CORES_SRC_NONE (-1) /** System call succeeded. */ #define DK3_CORES_SRC_SYSTEM 0 /** Environment variable NUMBER_OF_PROCESSORS on Windows. */ #define DK3_CORES_SRC_ENVIRONMENT 1 /** File /proc/cpuinfo on *x systems. */ #define DK3_CORES_SRC_CPUINFO 2 /** The /threads/max preference. */ #define DK3_CORES_SRC_PREFERENCE 3 /**@}*/ #ifdef __cplusplus extern "C" { #endif /** Retrieve number of processor cores on system. @param src Pointer to information source indicator variable, may be NULL. @return Number of processor cores found. */ size_t dk3cores_get_num(int *src); /** Check whether we run on WOW6432. @return 1 for WOW6432, 0 otherwise. */ int dk3cores_is_wow64(void); /** Get maximum number of threads. The number is retrieved from the /threads/max preference if available, or derived from the number of cores available (back = (n > 2) ? (n - 1) : 1) to leave one core for @param app Application to use for preferences retrieval. @param src Pointer to information source indicator variable, may be NULL. @return Number of threas to use maximally. */ size_t dk3cores_max_threads(dk3_app_t *app, int *src); #ifdef __cplusplus } #endif %% module #ifndef _WIN32_WINNT /** On Windows use minimum Windows version required for functions in this module. */ #define _WIN32_WINNT 0x0501 #endif #include "dk3all.h" #if MACOS || DK3_HAVE_SYS_SYSCTL_H #include #endif #include "dk3cores.h" $!trace-include #if DK3_ON_WINDOWS typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); typedef void (WINAPI *LPFN_GETSYSTEMINFO) (LPSYSTEM_INFO); #endif int dk3cores_is_wow64(void) { int back = 0; #if DK3_ON_WINDOWS LPFN_ISWOW64PROCESS fnIsWow64Process; /* Function address */ BOOL bIsWow64 = FALSE; /* Flag: Is Wow64 process. */ #if DK3_CHAR_SIZE > 1 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandleW( L"kernel32" ), "IsWow64Process" ); #else fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandleA("kernel32"), "IsWow64Process" ); #endif if(NULL != fnIsWow64Process) { if(fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { if(bIsWow64) { back = 1; } } } #endif return back; } #if !DK3_ON_WINDOWS /** Compare two unsigned long numbers. @param l Pointer to left number. @param r Pointer to right number. @param cr Comparison criteria, ignored. @return Comparison result. */ static int dk3cores_compare_lu(void const *l, void const *r, int cr) { int back = 0; unsigned long const *ull; unsigned long const *ulr; if(l) { if(r) { ull = (unsigned long const *)l; ulr = (unsigned long const *)r; if((*ull) > (*ulr)) { back = 1; } else { if((*ull) < (*ulr)) { back = -1; } } } else back = 1; } else { if(r) back = -1; } return back; } /** Retrieve number of cores from /proc/cpuinfo. @param src Pointer to information source indicator variable. @return Number of cores found, 1 for default. */ static size_t dk3cores_from_proc_cpuinfo(int *src) { char line[1024]; /* Input text line buffer. */ FILE *fipo = NULL; /* Input file. */ char *pc = NULL; /* Current word pointer. */ char *pn = NULL; /* Next text pointer. */ dk3_sto_t *scores = NULL; /* Storage for found core numbers. */ dk3_sto_it_t *icores = NULL; /* Iterator through core numbers storage. */ unsigned long *ulp = NULL; /* New unsigned long memory. */ unsigned long ul = 0UL; /* Result variable for sscanf(). */ unsigned long maxul = 0UL; /* Maximum core ID found so far. */ int memerr = 0; /* Flag: Memory allocation error occured. */ size_t back = 0; $? "+ dk3cores_from_proc_cpuinfo" scores = dk3sto_open_app(NULL); if(scores) { dk3sto_set_comp(scores, dk3cores_compare_lu, 0); icores = dk3sto_it_open(scores); if(icores) { fipo = fopen("/proc/cpuinfo", "r"); if(fipo) { while(fgets(line, sizeof(line), fipo)) { pc = dk3str_c8_start(line, NULL); if(pc) { dk3str_c8_delnl(line); $? ". process \"%s\"", line pn = dk3str_c8_next(pc, NULL); if(0 == strcmp(pc, "core")) { pc = pn; if(pc) { pn = dk3str_c8_next(pc, NULL); if(0 == strcmp(pc, "id")) { pc = pn; if(pc) { if(':' == *pc) { pc++; #if VERSION_BEFORE_20140716 if(1 == sscanf(pc, "%lu", &ul)) #else if(0 != dk3ma_ul_from_c8_string(&ul, pc, NULL)) #endif { $? ". %lu", ul if(ul > maxul) { maxul = ul; } *src = DK3_CORES_SRC_CPUINFO; ulp = (unsigned long *)dk3sto_it_find_like( icores, (void *)(&ul), 0 ); if(NULL == ulp) { ulp = dk3_new(unsigned long,1); if(ulp) { if(!dk3sto_add(scores, (void *)ulp)) { memerr = 1; } } else { memerr = 1; } } } } } } } } } } fclose(fipo); } else { $? "! fopen" } dk3sto_it_reset(icores); while(NULL != (ulp = (unsigned long *)dk3sto_it_next(icores))) { back++; $? ". yet another core" dk3_delete(ulp); } dk3sto_it_close(icores); } else { $? "! icores" memerr = 1; } dk3sto_close(scores); } else { $? "! scores" memerr = 1; } if(memerr) { $? "! memory error" if(back < (size_t)(maxul + 1UL)) { $? "! use maxul" back = (size_t)(maxul + 1UL); } } if(back < 1) { $? "! correction necessary" back = 1; } $? "- dk3cores_from_proc_cpuinfo %lu", (unsigned long)back return back; } #endif size_t dk3cores_get_num(int *src) { size_t back = 1; int found = DK3_CORES_SRC_NONE; #if DK3_ON_WINDOWS SYSTEM_INFO si; /* System information structure. */ LPFN_GETSYSTEMINFO fngetsysteminfo; /* Function address. */ char *ptr; /* Environment variable text. */ unsigned u; /* Core number from environment. */ #elif MACOS || (DK3_HAVE_SYSCTL && defined(CTL_HW) && defined(HW_AVAILCPU) && defined(HW_NCPU)) uint32_t count = 0; /* Number of cores found. */ size_t len = 0; /* Argument length for sysctl(). */ int mib[4]; /* Mib for sysctl(). */ int scres = 0; /* Result from sysctl(). */ #endif $? "+ dk3cores_get_num" #if DK3_ON_WINDOWS if(dk3cores_is_wow64()) { $? ". windows wow6432" #if DK3_CHAR_SIZE > 1 fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleW( L"kernel32" ), "GetNativeSystemInfo" ); #else fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleA("kernel32"), "GetNativeSystemInfo" ); #endif if(NULL != fngetsysteminfo) { $? ". GetNativeSystemInfo" fngetsysteminfo(&si); found = DK3_CORES_SRC_SYSTEM; back = (size_t)(si.dwNumberOfProcessors); } else { $? "! GetNativeSystemInfo" #if DK3_CHAR_SIZE > 1 fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleW( L"kernel32" ), "GetSystemInfo" ); #else fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleA("kernel32"), "GetSystemInfo" ); #endif if(NULL != fngetsysteminfo) { $? ". GetSystemInfo" fngetsysteminfo(&si); found = DK3_CORES_SRC_SYSTEM; back = (size_t)(si.dwNumberOfProcessors); } else { $? "! GetSystemInfo" } } } else { $? ". windows native" #if DK3_CHAR_SIZE > 1 fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleW( L"kernel32" ), "GetSystemInfo" ); #else fngetsysteminfo = (LPFN_GETSYSTEMINFO)GetProcAddress( GetModuleHandleA("kernel32"), "GetSystemInfo" ); #endif if(NULL != fngetsysteminfo) { $? ". GetSystemInfo" fngetsysteminfo(&si); found = DK3_CORES_SRC_SYSTEM; back = (size_t)(si.dwNumberOfProcessors); } else { $? "! GetSystemInfo" } } if((DK3_CORES_SRC_NONE == found) || (back < 1)) { $? ". check environment" ptr = getenv("NUMBER_OF_PROCESSORS"); if(ptr) { $? ". found" #if VERSION_BEFORE_20140716 if(1 == sscanf(ptr, "%u", &u)) #else if (0 != dk3ma_ui_from_c8_string(&u, ptr, NULL)) #endif { $? ". number" back = (size_t)u; found = DK3_CORES_SRC_ENVIRONMENT; } else { $? "! not numeric" } } else { $? "! NUMBER_OF_PROCESSORS" } } #elif DK3_HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN) $? ". sysconf (1)" back = (size_t)sysconf(_SC_NPROCESSORS_ONLN); found = DK3_CORES_SRC_SYSTEM; #elif DK3_HAVE_SYSCONF && defined(_SC_NPROC_ONLN) $? ". sysconf (2)" back = (size_t)sysconf(_SC_NPROC_ONLN); found = DK3_CORES_SRC_SYSTEM; #elif DK3_HAVE_MPCTL && defined(MPC_GETNUMSPUS) $? ". mpctl (1)" back = (size_t)mpctl(MPC_GETNUMSPUS, NULL, NULL); found = DK3_CORES_SRC_SYSTEM; #elif DK3_HAVE_MPCTL && defined(MPC_GETNUMCPUS) $? ". mpctl (2)" back = (size_t)mpctl(MPC_GETNUMCPUS, NULL, NULL); found = DK3_CORES_SRC_SYSTEM; #elif MACOS || (DK3_HAVE_SYSCTL && defined(CTL_HW) && defined(HW_AVAILCPU) && defined(HW_NCPU)) $? ". sysctl (hope we are on Mac or BSD here)" mib[0] = CTL_HW; mib[1] = HW_AVAILCPU; len = sizeof(count); scres = sysctl(mib, 2, &count, &len, NULL, 0); if((0 != scres) || (count < 1)) { $? "! HW_AVAILCPU" mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof(count); scres = sysctl(mib, 2, &count, &len, NULL, 0); if((0 == scres) && (count > 0)) { $? ". HW_NCPU" back = (size_t)count; found = DK3_CORES_SRC_SYSTEM; } } else { $? ". HW_AVAILCPU" back = (size_t)count; found = DK3_CORES_SRC_SYSTEM; } #endif #if !DK3_ON_WINDOWS if((DK3_CORES_SRC_NONE == found)) { $? "! no value found" back = dk3cores_from_proc_cpuinfo(&found); } #endif if(back < 1) { $? "! correction necessary" back = 1; } if(src) { *src = found; } $? "- dk3cores_get_num %lu", (unsigned long)back return back; } size_t dk3cores_max_threads(dk3_app_t *app, int *src) { dkChar line[128]; /* Result buffer for preferences .*/ unsigned long ul; /* Result variable for sscanf(). */ size_t back = 0; size_t cores = 0; /* Number of cores found. */ size_t x; /* Result variable for sscanf(). */ int found = DK3_CORES_SRC_NONE; /* Information source. */ $? "+ dk3cores_max_threads" /* Derive number of threads from number of cores. */ cores = back = dk3cores_get_num(&found); if(back > 2) { back = back - 1; } /* Check /threads/max preference, attempt to use it. */ if(app) { if(dk3app_get_pref(app,dkT("/threads/max"),line,DK3_SIZEOF(line,dkChar))) { #if VERSION_BEFORE_20140716 if(1 == dk3sf_sscanf3(line, dkT("%lu"), &ul)) #else if (0 != dk3ma_ul_from_string(&ul, line, NULL)) #endif { x = (size_t)ul; if(x > back) { dk3app_log_i1(app, DK3_LL_DEBUG, 365); } found = DK3_CORES_SRC_PREFERENCE; back = x; } else { if(0 == dk3str_cmp(dkT("cores"), line)) { back = cores; } } } } /* Apply corrections if no value was found. */ if(back < 1) { back = 1; } if(src) { *src = found; } $? "- dk3cores_max_threads" return back; }