@@ -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 }
0 commit comments