/*-****************************************
-* count the number of physical cores
+* count the number of cores
******************************************/
#if defined(_WIN32) || defined(WIN32)
typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
-int UTIL_countPhysicalCores(void)
+DWORD CountSetBits(ULONG_PTR bitMask)
+{
+ DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
+ DWORD bitSetCount = 0;
+ ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;
+ DWORD i;
+
+ for (i = 0; i <= LSHIFT; ++i)
+ {
+ bitSetCount += ((bitMask & bitTest)?1:0);
+ bitTest/=2;
+ }
+
+ return bitSetCount;
+}
+
+int UTIL_countCores(int logical)
{
- static int numPhysicalCores = 0;
- if (numPhysicalCores != 0) return numPhysicalCores;
+ static int numCores = 0;
+ if (numCores != 0) return numCores;
{ LPFN_GLPI glpi;
BOOL done = FALSE;
while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
if (ptr->Relationship == RelationProcessorCore) {
- numPhysicalCores++;
+ if (logical)
+ numCores += CountSetBits(ptr->ProcessorMask);
+ else
+ numCores++;
}
ptr++;
free(buffer);
- return numPhysicalCores;
+ return numCores;
}
failed:
/* try to fall back on GetSystemInfo */
{ SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
- numPhysicalCores = sysinfo.dwNumberOfProcessors;
- if (numPhysicalCores == 0) numPhysicalCores = 1; /* just in case */
+ numCores = sysinfo.dwNumberOfProcessors;
+ if (numCores == 0) numCores = 1; /* just in case */
}
- return numPhysicalCores;
+ return numCores;
}
#elif defined(__APPLE__)
/* Use apple-provided syscall
* see: man 3 sysctl */
-int UTIL_countPhysicalCores(void)
+int UTIL_countCores(int logical)
{
- static S32 numPhysicalCores = 0; /* apple specifies int32_t */
- if (numPhysicalCores != 0) return numPhysicalCores;
+ static S32 numCores = 0; /* apple specifies int32_t */
+ if (numCores != 0) return numCores;
{ size_t size = sizeof(S32);
- int const ret = sysctlbyname("hw.physicalcpu", &numPhysicalCores, &size, NULL, 0);
+ int const ret = sysctlbyname(logical ? "hw.logicalcpu" : "hw.physicalcpu", &numCores, &size, NULL, 0);
if (ret != 0) {
if (errno == ENOENT) {
/* entry not present, fall back on 1 */
- numPhysicalCores = 1;
+ numCores = 1;
} else {
- perror("zstd: can't get number of physical cpus");
+ perror("zstd: can't get number of cpus");
exit(1);
}
}
- return numPhysicalCores;
+ return numCores;
}
}
/* parse /proc/cpuinfo
* siblings / cpu cores should give hyperthreading ratio
* otherwise fall back on sysconf */
-int UTIL_countPhysicalCores(void)
+int UTIL_countCores(int logical)
{
- static int numPhysicalCores = 0;
+ static int numCores = 0;
- if (numPhysicalCores != 0) return numPhysicalCores;
+ if (numCores != 0) return numCores;
- numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
- if (numPhysicalCores == -1) {
+ numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ if (numCores == -1) {
/* value not queryable, fall back on 1 */
- return numPhysicalCores = 1;
+ return numCores = 1;
}
/* try to determine if there's hyperthreading */
if (cpuinfo == NULL) {
/* fall back on the sysconf value */
- return numPhysicalCores;
+ return numCores;
}
/* assume the cpu cores/siblings values will be constant across all
ratio = siblings / cpu_cores;
}
- if (ratio && numPhysicalCores > ratio) {
- numPhysicalCores = numPhysicalCores / ratio;
+ if (ratio && numCores > ratio && !logical) {
+ numCores = numCores / ratio;
}
failed:
fclose(cpuinfo);
- return numPhysicalCores;
+ return numCores;
}
}
/* Use physical core sysctl when available
* see: man 4 smp, man 3 sysctl */
-int UTIL_countPhysicalCores(void)
+int UTIL_countCores(int logical)
{
- static int numPhysicalCores = 0; /* freebsd sysctl is native int sized */
- if (numPhysicalCores != 0) return numPhysicalCores;
+ static int numCores = 0; /* freebsd sysctl is native int sized */
+#if __FreeBSD_version >= 1300008
+ static int perCore = 1;
+#endif
+ if (numCores != 0) return numCores;
#if __FreeBSD_version >= 1300008
- { size_t size = sizeof(numPhysicalCores);
- int ret = sysctlbyname("kern.smp.cores", &numPhysicalCores, &size, NULL, 0);
- if (ret == 0) return numPhysicalCores;
+ { size_t size = sizeof(numCores);
+ int ret = sysctlbyname("kern.smp.cores", &numCores, &size, NULL, 0);
+ if (ret == 0) {
+ if (logical) {
+ ret = sysctlbyname("kern.smp.threads_per_core", &perCore, &size, NULL, 0);
+ /* default to physical cores if logical cannot be read */
+ if (ret == 0)
+ numCores *= perCore;
+ }
+
+ return numCores;
+ }
if (errno != ENOENT) {
- perror("zstd: can't get number of physical cpus");
+ perror("zstd: can't get number of cpus");
exit(1);
}
/* sysctl not present, fall through to older sysconf method */
}
+#else
+ /* suppress unused parameter warning */
+ (void) logical;
#endif
- numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
- if (numPhysicalCores == -1) {
+ numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ if (numCores == -1) {
/* value not queryable, fall back on 1 */
- numPhysicalCores = 1;
+ numCores = 1;
}
- return numPhysicalCores;
+ return numCores;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
/* Use POSIX sysconf
* see: man 3 sysconf */
-int UTIL_countPhysicalCores(void)
+int UTIL_countCores(int logical)
{
- static int numPhysicalCores = 0;
+ /* suppress unused parameter warning */
+ (void) logical;
- if (numPhysicalCores != 0) return numPhysicalCores;
+ static int numCores = 0;
- numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
- if (numPhysicalCores == -1) {
+ if (numCores != 0) return numCores;
+
+ numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ if (numCores == -1) {
/* value not queryable, fall back on 1 */
- return numPhysicalCores = 1;
+ return numCores = 1;
}
- return numPhysicalCores;
+ return numCores;
}
#else
-int UTIL_countPhysicalCores(void)
+int UTIL_countCores(int logical)
{
/* assume 1 */
return 1;
#endif
+int UTIL_countPhysicalCores(void)
+{
+ return UTIL_countCores(0);
+}
+
+int UTIL_countLogicalCores(void)
+{
+ return UTIL_countCores(1);
+}
+
#if defined (__cplusplus)
}
#endif
DISPLAYOUT( " -T# : spawns # compression threads (default: 1, 0==# cores) \n");
DISPLAYOUT( " -B# : select size of each job (default: 0==automatic) \n");
DISPLAYOUT( "--single-thread : use a single thread for both I/O and compression (result slightly different than -T1) \n");
+ DISPLAYOUT( "--auto-threads={physical,logical} (default: physical} : use either physical cores or logical cores as default when specifying -T0 \n");
DISPLAYOUT( "--rsyncable : compress using a rsync-friendly method (-B sets block size) \n");
# endif
DISPLAYOUT( "--exclude-compressed: only compress files that are not already compressed \n");
separateFiles = 0,
setRealTimePrio = 0,
singleThread = 0,
+#ifdef ZSTD_MULTITHREAD
+ defaultLogicalCores = 0,
+#endif
showDefaultCParams = 0,
ultra=0,
contentSize=1;
if (longCommandWArg(&argument, "--target-compressed-block-size=")) { targetCBlockSize = readSizeTFromChar(&argument); continue; }
if (longCommandWArg(&argument, "--size-hint=")) { srcSizeHint = readSizeTFromChar(&argument); continue; }
if (longCommandWArg(&argument, "--output-dir-flat")) { NEXT_FIELD(outDirName); continue; }
+#ifdef ZSTD_MULTITHREAD
+ if (longCommandWArg(&argument, "--auto-threads")) {
+ const char* threadDefault = NULL;
+ NEXT_FIELD(threadDefault);
+ if (strcmp(threadDefault, "logical") == 0)
+ defaultLogicalCores = 1;
+ continue;
+ }
+#endif
#ifdef UTIL_HAS_MIRRORFILELIST
if (longCommandWArg(&argument, "--output-dir-mirror")) { NEXT_FIELD(outMirroredDirName); continue; }
#endif
#ifdef ZSTD_MULTITHREAD
if ((nbWorkers==0) && (!singleThread)) {
/* automatically set # workers based on # of reported cpus */
- nbWorkers = UTIL_countPhysicalCores();
- DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers);
+ if (defaultLogicalCores) {
+ nbWorkers = UTIL_countLogicalCores();
+ DISPLAYLEVEL(3, "Note: %d logical core(s) detected \n", nbWorkers);
+ } else {
+ nbWorkers = UTIL_countPhysicalCores();
+ DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers);
+ }
}
#else
(void)singleThread; (void)nbWorkers;