Skip to content

Commit 5a4c459

Browse files
authored
fix memory manager result bug (#1941)
* fix memory manager result bug * change is_valid to memory_iterations * fix test * some fixes * fix test ...for msvc * fix test * fix test add the correct explicitly casts * fix msvc failure * some fixes * remove unnecessary include
1 parent 571c235 commit 5a4c459

File tree

6 files changed

+120
-25
lines changed

6 files changed

+120
-25
lines changed

include/benchmark/benchmark.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ namespace benchmark {
306306
class BenchmarkReporter;
307307
class State;
308308

309+
using IterationCount = int64_t;
310+
309311
// Define alias of Setup/Teardown callback function type
310312
using callback_function = std::function<void(const benchmark::State&)>;
311313

@@ -387,14 +389,15 @@ BENCHMARK_EXPORT void SetDefaultTimeUnit(TimeUnit unit);
387389
// benchmark.
388390
class MemoryManager {
389391
public:
390-
static const int64_t TombstoneValue;
392+
static constexpr int64_t TombstoneValue = std::numeric_limits<int64_t>::max();
391393

392394
struct Result {
393395
Result()
394396
: num_allocs(0),
395397
max_bytes_used(0),
396398
total_allocated_bytes(TombstoneValue),
397-
net_heap_growth(TombstoneValue) {}
399+
net_heap_growth(TombstoneValue),
400+
memory_iterations(0) {}
398401

399402
// The number of allocations made in total between Start and Stop.
400403
int64_t num_allocs;
@@ -410,6 +413,8 @@ class MemoryManager {
410413
// ie., total_allocated_bytes - total_deallocated_bytes.
411414
// Init'ed to TombstoneValue if metric not available.
412415
int64_t net_heap_growth;
416+
417+
IterationCount memory_iterations;
413418
};
414419

415420
virtual ~MemoryManager() {}
@@ -659,8 +664,6 @@ enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda };
659664

660665
typedef int64_t ComplexityN;
661666

662-
typedef int64_t IterationCount;
663-
664667
enum StatisticUnit { kTime, kPercentage };
665668

666669
// BigOFunc is passed to a benchmark in order to specify the asymptotic
@@ -1721,7 +1724,6 @@ class BENCHMARK_EXPORT BenchmarkReporter {
17211724
complexity_n(0),
17221725
report_big_o(false),
17231726
report_rms(false),
1724-
memory_result(NULL),
17251727
allocs_per_iter(0.0) {}
17261728

17271729
std::string benchmark_name() const;
@@ -1777,7 +1779,7 @@ class BENCHMARK_EXPORT BenchmarkReporter {
17771779
UserCounters counters;
17781780

17791781
// Memory metrics.
1780-
const MemoryManager::Result* memory_result;
1782+
MemoryManager::Result memory_result;
17811783
double allocs_per_iter;
17821784
};
17831785

src/benchmark_runner.cc

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ BenchmarkReporter::Run CreateRunReport(
8181
const benchmark::internal::BenchmarkInstance& b,
8282
const internal::ThreadManager::Result& results,
8383
IterationCount memory_iterations,
84-
const MemoryManager::Result* memory_result, double seconds,
84+
const MemoryManager::Result& memory_result, double seconds,
8585
int64_t repetition_index, int64_t repeats) {
8686
// Create report about this benchmark run.
8787
BenchmarkReporter::Run report;
@@ -114,11 +114,10 @@ BenchmarkReporter::Run CreateRunReport(
114114
report.counters = results.counters;
115115

116116
if (memory_iterations > 0) {
117-
assert(memory_result != nullptr);
118117
report.memory_result = memory_result;
119118
report.allocs_per_iter =
120119
memory_iterations != 0
121-
? static_cast<double>(memory_result->num_allocs) /
120+
? static_cast<double>(memory_result.num_allocs) /
122121
static_cast<double>(memory_iterations)
123122
: 0;
124123
}
@@ -426,13 +425,8 @@ void BenchmarkRunner::RunWarmUp() {
426425
}
427426
}
428427

429-
MemoryManager::Result* BenchmarkRunner::RunMemoryManager(
428+
MemoryManager::Result BenchmarkRunner::RunMemoryManager(
430429
IterationCount memory_iterations) {
431-
// TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an
432-
// optional so we don't have to own the Result here.
433-
// Can't do it now due to cxx03.
434-
memory_results.push_back(MemoryManager::Result());
435-
MemoryManager::Result* memory_result = &memory_results.back();
436430
memory_manager->Start();
437431
std::unique_ptr<internal::ThreadManager> manager;
438432
manager.reset(new internal::ThreadManager(1));
@@ -443,7 +437,9 @@ MemoryManager::Result* BenchmarkRunner::RunMemoryManager(
443437
manager->WaitForAllThreads();
444438
manager.reset();
445439
b.Teardown();
446-
memory_manager->Stop(*memory_result);
440+
MemoryManager::Result memory_result;
441+
memory_manager->Stop(memory_result);
442+
memory_result.memory_iterations = memory_iterations;
447443
return memory_result;
448444
}
449445

@@ -508,7 +504,7 @@ void BenchmarkRunner::DoOneRepetition() {
508504
}
509505

510506
// Produce memory measurements if requested.
511-
MemoryManager::Result* memory_result = nullptr;
507+
MemoryManager::Result memory_result;
512508
IterationCount memory_iterations = 0;
513509
if (memory_manager != nullptr) {
514510
// Only run a few iterations to reduce the impact of one-time

src/benchmark_runner.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ class BenchmarkRunner {
9191

9292
std::vector<std::thread> pool;
9393

94-
std::vector<MemoryManager::Result> memory_results;
95-
9694
IterationCount iters; // preserved between repetitions!
9795
// So only the first repetition has to find/calculate it,
9896
// the other repetitions will just use that precomputed iteration count.
@@ -106,7 +104,7 @@ class BenchmarkRunner {
106104
};
107105
IterationResults DoNIterations();
108106

109-
MemoryManager::Result* RunMemoryManager(IterationCount memory_iterations);
107+
MemoryManager::Result RunMemoryManager(IterationCount memory_iterations);
110108

111109
void RunProfilerManager(IterationCount profile_iterations);
112110

src/json_reporter.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,8 @@ void JSONReporter::PrintRunData(Run const& run) {
306306
out << ",\n" << indent << FormatKV(c.first, c.second);
307307
}
308308

309-
if (run.memory_result != nullptr) {
310-
const MemoryManager::Result memory_result = *run.memory_result;
309+
if (run.memory_result.memory_iterations > 0) {
310+
const auto& memory_result = run.memory_result;
311311
out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter);
312312
out << ",\n"
313313
<< indent << FormatKV("max_bytes_used", memory_result.max_bytes_used);
@@ -330,7 +330,4 @@ void JSONReporter::PrintRunData(Run const& run) {
330330
out << '\n';
331331
}
332332

333-
const int64_t MemoryManager::TombstoneValue =
334-
std::numeric_limits<int64_t>::max();
335-
336333
} // end namespace benchmark

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS)
233233
add_gtest(min_time_parse_gtest)
234234
add_gtest(profiler_manager_gtest)
235235
add_gtest(benchmark_setup_teardown_cb_types_gtest)
236+
add_gtest(memory_results_gtest)
236237
endif(BENCHMARK_ENABLE_GTEST_TESTS)
237238

238239
###############################################################################

test/memory_results_gtest.cc

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include <vector>
2+
3+
#include "benchmark/benchmark.h"
4+
#include "gtest/gtest.h"
5+
6+
namespace {
7+
8+
using benchmark::ClearRegisteredBenchmarks;
9+
using benchmark::ConsoleReporter;
10+
using benchmark::MemoryManager;
11+
using benchmark::RegisterBenchmark;
12+
using benchmark::RunSpecifiedBenchmarks;
13+
using benchmark::State;
14+
using benchmark::internal::Benchmark;
15+
16+
constexpr int N_REPETITIONS = 100;
17+
constexpr int N_ITERATIONS = 1;
18+
19+
int num_allocs = 0;
20+
int max_bytes_used = 0;
21+
int total_allocated_bytes = 0;
22+
int net_heap_growth = 0;
23+
24+
void reset() {
25+
num_allocs = 0;
26+
max_bytes_used = 0;
27+
total_allocated_bytes = 0;
28+
net_heap_growth = 0;
29+
}
30+
class TestMemoryManager : public MemoryManager {
31+
void Start() override {}
32+
void Stop(Result& result) override {
33+
result.num_allocs = num_allocs;
34+
result.net_heap_growth = net_heap_growth;
35+
result.max_bytes_used = max_bytes_used;
36+
result.total_allocated_bytes = total_allocated_bytes;
37+
38+
num_allocs += 1;
39+
max_bytes_used += 2;
40+
net_heap_growth += 4;
41+
total_allocated_bytes += 10;
42+
}
43+
};
44+
45+
class TestReporter : public ConsoleReporter {
46+
public:
47+
TestReporter() = default;
48+
virtual ~TestReporter() = default;
49+
50+
bool ReportContext(const Context& /*unused*/) override { return true; }
51+
52+
void PrintHeader(const Run&) override {}
53+
void PrintRunData(const Run& run) override {
54+
if (run.repetition_index == -1) return;
55+
if (!run.memory_result.memory_iterations) return;
56+
57+
store.push_back(run.memory_result);
58+
}
59+
60+
std::vector<MemoryManager::Result> store;
61+
};
62+
63+
class MemoryResultsTest : public testing::Test {
64+
public:
65+
Benchmark* bm;
66+
TestReporter reporter;
67+
68+
void SetUp() override {
69+
bm = RegisterBenchmark("BM", [](State& st) {
70+
for (auto _ : st) {
71+
}
72+
});
73+
bm->Repetitions(N_REPETITIONS);
74+
bm->Iterations(N_ITERATIONS);
75+
reset();
76+
}
77+
void TearDown() override { ClearRegisteredBenchmarks(); }
78+
};
79+
80+
TEST_F(MemoryResultsTest, NoMMTest) {
81+
RunSpecifiedBenchmarks(&reporter);
82+
EXPECT_EQ(reporter.store.size(), 0);
83+
}
84+
85+
TEST_F(MemoryResultsTest, ResultsTest) {
86+
auto mm = std::make_unique<TestMemoryManager>();
87+
RegisterMemoryManager(mm.get());
88+
89+
RunSpecifiedBenchmarks(&reporter);
90+
EXPECT_EQ(reporter.store.size(), N_REPETITIONS);
91+
92+
for (size_t i = 0; i < reporter.store.size(); i++) {
93+
EXPECT_EQ(reporter.store[i].num_allocs, static_cast<int64_t>(i));
94+
EXPECT_EQ(reporter.store[i].max_bytes_used, static_cast<int64_t>(i) * 2);
95+
EXPECT_EQ(reporter.store[i].net_heap_growth, static_cast<int64_t>(i) * 4);
96+
EXPECT_EQ(reporter.store[i].total_allocated_bytes,
97+
static_cast<int64_t>(i) * 10);
98+
}
99+
}
100+
101+
} // namespace

0 commit comments

Comments
 (0)