Commit 27e0b439 by Eric Committed by Dominic Hamon

Refactor System information collection -- Add CPU Cache Info (#483)

* Refactor System information collection. This patch refactors the system information collection, and in particular information about the target CPU. The motivation is to make it easier to access CPU information, and easier to add new information as need be. This patch additionally adds information about the cache sizes of the CPU. * Address review comments: Clean up integer types. This commit cleans up the integer types used in ValueUnion to follow the Google style guide. Additionally it adds a BENCHMARK_UNREACHABLE macro to assist in documenting/catching unreachable code paths. * Rename ValueUnion accessors.
parent aad6a5fa
...@@ -1154,6 +1154,25 @@ class Fixture : public internal::Benchmark { ...@@ -1154,6 +1154,25 @@ class Fixture : public internal::Benchmark {
namespace benchmark { namespace benchmark {
struct CPUInfo {
struct CacheInfo {
std::string type;
int level;
int size;
};
int num_cpus;
double cycles_per_second;
std::vector<CacheInfo> caches;
bool scaling_enabled;
static const CPUInfo& Get();
private:
CPUInfo();
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo);
};
// Interface for custom benchmark result printers. // Interface for custom benchmark result printers.
// By default, benchmark reports are printed to stdout. However an application // By default, benchmark reports are printed to stdout. However an application
// can control the destination of the reports by calling // can control the destination of the reports by calling
...@@ -1162,12 +1181,11 @@ namespace benchmark { ...@@ -1162,12 +1181,11 @@ namespace benchmark {
class BenchmarkReporter { class BenchmarkReporter {
public: public:
struct Context { struct Context {
int num_cpus; CPUInfo const& cpu_info;
double mhz_per_cpu;
bool cpu_scaling_enabled;
// The number of chars in the longest benchmark name. // The number of chars in the longest benchmark name.
size_t name_field_width; size_t name_field_width;
Context();
}; };
struct Run { struct Run {
......
...@@ -37,13 +37,13 @@ ...@@ -37,13 +37,13 @@
#include "colorprint.h" #include "colorprint.h"
#include "commandlineflags.h" #include "commandlineflags.h"
#include "complexity.h" #include "complexity.h"
#include "statistics.h"
#include "counter.h" #include "counter.h"
#include "internal_macros.h"
#include "log.h" #include "log.h"
#include "mutex.h" #include "mutex.h"
#include "re.h" #include "re.h"
#include "statistics.h"
#include "string_util.h" #include "string_util.h"
#include "sysinfo.h"
#include "timers.h" #include "timers.h"
DEFINE_bool(benchmark_list_tests, false, DEFINE_bool(benchmark_list_tests, false,
...@@ -108,6 +108,14 @@ namespace internal { ...@@ -108,6 +108,14 @@ namespace internal {
void UseCharPointer(char const volatile*) {} void UseCharPointer(char const volatile*) {}
#ifdef BENCHMARK_HAS_NO_BUILTIN_UNREACHABLE
BENCHMARK_NORETURN void UnreachableImp(const char* FName, int Line) {
std::cerr << FName << ":" << Line << " executing unreachable code!"
<< std::endl;
std::abort();
}
#endif
class ThreadManager { class ThreadManager {
public: public:
ThreadManager(int num_threads) ThreadManager(int num_threads)
...@@ -493,10 +501,6 @@ void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks, ...@@ -493,10 +501,6 @@ void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
// Print header here // Print header here
BenchmarkReporter::Context context; BenchmarkReporter::Context context;
context.num_cpus = NumCPUs();
context.mhz_per_cpu = CyclesPerSecond() / 1000000.0;
context.cpu_scaling_enabled = CpuScalingEnabled();
context.name_field_width = name_field_width; context.name_field_width = name_field_width;
// Keep track of runing times of all instances of current benchmark // Keep track of runing times of all instances of current benchmark
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include "mutex.h" #include "mutex.h"
#include "re.h" #include "re.h"
#include "string_util.h" #include "string_util.h"
#include "sysinfo.h"
#include "timers.h" #include "timers.h"
namespace benchmark { namespace benchmark {
...@@ -448,8 +447,7 @@ Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads, ...@@ -448,8 +447,7 @@ Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
} }
Benchmark* Benchmark::ThreadPerCpu() { Benchmark* Benchmark::ThreadPerCpu() {
static int num_cpus = NumCPUs(); thread_counts_.push_back(CPUInfo::Get().num_cpus);
thread_counts_.push_back(num_cpus);
return this; return this;
} }
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
#ifndef __has_feature #ifndef __has_feature
#define __has_feature(x) 0 #define __has_feature(x) 0
#endif #endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if defined(__clang__) #if defined(__clang__)
#define COMPILER_CLANG #define COMPILER_CLANG
...@@ -56,4 +59,23 @@ ...@@ -56,4 +59,23 @@
#define BENCHMARK_HAS_NO_EXCEPTIONS #define BENCHMARK_HAS_NO_EXCEPTIONS
#endif #endif
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
#define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
#else
#define BENCHMARK_MAYBE_UNUSED
#endif
#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
#define BENCHMARK_UNREACHABLE() __builtin_unreachable()
#else
#define BENCHMARK_HAS_NO_BUILTIN_UNREACHABLE
namespace benchmark {
namespace internal {
BENCHMARK_NORETURN void UnreachableImp(const char* FName, int Line);
}
} // namespace benchmark
#define BENCHMARK_UNREACHABLE() \
::benchmark::internal::UnreachableImp(__FILE__, __LINE__)
#endif
#endif // BENCHMARK_INTERNAL_MACROS_H_ #endif // BENCHMARK_INTERNAL_MACROS_H_
...@@ -77,11 +77,14 @@ bool JSONReporter::ReportContext(const Context& context) { ...@@ -77,11 +77,14 @@ bool JSONReporter::ReportContext(const Context& context) {
std::string walltime_value = LocalDateTimeString(); std::string walltime_value = LocalDateTimeString();
out << indent << FormatKV("date", walltime_value) << ",\n"; out << indent << FormatKV("date", walltime_value) << ",\n";
out << indent << FormatKV("num_cpus", static_cast<int64_t>(context.num_cpus)) CPUInfo const& info = context.cpu_info;
out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
<< ",\n"; << ",\n";
out << indent << FormatKV("mhz_per_cpu", RoundDouble(context.mhz_per_cpu)) out << indent
<< FormatKV("mhz_per_cpu",
RoundDouble(info.cycles_per_second / 1000000.0))
<< ",\n"; << ",\n";
out << indent << FormatKV("cpu_scaling_enabled", context.cpu_scaling_enabled) out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled)
<< ",\n"; << ",\n";
#if defined(NDEBUG) #if defined(NDEBUG)
......
...@@ -35,12 +35,21 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, ...@@ -35,12 +35,21 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out,
CHECK(out) << "cannot be null"; CHECK(out) << "cannot be null";
auto &Out = *out; auto &Out = *out;
Out << "Run on (" << context.num_cpus << " X " << context.mhz_per_cpu
<< " MHz CPU " << ((context.num_cpus > 1) ? "s" : "") << ")\n";
Out << LocalDateTimeString() << "\n"; Out << LocalDateTimeString() << "\n";
if (context.cpu_scaling_enabled) { 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";
if (info.caches.size() != 0) {
Out << "CPU Caches:\n";
for (auto &CInfo : info.caches) {
Out << " L" << CInfo.level << " " << CInfo.type << " "
<< (CInfo.size / 1000) << "K\n";
}
}
if (info.scaling_enabled) {
Out << "***WARNING*** CPU scaling is enabled, the benchmark " Out << "***WARNING*** CPU scaling is enabled, the benchmark "
"real time measurements may be noisy and will incur extra " "real time measurements may be noisy and will incur extra "
"overhead.\n"; "overhead.\n";
...@@ -52,6 +61,8 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, ...@@ -52,6 +61,8 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out,
#endif #endif
} }
BenchmarkReporter::Context::Context() : cpu_info(CPUInfo::Get()) {}
double BenchmarkReporter::Run::GetAdjustedRealTime() const { double BenchmarkReporter::Run::GetAdjustedRealTime() const {
double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit); double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit);
if (iterations != 0) new_time /= static_cast<double>(iterations); if (iterations != 0) new_time /= static_cast<double>(iterations);
......
#ifndef BENCHMARK_SYSINFO_H_
#define BENCHMARK_SYSINFO_H_
namespace benchmark {
int NumCPUs();
double CyclesPerSecond();
bool CpuScalingEnabled();
} // end namespace benchmark
#endif // BENCHMARK_SYSINFO_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment