@@ -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+ size_t memory_used = state.counters [" provider_memory_allocated" ];
363+
364+ if (memory_used != 0 ) {
365+ state.counters [" benchmark_memory_allocated" ] =
366+ 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 }
0 commit comments