Skip to content

Commit 0d62314

Browse files
committed
add memusage stat to os_provider and use it in benchmarks
1 parent c2024af commit 0d62314

File tree

5 files changed

+220
-26
lines changed

5 files changed

+220
-26
lines changed

benchmark/benchmark.hpp

+52-6
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ class provider_allocator : public allocator_interface {
173173
return argPos;
174174
}
175175

176+
void preBench(::benchmark::State &state) override {
177+
provider.preBench(state);
178+
}
179+
180+
void postBench(::benchmark::State &state) override {
181+
provider.postBench(state);
182+
}
183+
176184
void TearDown(::benchmark::State &state) override {
177185
provider.TearDown(state);
178186
}
@@ -204,13 +212,18 @@ template <typename Pool> class pool_allocator : public allocator_interface {
204212
return argPos;
205213
}
206214

215+
void preBench(::benchmark::State &state) override { pool.preBench(state); }
216+
void postBench(::benchmark::State &state) override {
217+
pool.postBench(state);
218+
}
219+
207220
void TearDown(::benchmark::State &state) override { pool.TearDown(state); }
208221

209-
virtual void *benchAlloc(size_t size) override {
222+
void *benchAlloc(size_t size) override {
210223
return umfPoolMalloc(pool.pool, size);
211224
}
212225

213-
virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) override {
226+
void benchFree(void *ptr, [[maybe_unused]] size_t size) override {
214227
umfPoolFree(pool.pool, ptr);
215228
}
216229

@@ -241,7 +254,7 @@ struct benchmark_interface : public benchmark::Fixture {
241254
allocator.TearDown(state);
242255
}
243256

244-
virtual void bench(::benchmark::State &state) = 0;
257+
void bench([[maybe_unused]] ::benchmark::State &state){};
245258

246259
virtual std::vector<std::string> argsName() {
247260
auto s = Size::argsName();
@@ -260,6 +273,9 @@ struct benchmark_interface : public benchmark::Fixture {
260273
benchmark->ArgNames(bench->argsName())->Name(bench->name());
261274
}
262275

276+
void custom_counters(::benchmark::State &state) {
277+
allocator.custom_counters(state);
278+
}
263279
std::vector<Size> alloc_sizes;
264280
Allocator allocator;
265281
};
@@ -282,7 +298,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
282298

283299
vector2d<alloc_data> allocations;
284300
std::vector<unsigned> iters;
285-
301+
std::vector<size_t> memused;
286302
vector2d<next_alloc_data> next;
287303
std::vector<std::vector<next_alloc_data>::const_iterator> next_iter;
288304
int64_t iterations;
@@ -302,6 +318,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
302318
allocations.resize(state.threads());
303319
next.resize(state.threads());
304320
next_iter.resize(state.threads());
321+
memused.assign(state.threads(), 0);
305322

306323
#ifndef WIN32
307324
// Ensure that system malloc does not have memory pooled on the heap
@@ -323,13 +340,36 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
323340
waitForAllThreads(state);
324341
// prepare workload for actual benchmark.
325342
freeAllocs(state);
343+
326344
prealloc(state);
327345
prepareWorkload(state);
346+
waitForAllThreads(state);
347+
base::allocator.preBench(state);
328348
}
329349

