Include system load average in console and JSON reports

High system load can skew benchmark results. By including system load averages
in the library's output, we help users identify a potential issue in the
quality of their measurements, and thus assist them in producing better (more
reproducible) results.

I got the idea for this from Brendan Gregg's checklist for benchmark accuracy
(http://www.brendangregg.com/blog/2018-06-30/benchmarking-checklist.html).
This commit is contained in:
Ori Livneh 2018-07-09 00:17:44 -04:00
parent 1f35fa4aa7
commit da9ec3dfca
5 changed files with 44 additions and 3 deletions

View File

@ -1242,6 +1242,7 @@ struct CPUInfo {
double cycles_per_second;
std::vector<CacheInfo> caches;
bool scaling_enabled;
std::vector<double> load_avg;
static const CPUInfo& Get();

View File

@ -111,6 +111,12 @@ bool JSONReporter::ReportContext(const Context& context) {
}
indent = std::string(4, ' ');
out << indent << "],\n";
out << indent << "\"load_avg\": [";
for (auto it = info.load_avg.begin(); it != info.load_avg.end();) {
out << *it++;
if (it != info.load_avg.end()) out << ",";
}
out << "],\n";
#if defined(NDEBUG)
const char build_type[] = "release";

View File

@ -22,6 +22,7 @@
#include <vector>
#include "check.h"
#include "string_util.h"
namespace benchmark {
@ -54,6 +55,14 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out,
Out << "\n";
}
}
if (!info.load_avg.empty()) {
Out << "Load Average: ";
for (auto It = info.load_avg.begin(); It != info.load_avg.end();) {
Out << StrFormat("%.2f", *It++);
if (It != info.load_avg.end()) Out << ", ";
}
Out << "\n";
}
if (info.scaling_enabled) {
Out << "***WARNING*** CPU scaling is enabled, the benchmark "

View File

@ -571,6 +571,24 @@ double GetCPUCyclesPerSecond() {
return static_cast<double>(cycleclock::Now() - start_ticks);
}
std::vector<double> GetLoadAvg() {
#if defined BENCHMARK_OS_FREEBSD || defined(BENCHMARK_OS_LINUX) || \
defined BENCHMARK_OS_MACOSX || defined BENCHMARK_OS_NETBSD || \
defined BENCHMARK_OS_OPENBSD
constexpr int kMaxSamples = 3;
std::vector<double> res(kMaxSamples, 0.0);
const int nelem = getloadavg(res.data(), kMaxSamples);
if (nelem < 1) {
res.clear();
} else {
res.resize(nelem);
}
return res;
#else
return {};
#endif
}
} // end namespace
const CPUInfo& CPUInfo::Get() {
@ -582,6 +600,7 @@ CPUInfo::CPUInfo()
: num_cpus(GetNumCPUs()),
cycles_per_second(GetCPUCyclesPerSecond()),
caches(GetCacheSizes()),
scaling_enabled(CpuScalingEnabled(num_cpus)) {}
scaling_enabled(CpuScalingEnabled(num_cpus)),
load_avg(GetLoadAvg()) {}
} // end namespace benchmark

View File

@ -28,7 +28,8 @@ static int AddContextCases() {
{"\"mhz_per_cpu\": %float,$", MR_Next},
{"\"cpu_scaling_enabled\": ", MR_Next},
{"\"caches\": \\[$", MR_Next}});
auto const& Caches = benchmark::CPUInfo::Get().caches;
auto const& Info = benchmark::CPUInfo::Get();
auto const& Caches = Info.caches;
if (!Caches.empty()) {
AddCases(TC_ConsoleErr, {{"CPU Caches:$", MR_Next}});
}
@ -45,8 +46,13 @@ static int AddContextCases() {
{"\"num_sharing\": %int$", MR_Next},
{"}[,]{0,1}$", MR_Next}});
}
AddCases(TC_JSONOut, {{"],$"}});
auto const& LoadAvg = Info.load_avg;
if (!LoadAvg.empty()) {
AddCases(TC_ConsoleErr,
{{"Load Average: (%float, ){0,2}%float$", MR_Next}});
}
AddCases(TC_JSONOut, {{"\"load_avg\": \\[(%float,?){0,3}],$", MR_Next}});
return 0;
}
int dummy_register = AddContextCases();