diff --git a/AUTHORS b/AUTHORS index 4a14b98707..a414be01ee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -79,6 +79,7 @@ Stanley C. Steinar H. Gunderson Stripe, Inc. Tobias Schmidt +Vincenzo Reina XiaoWei Lu Yixuan Qiu Yusuke Suzuki diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 74e5fe958f..ea6c3a2bb4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -106,6 +106,7 @@ Stanley C. Tobias Schmidt Tobias Ulvgård Tom Madams +Vincenzo Reina XiaoWei Lu Yixuan Qiu Yusuke Suzuki diff --git a/include/benchmark/sysinfo.h b/include/benchmark/sysinfo.h index 711e64d7fb..08ca4fbbba 100644 --- a/include/benchmark/sysinfo.h +++ b/include/benchmark/sysinfo.h @@ -38,6 +38,7 @@ struct BENCHMARK_EXPORT CPUInfo { enum Scaling { UNKNOWN, ENABLED, DISABLED }; int num_cpus; + int num_cpus_in_affinity_mask; Scaling scaling; double cycles_per_second; std::vector caches; diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 37da17ba03..740a0992e2 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -139,6 +139,12 @@ bool JSONReporter::ReportContext(const Context& context) { CPUInfo const& info = context.cpu_info; out << indent << FormatKV("num_cpus", static_cast(info.num_cpus)) << ",\n"; + if (info.num_cpus_in_affinity_mask > 0) { + out << indent + << FormatKV("num_cpus_in_affinity_mask", + static_cast(info.num_cpus_in_affinity_mask)) + << ",\n"; + } out << indent << FormatKV("mhz_per_cpu", RoundDouble(info.cycles_per_second / 1000000.0)) diff --git a/src/reporter.cc b/src/reporter.cc index 298ff1a60e..91649d9dfa 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -54,7 +54,13 @@ void BenchmarkReporter::PrintBasicContext(std::ostream* out, const CPUInfo& info = context.cpu_info; Out << "Run on (" << info.num_cpus << " X " << (info.cycles_per_second / 1000000.0) << " MHz CPU " - << ((info.num_cpus > 1) ? "s" : "") << ")\n"; + << ((info.num_cpus > 1) ? "s" : ""); + // Only mention the affinity mask when it actually restricts the process. + if (info.num_cpus_in_affinity_mask > 0 && + info.num_cpus_in_affinity_mask < info.num_cpus) { + Out << ", " << info.num_cpus_in_affinity_mask << " in affinity mask"; + } + Out << ")\n"; if (!info.caches.empty()) { Out << "CPU Caches:\n"; for (const auto& CInfo : info.caches) { diff --git a/src/sysinfo.cc b/src/sysinfo.cc index a291e10e2b..a1485717af 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -574,6 +574,34 @@ int GetNumCPUs() { return num_cpus; } +int GetNumCPUsInAffinityMask() { +#if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) + cpu_set_t affinity; + if (pthread_getaffinity_np(pthread_self(), sizeof(affinity), &affinity) != + 0) { + return 0; + } + int num_cpus = 0; + for (int i = 0; i < CPU_SETSIZE; ++i) { + if (CPU_ISSET(i, &affinity)) { + ++num_cpus; + } + } + return num_cpus; +#elif defined(BENCHMARK_OS_WINDOWS_WIN32) + DWORD_PTR process_mask = 0; + DWORD_PTR system_mask = 0; + if (GetProcessAffinityMask(GetCurrentProcess(), &process_mask, + &system_mask) == 0) { + return 0; + } + return static_cast( + std::bitset(process_mask).count()); +#else + return 0; +#endif +} + class ThreadAffinityGuard final { public: ThreadAffinityGuard() : reset_affinity(SetAffinity()) { @@ -896,6 +924,7 @@ const CPUInfo& CPUInfo::Get() { CPUInfo::CPUInfo() : num_cpus(GetNumCPUs()), + num_cpus_in_affinity_mask(GetNumCPUsInAffinityMask()), scaling(CpuScaling(num_cpus)), cycles_per_second(GetCPUCyclesPerSecond(scaling)), caches(GetCacheSizes()), diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 2ad2e371bd..1f49f5211e 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -22,7 +22,9 @@ int AddContextCases() { { {"^%int-%int-%intT%int:%int:%int[-+]%int:%int$", MR_Default}, {"Running .*(/|\\\\)reporter_output_test(\\.exe)?$", MR_Next}, - {"Run on \\(%int X %float MHz CPU s?\\)", MR_Next}, + {"Run on \\(%int X %float MHz CPU s?" + "(, %int in affinity mask)?\\)", + MR_Next}, }); AddCases(TC_JSONOut, {{"^\\{", MR_Default}, @@ -31,10 +33,14 @@ int AddContextCases() { {"\"host_name\":", MR_Next}, {"\"executable\": \".*(/|\\\\)reporter_output_test(\\.exe)?\",", MR_Next}, - {"\"num_cpus\": %int,$", MR_Next}, - {"\"mhz_per_cpu\": %float,$", MR_Next}, - {"\"caches\": \\[$", MR_Default}}); + {"\"num_cpus\": %int,$", MR_Next}}); auto const& Info = benchmark::CPUInfo::Get(); + // The affinity field is only emitted when it could be determined. + if (Info.num_cpus_in_affinity_mask > 0) { + AddCases(TC_JSONOut, {{"\"num_cpus_in_affinity_mask\": %int,$", MR_Next}}); + } + AddCases(TC_JSONOut, {{"\"mhz_per_cpu\": %float,$", MR_Next}, + {"\"caches\": \\[$", MR_Default}}); auto const& Caches = Info.caches; if (!Caches.empty()) { AddCases(TC_ConsoleErr, {{"CPU Caches:$", MR_Next}});