Skip to content

Commit 2504e25

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

File tree

5 files changed

+220
-24
lines changed

5 files changed

+220
-24
lines changed

benchmark/benchmark.hpp

Lines changed: 52 additions & 6 deletions
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

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct provider_interface {
3030
using params_ptr = std::unique_ptr<void, void (*)(void *)>;
3131

3232
umf_memory_provider_handle_t provider = NULL;
33-
virtual void SetUp(::benchmark::State &state) {
33+
void SetUp(::benchmark::State &state) {
3434
if (state.thread_index() != 0) {
3535
return;
3636
}
@@ -42,7 +42,27 @@ struct provider_interface {
4242
}
4343
}
4444

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

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

6078
virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) {
6179
return {nullptr, [](void *) {}};
@@ -68,7 +86,7 @@ template <typename T,
6886
struct pool_interface {
6987
using params_ptr = std::unique_ptr<void, void (*)(void *)>;
7088

71-
virtual void SetUp(::benchmark::State &state) {
89+
void SetUp(::benchmark::State &state) {
7290
provider.SetUp(state);
7391
if (state.thread_index() != 0) {
7492
return;
@@ -80,7 +98,22 @@ struct pool_interface {
8098
state.SkipWithError("umfPoolCreate() failed");
8199
}
82100
}
83-
virtual void TearDown([[maybe_unused]] ::benchmark::State &state) {
101+
102+
void preBench([[maybe_unused]] ::benchmark::State &state) {
103+
provider.preBench(state);
104+
if (state.thread_index() != 0) {
105+
return;
106+
}
107+
}
108+
109+
void postBench([[maybe_unused]] ::benchmark::State &state) {
110+
provider.postBench(state);
111+
if (state.thread_index() != 0) {
112+
return;
113+
}
114+
}
115+
116+
void TearDown([[maybe_unused]] ::benchmark::State &state) {
84117
if (state.thread_index() != 0) {
85118
return;
86119
}
@@ -93,15 +126,17 @@ struct pool_interface {
93126
if (pool) {
94127
umfPoolDestroy(pool);
95128
}
129+
130+
provider.TearDown(state);
96131
};
97132

98133
virtual umf_memory_pool_ops_t *
99-
getOps([[maybe_unused]] ::benchmark::State &state) {
100-
return nullptr;
101-
}
134+
getOps([[maybe_unused]] ::benchmark::State &state) = 0;
135+
102136
virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) {
103137
return {nullptr, [](void *) {}};
104138
}
139+
105140
T provider;
106141
umf_memory_pool_handle_t pool;
107142
};
@@ -110,6 +145,8 @@ class allocator_interface {
110145
public:
111146
virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state,
112147
[[maybe_unused]] unsigned argPos) = 0;
148+
virtual void preBench([[maybe_unused]] ::benchmark::State &state) = 0;
149+
virtual void postBench([[maybe_unused]] ::benchmark::State &state) = 0;
113150
virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0;
114151
virtual void *benchAlloc(size_t size) = 0;
115152
virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) = 0;
@@ -121,7 +158,9 @@ struct glibc_malloc : public allocator_interface {
121158
unsigned argPos) override {
122159
return argPos;
123160
}
124-
void TearDown([[maybe_unused]] ::benchmark::State &state) override{};
161+
void preBench([[maybe_unused]] ::benchmark::State &state) override {}
162+
void postBench([[maybe_unused]] ::benchmark::State &state) override {}
163+
void TearDown([[maybe_unused]] ::benchmark::State &state) override {}
125164
void *benchAlloc(size_t size) override { return malloc(size); }
126165
void benchFree(void *ptr, [[maybe_unused]] size_t size) override {
127166
free(ptr);
@@ -163,7 +202,7 @@ struct fixed_provider : public provider_interface {
163202
char *mem = NULL;
164203
const size_t size = 1024 * 1024 * 1024; // 1GB
165204
public:
166-
virtual void SetUp(::benchmark::State &state) override {
205+
void SetUp(::benchmark::State &state) {
167206
if (state.thread_index() != 0) {
168207
return;
169208
}
@@ -175,7 +214,7 @@ struct fixed_provider : public provider_interface {
175214
provider_interface::SetUp(state);
176215
}
177216

178-
virtual void TearDown(::benchmark::State &state) override {
217+
void TearDown(::benchmark::State &state) {
179218
if (state.thread_index() != 0) {
180219
return;
181220
}
@@ -295,7 +334,7 @@ struct jemalloc_pool : public pool_interface<Provider> {
295334
#ifdef UMF_POOL_SCALABLE_ENABLED
296335
template <typename Provider>
297336
struct scalable_pool : public pool_interface<Provider> {
298-
virtual umf_memory_pool_ops_t *
337+
umf_memory_pool_ops_t *
299338
getOps([[maybe_unused]] ::benchmark::State &state) override {
300339
return umfScalablePoolOps();
301340
}

0 commit comments

Comments
 (0)