Introduce use of std::chrono and remove Walltime printing

This commit is contained in:
Eric Fiselier 2015-03-26 14:26:07 -04:00
parent 8b0b73f06c
commit a3308c6d86
8 changed files with 98 additions and 82 deletions

View File

@ -69,17 +69,6 @@ DEFINE_bool(color_print, true, "Enables colorized logging.");
DEFINE_int32(v, 0, "The level of verbose logging to output");
// The ""'s catch people who don't pass in a literal for "str"
#define strliterallen(str) (sizeof("" str "") - 1)
// Must use a string literal for prefix.
#define memprefix(str, len, prefix) \
((((len) >= strliterallen(prefix)) && \
std::memcmp(str, prefix, strliterallen(prefix)) == 0) \
? str + strliterallen(prefix) \
: nullptr)
namespace benchmark {
namespace internal {
@ -120,23 +109,6 @@ bool use_real_time GUARDED_BY(GetBenchmarkLock());
// TODO(ericwf): support MallocCounter.
//static benchmark::MallocCounter *benchmark_mc;
static bool CpuScalingEnabled() {
// On Linux, the CPUfreq subsystem exposes CPU information as files on the
// local file system. If reading the exported files fails, then we may not be
// running on Linux, so we silently ignore all the read errors.
for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) {
std::string governor_file = StrCat("/sys/devices/system/cpu/cpu", cpu,
"/cpufreq/scaling_governor");
FILE* file = fopen(governor_file.c_str(), "r");
if (!file) break;
char buff[16];
size_t bytes_read = fread(buff, 1, sizeof(buff), file);
fclose(file);
if (memprefix(buff, bytes_read, "performance") == nullptr) return true;
}
return false;
}
struct ThreadStats {
ThreadStats() : bytes_processed(0), items_processed(0) {}
int64_t bytes_processed;

View File

@ -65,11 +65,8 @@ bool JSONReporter::ReportContext(const Context& context) {
// Open context block and print context information.
out << inner_indent << "\"context\": {\n";
std::string indent(4, ' ');
int remainder_us;
std::string walltime_value = walltime::Print(
walltime::Now(), "%Y/%m/%d-%H:%M:%S",
true, // use local timezone
&remainder_us);
std::string walltime_value = LocalDateTimeString();
out << indent << FormatKV("date", walltime_value) << ",\n";
out << indent

View File

@ -98,11 +98,7 @@ bool ConsoleReporter::ReportContext(const Context& context) {
context.mhz_per_cpu,
(context.num_cpus > 1) ? "s" : "");
int remainder_us;
std::string walltime_str = walltime::Print(
walltime::Now(), "%Y/%m/%d-%H:%M:%S",
true, // use local timezone
&remainder_us);
std::string walltime_str = LocalDateTimeString();
fprintf(stdout, "%s\n", walltime_str.c_str());
if (context.cpu_scaling_enabled) {

View File

@ -36,6 +36,7 @@
#include "internal_macros.h"
#include "log.h"
#include "sleep.h"
#include "string_util.h"
namespace benchmark {
namespace {
@ -352,4 +353,32 @@ int NumCPUs(void) {
std::call_once(cpuinfo_init, InitializeSystemInfo);
return cpuinfo_num_cpus;
}
// The ""'s catch people who don't pass in a literal for "str"
#define strliterallen(str) (sizeof("" str "") - 1)
// Must use a string literal for prefix.
#define memprefix(str, len, prefix) \
((((len) >= strliterallen(prefix)) && \
std::memcmp(str, prefix, strliterallen(prefix)) == 0) \
? str + strliterallen(prefix) \
: nullptr)
bool CpuScalingEnabled() {
// On Linux, the CPUfreq subsystem exposes CPU information as files on the
// local file system. If reading the exported files fails, then we may not be
// running on Linux, so we silently ignore all the read errors.
for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) {
std::string governor_file = StrCat("/sys/devices/system/cpu/cpu", cpu,
"/cpufreq/scaling_governor");
FILE* file = fopen(governor_file.c_str(), "r");
if (!file) break;
char buff[16];
size_t bytes_read = fread(buff, 1, sizeof(buff), file);
fclose(file);
if (memprefix(buff, bytes_read, "performance") == nullptr) return true;
}
return false;
}
} // end namespace benchmark

View File

@ -6,6 +6,7 @@ double MyCPUUsage();
double ChildrenCPUUsage();
int NumCPUs();
double CyclesPerSecond();
bool CpuScalingEnabled();
} // end namespace benchmark
#endif // BENCHMARK_SYSINFO_H_

View File

@ -15,6 +15,7 @@
#include "walltime.h"
#include <sys/time.h>
#include <iostream>
#include <cstdio>
#include <cstdint>
@ -22,35 +23,17 @@
#include <ctime>
#include <atomic>
#include <chrono>
#include <limits>
#include <type_traits>
#include "arraysize.h"
#include "check.h"
#include "cycleclock.h"
#include "sysinfo.h"
namespace benchmark {
namespace walltime {
namespace {
bool SplitTimezone(WallTime value, bool local, struct tm* t,
double* subsecond) {
memset(t, 0, sizeof(*t));
if ((value < 0) || (value > std::numeric_limits<time_t>::max())) {
*subsecond = 0.0;
return false;
}
const time_t whole_time = static_cast<time_t>(value);
*subsecond = value - whole_time;
if (local)
localtime_r(&whole_time, t);
else
gmtime_r(&whole_time, t);
return true;
}
} // end anonymous namespace
namespace {
@ -163,29 +146,47 @@ WallTimeImp::WallTimeImp()
} // end anonymous namespace
// WallTimeImp doesn't work when CPU Scaling is enabled. If CPU Scaling is
// enabled at the start of the program then std::chrono::system_clock is used
// instead.
WallTime Now()
{
static bool useWallTime = !CpuScalingEnabled();
if (useWallTime) {
static WallTimeImp& imp = WallTimeImp::GetWallTimeImp();
return imp.Now();
}
std::string Print(WallTime time, const char* format, bool local,
int* remainder_us) {
char storage[32];
struct tm split;
double subsecond;
if (!SplitTimezone(time, local, &split, &subsecond)) {
snprintf(storage, sizeof(storage), "Invalid time: %f", time);
} else {
if (remainder_us != nullptr) {
*remainder_us = static_cast<int>((subsecond * 1000000) + 0.5);
if (*remainder_us > 999999) *remainder_us = 999999;
if (*remainder_us < 0) *remainder_us = 0;
}
strftime(storage, sizeof(storage), format, &split);
typedef std::chrono::system_clock Clock;
typedef std::chrono::duration<WallTime, std::chrono::seconds::period>
FPSeconds;
static_assert(std::chrono::treat_as_floating_point<WallTime>::value,
"This type must be treated as a floating point type.");
auto now = Clock::now().time_since_epoch();
return std::chrono::duration_cast<FPSeconds>(now).count();
}
return std::string(storage);
}
} // end namespace walltime
std::string DateTimeString(bool local) {
typedef std::chrono::system_clock Clock;
std::time_t now = Clock::to_time_t(Clock::now());
char storage[128];
std::tm timeinfo;
if (local) {
std::tm* ret = std::localtime(&now);
CHECK(ret != nullptr);
timeinfo = *ret;
} else {
std::tm* ret = std::gmtime(&now);
CHECK(ret != nullptr);
timeinfo = *ret;
}
std::size_t written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
CHECK(written < arraysize(storage));
return std::string(storage);
}
} // end namespace benchmark

View File

@ -8,15 +8,14 @@ typedef double WallTime;
namespace walltime {
WallTime Now();
// GIVEN: walltime, generic format string (as understood by strftime),
// a boolean flag specifying if the time is local or UTC (true=local).
// RETURNS: the formatted string. ALSO RETURNS: the remaining number of
// microseconds (never printed in the string since strftime does not understand
// it)
std::string Print(WallTime time, const char *format, bool local,
int *remainder_us);
} // end namespace walltime
std::string DateTimeString(bool local = false);
inline std::string LocalDateTimeString() {
return DateTimeString(true);
}
} // end namespace benchmark
#endif // BENCHMARK_WALLTIME_H_

View File

@ -59,6 +59,27 @@ void BM_spin_pause_during(benchmark::State& state) {
BASIC_BENCHMARK_TEST(BM_spin_pause_during);
BASIC_BENCHMARK_TEST(BM_spin_pause_during)->ThreadPerCpu();
void BM_pause_during(benchmark::State& state) {
while(state.KeepRunning()) {
state.PauseTiming();
state.ResumeTiming();
}
}
BASIC_BENCHMARK_TEST(BM_pause_during);
BASIC_BENCHMARK_TEST(BM_pause_during)->ThreadPerCpu();
void BM_pause_during_realtime(benchmark::State& state) {
state.UseRealTime();
while(state.KeepRunning()) {
state.PauseTiming();
state.ResumeTiming();
}
}
BASIC_BENCHMARK_TEST(BM_pause_during_realtime);
BASIC_BENCHMARK_TEST(BM_pause_during_realtime)->ThreadPerCpu();
void BM_spin_pause_after(benchmark::State& state) {
while(state.KeepRunning()) {