mirror of https://github.com/google/benchmark.git
Introduce additional memory metrics (#1238)
- added total_allocs and net_allocs - updated reporter code to report these, if available.
This commit is contained in:
parent
f730846b0a
commit
7fad964a94
|
@ -180,6 +180,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
|
|||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
@ -273,7 +274,6 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
|
|||
|
||||
namespace benchmark {
|
||||
class BenchmarkReporter;
|
||||
class MemoryManager;
|
||||
|
||||
void Initialize(int* argc, char** argv);
|
||||
void Shutdown();
|
||||
|
@ -299,6 +299,49 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter);
|
|||
size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter,
|
||||
BenchmarkReporter* file_reporter);
|
||||
|
||||
// If a MemoryManager is registered (via RegisterMemoryManager()),
|
||||
// it can be used to collect and report allocation metrics for a run of the
|
||||
// benchmark.
|
||||
class MemoryManager {
|
||||
public:
|
||||
static const int64_t TombstoneValue;
|
||||
|
||||
struct Result {
|
||||
Result()
|
||||
: num_allocs(0),
|
||||
max_bytes_used(0),
|
||||
total_allocated_bytes(TombstoneValue),
|
||||
net_heap_growth(TombstoneValue) {}
|
||||
|
||||
// The number of allocations made in total between Start and Stop.
|
||||
int64_t num_allocs;
|
||||
|
||||
// The peak memory use between Start and Stop.
|
||||
int64_t max_bytes_used;
|
||||
|
||||
// The total memory allocated, in bytes, between Start and Stop.
|
||||
// Init'ed to TombstoneValue if metric not available.
|
||||
int64_t total_allocated_bytes;
|
||||
|
||||
// The net changes in memory, in bytes, between Start and Stop.
|
||||
// ie., total_allocated_bytes - total_deallocated_bytes.
|
||||
// Init'ed to TombstoneValue if metric not available.
|
||||
int64_t net_heap_growth;
|
||||
};
|
||||
|
||||
virtual ~MemoryManager() {}
|
||||
|
||||
// Implement this to start recording allocation information.
|
||||
virtual void Start() = 0;
|
||||
|
||||
// Implement this to stop recording and fill out the given Result structure.
|
||||
BENCHMARK_DEPRECATED_MSG("Use Stop(Result&) instead")
|
||||
virtual void Stop(Result* result) = 0;
|
||||
|
||||
// FIXME(vyng): Make this pure virtual once we've migrated current users.
|
||||
virtual void Stop(Result& result) { Stop(&result); }
|
||||
};
|
||||
|
||||
// Register a MemoryManager instance that will be used to collect and report
|
||||
// allocation measurements for benchmark runs.
|
||||
void RegisterMemoryManager(MemoryManager* memory_manager);
|
||||
|
@ -1440,9 +1483,8 @@ class BenchmarkReporter {
|
|||
report_big_o(false),
|
||||
report_rms(false),
|
||||
counters(),
|
||||
has_memory_result(false),
|
||||
allocs_per_iter(0.0),
|
||||
max_bytes_used(0) {}
|
||||
memory_result(NULL),
|
||||
allocs_per_iter(0.0) {}
|
||||
|
||||
std::string benchmark_name() const;
|
||||
BenchmarkName run_name;
|
||||
|
@ -1493,9 +1535,8 @@ class BenchmarkReporter {
|
|||
UserCounters counters;
|
||||
|
||||
// Memory metrics.
|
||||
bool has_memory_result;
|
||||
const MemoryManager::Result* memory_result;
|
||||
double allocs_per_iter;
|
||||
int64_t max_bytes_used;
|
||||
};
|
||||
|
||||
struct PerFamilyRunReports {
|
||||
|
@ -1624,28 +1665,6 @@ class BENCHMARK_DEPRECATED_MSG(
|
|||
std::set<std::string> user_counter_names_;
|
||||
};
|
||||
|
||||
// If a MemoryManager is registered, it can be used to collect and report
|
||||
// allocation metrics for a run of the benchmark.
|
||||
class MemoryManager {
|
||||
public:
|
||||
struct Result {
|
||||
Result() : num_allocs(0), max_bytes_used(0) {}
|
||||
|
||||
// The number of allocations made in total between Start and Stop.
|
||||
int64_t num_allocs;
|
||||
|
||||
// The peak memory use between Start and Stop.
|
||||
int64_t max_bytes_used;
|
||||
};
|
||||
|
||||
virtual ~MemoryManager() {}
|
||||
|
||||
// Implement this to start recording allocation information.
|
||||
virtual void Start() = 0;
|
||||
|
||||
// Implement this to stop recording and fill out the given Result structure.
|
||||
virtual void Stop(Result* result) = 0;
|
||||
};
|
||||
|
||||
inline const char* GetTimeUnitString(TimeUnit unit) {
|
||||
switch (unit) {
|
||||
|
|
|
@ -67,7 +67,7 @@ BenchmarkReporter::Run CreateRunReport(
|
|||
const benchmark::internal::BenchmarkInstance& b,
|
||||
const internal::ThreadManager::Result& results,
|
||||
IterationCount memory_iterations,
|
||||
const MemoryManager::Result& memory_result, double seconds,
|
||||
const MemoryManager::Result* memory_result, double seconds,
|
||||
int64_t repetition_index, int64_t repeats) {
|
||||
// Create report about this benchmark run.
|
||||
BenchmarkReporter::Run report;
|
||||
|
@ -99,12 +99,12 @@ BenchmarkReporter::Run CreateRunReport(
|
|||
report.counters = results.counters;
|
||||
|
||||
if (memory_iterations > 0) {
|
||||
report.has_memory_result = true;
|
||||
assert(memory_result != nullptr);
|
||||
report.memory_result = memory_result;
|
||||
report.allocs_per_iter =
|
||||
memory_iterations ? static_cast<double>(memory_result.num_allocs) /
|
||||
memory_iterations ? static_cast<double>(memory_result->num_allocs) /
|
||||
memory_iterations
|
||||
: 0;
|
||||
report.max_bytes_used = memory_result.max_bytes_used;
|
||||
}
|
||||
|
||||
internal::Finish(&report.counters, results.iterations, seconds,
|
||||
|
@ -302,9 +302,14 @@ void BenchmarkRunner::DoOneRepetition() {
|
|||
}
|
||||
|
||||
// Oh, one last thing, we need to also produce the 'memory measurements'..
|
||||
MemoryManager::Result memory_result;
|
||||
MemoryManager::Result* memory_result = nullptr;
|
||||
IterationCount memory_iterations = 0;
|
||||
if (memory_manager != nullptr) {
|
||||
// TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an
|
||||
// optional so we don't have to own the Result here.
|
||||
// Can't do it now due to cxx03.
|
||||
memory_results.push_back(MemoryManager::Result());
|
||||
memory_result = &memory_results.back();
|
||||
// Only run a few iterations to reduce the impact of one-time
|
||||
// allocations in benchmarks that are not properly managed.
|
||||
memory_iterations = std::min<IterationCount>(16, iters);
|
||||
|
@ -316,7 +321,7 @@ void BenchmarkRunner::DoOneRepetition() {
|
|||
manager->WaitForAllThreads();
|
||||
manager.reset();
|
||||
|
||||
memory_manager->Stop(&memory_result);
|
||||
memory_manager->Stop(memory_result);
|
||||
}
|
||||
|
||||
// Ok, now actually report.
|
||||
|
|
|
@ -76,6 +76,8 @@ class BenchmarkRunner {
|
|||
|
||||
std::vector<std::thread> pool;
|
||||
|
||||
std::vector<MemoryManager::Result> memory_results;
|
||||
|
||||
IterationCount iters; // preserved between repetitions!
|
||||
// So only the first repetition has to find/calculate it,
|
||||
// the other repetitions will just use that precomputed iteration count.
|
||||
|
|
|
@ -295,9 +295,20 @@ void JSONReporter::PrintRunData(Run const& run) {
|
|||
out << ",\n" << indent << FormatKV(c.first, c.second);
|
||||
}
|
||||
|
||||
if (run.has_memory_result) {
|
||||
if (run.memory_result) {
|
||||
const MemoryManager::Result memory_result = *run.memory_result;
|
||||
out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter);
|
||||
out << ",\n" << indent << FormatKV("max_bytes_used", run.max_bytes_used);
|
||||
out << ",\n"
|
||||
<< indent << FormatKV("max_bytes_used", memory_result.max_bytes_used);
|
||||
|
||||
auto report_if_present = [&out, &indent](const char* label, int64_t val) {
|
||||
if (val != MemoryManager::TombstoneValue)
|
||||
out << ",\n" << indent << FormatKV(label, val);
|
||||
};
|
||||
|
||||
report_if_present("total_allocated_bytes",
|
||||
memory_result.total_allocated_bytes);
|
||||
report_if_present("net_heap_growth", memory_result.net_heap_growth);
|
||||
}
|
||||
|
||||
if (!run.report_label.empty()) {
|
||||
|
@ -306,4 +317,6 @@ void JSONReporter::PrintRunData(Run const& run) {
|
|||
out << '\n';
|
||||
}
|
||||
|
||||
const int64_t MemoryManager::TombstoneValue = std::numeric_limits<int64_t>::max();
|
||||
|
||||
} // end namespace benchmark
|
||||
|
|
Loading…
Reference in New Issue