Skip to content

Instantly share code, notes, and snippets.

@SeijiEmery
Last active October 5, 2017 10:25
Show Gist options
  • Save SeijiEmery/3af0b7ddd08ca1cc3257dd4b8f93cb4e to your computer and use it in GitHub Desktop.
Save SeijiEmery/3af0b7ddd08ca1cc3257dd4b8f93cb4e to your computer and use it in GitHub Desktop.
//
// Memory + time benchmarking code: this hijacks (overloads) global new / delete
// to trace memory allocations (very simple: # of allocations / frees + # bytes
// allocated / freed), and adds a global variable that displays this stuff
// from its dtor (guaranteed to be called after main() but before program exits).
//
// It also adds basic time profiling (global ctor / dtor) using std::chrono.
//
// All of this can be achieved externally ofc using time + valgrind (*nix),
// and is perhaps preferable - but implementing these interally was an interesting
// exercise nevertheless.
//
// This can all be disabled if compiling with -D NO_MEM_DEBUG.
//
#ifndef NO_MEM_DEBUG
#include <chrono>
struct MemTracer {
void traceAlloc (size_t bytes) { ++numAllocations; allocatedMem += bytes; }
void traceFreed (size_t bytes) { ++numFrees; freedMem += bytes;}
private:
size_t numAllocations = 0; // number of allocations in this program
size_t numFrees = 0; // number of deallocations in this program
size_t allocatedMem = 0; // bytes allocated
size_t freedMem = 0; // bytes freed
std::chrono::high_resolution_clock::time_point t0; // time at program start
public:
MemTracer () : t0(std::chrono::high_resolution_clock::now()) {}
~MemTracer () {
using namespace std::chrono;
auto t1 = high_resolution_clock::now();
std::cout << "\nUsed memory: " << ((double)allocatedMem) * 1e-6 << " MB (" << numAllocations << " allocations)\n";
std::cout << "Freed memory: " << ((double)freedMem) * 1e-6 << " MB (" << numFrees << " deallocations)\n";
std::cout << "Ran in " << duration_cast<duration<double>>(t1 - t0).count() * 1e3 << " ms\n";
}
} g_memTracer;
void* operator new (size_t size) throw(std::bad_alloc) {
g_memTracer.traceAlloc(size);
size_t* mem = (size_t*)std::malloc(size + sizeof(size_t));
if (!mem) {
throw std::bad_alloc();
}
mem[0] = size;
return (void*)(&mem[1]);
}
void operator delete (void* mem) throw() {
auto ptr = &((size_t*)mem)[-1];
g_memTracer.traceFreed(ptr[0]);
std::free(ptr);
}
#endif // NO_MEM_DEBUG
@SeijiEmery
Copy link
Author

SeijiEmery commented Oct 4, 2017

Note: this is NOT threadsafe – though it could be made threadsafe by using atomic operations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment