| 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
|