330350
void TearDown(::benchmark::State &state) override {
351+
base::allocator.postBench(state);
331352
auto tid = state.thread_index();
353+
if (tid == 0) {
354+
size_t current_memory_allocated = 0;
355+
for (const auto &used : memused) {
356+
current_memory_allocated += used;
357+
}
358+
359+
auto memory_used = state.counters["provider_memory_allocated"];
360+
361+
if (memory_used != 0) {
362+
state.counters["benchmark_memory_allocated"] =
363+
static_cast<double>(current_memory_allocated);
364+
state.counters["memory_overhead"] =
365+
100.0 * (memory_used - current_memory_allocated) /
366+
memory_used;
367+
} else {
368+
state.counters.erase("provider_memory_allocated");
369+
}
370+
}
332371

372+
waitForAllThreads(state);
333373
freeAllocs(state);
334374
waitForAllThreads(state);
335375
if (tid == 0) {
@@ -342,20 +382,22 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
342382
base::TearDown(state);
343383
}
344384

345-
void bench(benchmark::State &state) override {
385+
void bench(benchmark::State &state) {
346386
auto tid = state.thread_index();
347387
auto &allocation = allocations[tid];
388+
auto &memuse = memused[tid];
348389
for (int i = 0; i < allocsPerIterations; i++) {
349390
auto &n = *next_iter[tid]++;
350391
auto &alloc = allocation[n.offset];
351392
base::allocator.benchFree(alloc.ptr, alloc.size);
352-
393+
memuse -= alloc.size;
353394
alloc.size = n.size;
354395
alloc.ptr = base::allocator.benchAlloc(alloc.size);
355396

356397
if (alloc.ptr == NULL) {
357398
state.SkipWithError("allocation failed");
358399
}
400+
memuse += alloc.size;
359401
}
360402
}
361403

@@ -376,7 +418,9 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
376418
auto tid = state.thread_index();
377419
auto &i = allocations[tid];
378420
i.resize(max_allocs);
421+
auto &memuse = memused[tid];
379422
auto sizeGenerator = base::alloc_sizes[tid];
423+
380424
for (size_t j = 0; j < max_allocs; j++) {
381425
auto size = sizeGenerator.nextSize();
382426
i[j].ptr = base::allocator.benchAlloc(size);
@@ -385,6 +429,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
385429
return;
386430
}
387431
i[j].size = size;
432+
memuse += size;
388433
}
389434
}
390435

