| 1 | // mycpp/bump_leak_heap.cc: Leaky Bump Allocator
 | 
| 2 | 
 | 
| 3 | #include "mycpp/bump_leak_heap.h"
 | 
| 4 | 
 | 
| 5 | #include <inttypes.h>  // PRId64
 | 
| 6 | #include <stddef.h>
 | 
| 7 | #include <stdio.h>
 | 
| 8 | #include <string.h>  // memcpy
 | 
| 9 | #include <unistd.h>  // STDERR_FILENO
 | 
| 10 | 
 | 
| 11 | #include "mycpp/common.h"  // aligned
 | 
| 12 | 
 | 
| 13 | // We need this #ifdef because we don't want the global var in other binaries
 | 
| 14 | 
 | 
| 15 | #if defined(BUMP_LEAK) || defined(BUMP_SMALL) || defined(BUMP_BIG)
 | 
| 16 | 
 | 
| 17 | // some benchmarks take more than 1 GiB
 | 
| 18 | // but cachegrind can't work with static data of 2 GiB (get mmap() error)
 | 
| 19 | char gMemory[MiB(1400)];
 | 
| 20 | 
 | 
| 21 | // This type is for "layout"; it's not instantiated
 | 
| 22 | struct LayoutBlock {
 | 
| 23 |   size_t num_bytes;
 | 
| 24 |   char data[1];  // flexible array
 | 
| 25 | };
 | 
| 26 | 
 | 
| 27 | // offsetof() accounts for possible padding, but it should equal sizeof(size_t)
 | 
| 28 | const int kHeaderSize = offsetof(LayoutBlock, data);
 | 
| 29 | 
 | 
| 30 | // Allocate() bumps a pointer
 | 
| 31 | void* BumpLeakHeap::Allocate(size_t num_bytes) {
 | 
| 32 |   char* p = &(gMemory[mem_pos_]);
 | 
| 33 |   LayoutBlock* block = reinterpret_cast<LayoutBlock*>(p);
 | 
| 34 |   block->num_bytes = num_bytes;  // record size for Reallocate()
 | 
| 35 | 
 | 
| 36 |   mem_pos_ += aligned(kHeaderSize + num_bytes);
 | 
| 37 | 
 | 
| 38 |   // Update stats
 | 
| 39 |   num_allocated_++;
 | 
| 40 |   bytes_allocated_ += num_bytes;
 | 
| 41 | 
 | 
| 42 |   // log("Allocate() -> %p", block->data);
 | 
| 43 |   return block->data;  // pointer user can write to
 | 
| 44 | }
 | 
| 45 | 
 | 
| 46 | // Reallocate() calls Allocate() and then copies the old data
 | 
| 47 | void* BumpLeakHeap::Reallocate(void* old_data, size_t num_bytes) {
 | 
| 48 |   // log("");
 | 
| 49 |   // log("Reallocate(%d) got %p", num_bytes, old_data);
 | 
| 50 |   char* new_data = reinterpret_cast<char*>(Allocate(num_bytes));
 | 
| 51 | 
 | 
| 52 |   char* p_old = reinterpret_cast<char*>(old_data) - kHeaderSize;
 | 
| 53 |   LayoutBlock* old_block = reinterpret_cast<LayoutBlock*>(p_old);
 | 
| 54 | 
 | 
| 55 |   memcpy(new_data, old_block->data, old_block->num_bytes);
 | 
| 56 | 
 | 
| 57 |   return new_data;
 | 
| 58 | }
 | 
| 59 | 
 | 
| 60 | void BumpLeakHeap::PrintStats(int fd) {
 | 
| 61 |   dprintf(fd, "[BumpLeakHeap]");
 | 
| 62 |   #ifdef BUMP_ROOT
 | 
| 63 |   dprintf(fd, "      max roots = %10d\n", max_roots_);
 | 
| 64 |   #endif
 | 
| 65 |   dprintf(fd, "  num allocated = %10d\n", num_allocated_);
 | 
| 66 |   dprintf(fd, "bytes allocated = %10" PRId64 "\n", bytes_allocated_);
 | 
| 67 |   dprintf(fd, "  mem pos       = %10d\n", mem_pos_);
 | 
| 68 | }
 | 
| 69 | 
 | 
| 70 | void BumpLeakHeap::CleanProcessExit() {
 | 
| 71 |   PrintStats(STDERR_FILENO);
 | 
| 72 | }
 | 
| 73 | 
 | 
| 74 | void BumpLeakHeap::ProcessExit() {
 | 
| 75 |   PrintStats(STDERR_FILENO);
 | 
| 76 | }
 | 
| 77 | #endif
 | 
| 78 | 
 | 
| 79 | #ifdef BUMP_LEAK
 | 
| 80 | BumpLeakHeap gHeap;
 | 
| 81 | #endif
 |