Skip to content

Commit 45bdf01

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

File tree

5 files changed

+223
-24
lines changed

5 files changed

+223
-24
lines changed

benchmark/benchmark.hpp

Lines changed: 55 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,10 @@ 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.resize(state.threads());
322+
for (int i = 0; i < state.threads(); i++) {
323+
memused[i] = 0;
324+
}
305325

306326
#ifndef WIN32
307327
// Ensure that system malloc does not have memory pooled on the heap
@@ -323,13 +343,36 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
323343
waitForAllThreads(state);
324344
// prepare workload for actual benchmark.
325345
freeAllocs(state);
346+
326347
prealloc(state);
327348
prepareWorkload(state);
349+
waitForAllThreads(state);
350+
base::allocator.preBench(state);
328351
}
329352

330353
void TearDown(::benchmark::State &state) override {
354+
base::allocator.postBench(state);
331355
auto tid = state.thread_index();
356+
if (tid == 0) {
357+
size_t current_memory_allocated = 0;
358+
for (int i = 0; i < state.threads(); i++) {
359+
current_memory_allocated += memused[i];
360+
}
361+
362+
auto memory_used = state.counters["provider_memory_allocated"];
363+
364+
if (memory_used != 0) {
365+
state.counters["benchmark_memory_allocated"] =
366+
static_cast<double>(current_memory_allocated);
367+
state.counters["memory_overhead"] =
368+
100.0 * (memory_used - current_memory_allocated) /
369+
memory_used;
370+
} else {
371+
state.counters.erase("provider_memory_allocated");
372+
}
373+
}
332374

375+
waitForAllThreads(state);
333376
freeAllocs(state);
334377
waitForAllThreads(state);
335378
if (tid == 0) {
@@ -342,20 +385,22 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
342385
base::TearDown(state);
343386
}
344387

345-
void bench(benchmark::State &state) override {
388+
void bench(benchmark::State &state) {
346389
auto tid = state.thread_index();
347390
auto &allocation = allocations[tid];
391+
auto &memuse = memused[tid];
348392
for (int i = 0; i < allocsPerIterations; i++) {
349393
auto &n = *next_iter[tid]++;
350394
auto &alloc = allocation[n.offset];
351395
base::allocator.benchFree(alloc.ptr, alloc.size);
352-
396+
memuse -= alloc.size;
353397
alloc.size = n.size;
354398
alloc.ptr = base::allocator.benchAlloc(alloc.size);
355399

356400
if (alloc.ptr == NULL) {
357401
state.SkipWithError("allocation failed");
358402
}
403+
memuse += alloc.size;
359404
}
360405
}
361406

@@ -376,7 +421,9 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
376421
auto tid = state.thread_index();
377422
auto &i = allocations[tid];
378423
i.resize(max_allocs);
424+
auto &memuse = memused[tid];
379425
auto sizeGenerator = base::alloc_sizes[tid];
426+
380427
for (size_t j = 0; j < max_allocs; j++) {
381428
auto size = sizeGenerator.nextSize();
382429
i[j].ptr = base::allocator.benchAlloc(size);
@@ -385,6 +432,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
385432
return;
386433
}
387434
i[j].size = size;
435+
memuse += size;
388436
}
389437
}
390438

@@ -394,6 +442,7 @@ class multiple_malloc_free_benchmark : public benchmark_interface<Size, Alloc> {
394442
for (auto &j : i) {
395443
if (j.ptr != NULL) {
396444
base::allocator.benchFree(j.ptr, j.size);
445+
memused[tid] -= j.size;
397446
j.ptr = NULL;
398447
j.size = 0;
399448
}

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)