@@ -394,6 +439,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
394439
for (auto &j : i) {
395440
if (j.ptr != NULL) {
396441
base::allocator.benchFree(j.ptr, j.size);
442+
memused[tid] -= j.size;
397443
j.ptr = NULL;
398444
j.size = 0;
399445
}

benchmark/benchmark_umf.hpp

+53-16
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
#include <benchmark/benchmark.h>
1212
#include <umf/memory_pool.h>
1313
#include <umf/memory_provider.h>
14-
15-
#include <benchmark/benchmark.h>
1614
#include <umf/pools/pool_disjoint.h>
1715
#include <umf/pools/pool_proxy.h>
1816

@@ -30,7 +28,7 @@ struct provider_interface {
3028
using params_ptr = std::unique_ptr<void, void (*)(void *)>;
3129

3230
umf_memory_provider_handle_t provider = NULL;
33-
virtual void SetUp(::benchmark::State &state) {
31+
void SetUp(::benchmark::State &state) {
3432
if (state.thread_index() != 0) {
3533
return;
3634
}
@@ -42,7 +40,27 @@ struct provider_interface {
4240
}
4341
}
4442

45-
virtual void TearDown([[maybe_unused]] ::benchmark::State &state) {
43+
void preBench([[maybe_unused]] ::benchmark::State &state) {
44+
if (state.thread_index() != 0) {
45+
return;
46+
}
47+
umfCtlExec("umf.provider.by_handle.stats.reset", provider, NULL);
48+
}
49+
50+
void postBench([[maybe_unused]] ::benchmark::State &state) {
51+
if (state.thread_index() != 0) {
52+
return;
53+
}
54+
size_t arg;
55+
umf_result_t ret = umfCtlGet(
56+
"umf.provider.by_handle.stats.allocated_memory", provider, &arg);
57+
if (ret == UMF_RESULT_SUCCESS) {
58+
state.counters["provider_memory_allocated"] =
59+
static_cast<double>(arg);
60+
}
61+
}
62+
63+
void TearDown([[maybe_unused]] ::benchmark::State &state) {
4664
if (state.thread_index() != 0) {
4765
return;
4866
}
@@ -53,9 +71,7 @@ struct provider_interface {
5371
}
5472

5573
virtual umf_memory_provider_ops_t *
56-
getOps([[maybe_unused]] ::benchmark::State &state) {
57-
return nullptr;
58-
}
74+
getOps([[maybe_unused]] ::benchmark::State &state) = 0;
5975

6076
virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) {
6177
return {nullptr, [](void *) {}};
@@ -68,7 +84,7 @@ template <typename T,
6884
struct pool_interface {
6985
using params_ptr = std::unique_ptr<void, void (*)(void *)>;
7086

71-
virtual void SetUp(::benchmark::State &state) {
87+
void SetUp(::benchmark::State &state) {
7288
provider.SetUp(state);
7389
if (state.thread_index() != 0) {
7490
return;
@@ -80,7 +96,22 @@ struct pool_interface {
8096
state.SkipWithError("umfPoolCreate() failed");
8197
}
8298
}
83-
virtual void TearDown([[maybe_unused]] ::benchmark::State &state) {
99+
100+
void preBench([[maybe_unused]] ::benchmark::State &state) {
101+
provider.preBench(state);
102+
if (state.thread_index() != 0) {
103+
return;
104+
}
105+
}
106+
107+
void postBench([[maybe_unused]] ::benchmark::State &state) {
108+
provider.postBench(state);
109+
if (state.thread_index() != 0) {
110+
return;
111+
}
112+
}
113+
114+
void TearDown([[maybe_unused]] ::benchmark::State &state) {
84115
if (state.thread_index() != 0) {
85116
return;
86117
}
@@ -93,15 +124,17 @@ struct pool_interface {
93124
if (pool) {
94125
umfPoolDestroy(pool);
95126
}
127+
128+
provider.TearDown(state);
96129
};
97130

98131
virtual umf_memory_pool_ops_t *
99-
getOps([[maybe_unused]] ::benchmark::State &state) {
100-
return nullptr;
101-
}
132+
getOps([[maybe_unused]] ::benchmark::State &state) = 0;
133+
102134
virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) {
103135
return {nullptr, [](void *) {}};
104136
}
137+
105138
T provider;
106139
umf_memory_pool_handle_t pool;
107140
};
@@ -110,6 +143,8 @@ class allocator_interface {
110143
public:
111144
virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state,
112145
[[maybe_unused]] unsigned argPos) = 0;
146+
virtual void preBench([[maybe_unused]] ::benchmark::State &state) = 0;
147+
virtual void postBench([[maybe_unused]] ::benchmark::State &state) = 0;
113148
virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0;
114149
virtual void *benchAlloc(size_t size) = 0;
115150
virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) = 0;
@@ -121,7 +156,9 @@ struct glibc_malloc : public allocator_interface {
121156
unsigned argPos) override {
122157
return argPos;
123158
}
124-
void TearDown([[maybe_unused]] ::benchmark::State &state) override{};
159+
void preBench([[maybe_unused]] ::benchmark::State &state) override {}
160+
void postBench([[maybe_unused]] ::benchmark::State &state) override {}
161+
void TearDown([[maybe_unused]] ::benchmark::State &state) override {}
125162
void *benchAlloc(size_t size) override { return malloc(size); }
126163
void benchFree(void *ptr, [[maybe_unused]] size_t size) override {
127164
free(ptr);
@@ -163,7 +200,7 @@ struct fixed_provider : public provider_interface {
163200
char *mem = NULL;
164201
const size_t size = 1024 * 1024 * 1024; // 1GB
165202
public:
166-
virtual void SetUp(::benchmark::State &state) override {
203+
void SetUp(::benchmark::State &state) {
167204
if (state.thread_index() != 0) {
168205
return;
169206
}
@@ -175,7 +212,7 @@ struct fixed_provider : public provider_interface {
175212
provider_interface::SetUp(state);
176213
}
177214

178-
virtual void TearDown(::benchmark::State &state) override {
215+
void TearDown(::benchmark::State &state) {
179216
if (state.thread_index() != 0) {
180217
return;
181218
}
@@ -295,7 +332,7 @@ struct jemalloc_pool : public pool_interface<Provider> {
295332
#ifdef UMF_POOL_SCALABLE_ENABLED
296333
template <typename Provider>
297334
struct scalable_pool : public pool_interface<Provider> {
298-
virtual umf_memory_pool_ops_t *
335+
umf_memory_pool_ops_t *
299336
getOps([[maybe_unused]] ::benchmark::State &state) override {
300337
return umfScalablePoolOps();
301338
}

0 commit comments

Comments
 (0)