Track malloc size with a header for SHOW_MEMORY

This commit is contained in:
2024-03-14 15:30:46 -07:00
parent ee36bda8f8
commit b817e3c749
4 changed files with 29 additions and 26 deletions

View File

@@ -2819,6 +2819,7 @@ void removeKey(Node *n) {
struct __attribute__((visibility("default"))) PeakPrinter { struct __attribute__((visibility("default"))) PeakPrinter {
~PeakPrinter() { ~PeakPrinter() {
printf("malloc bytes: %g\n", double(mallocBytes));
printf("Peak malloc bytes: %g\n", double(peakMallocBytes)); printf("Peak malloc bytes: %g\n", double(peakMallocBytes));
printf("Node bytes: %g\n", double(nodeBytes)); printf("Node bytes: %g\n", double(nodeBytes));
printf("Peak node bytes: %g\n", double(peakNodeBytes)); printf("Peak node bytes: %g\n", double(peakNodeBytes));

View File

@@ -102,7 +102,7 @@ ConflictSet::ConflictSet(int64_t oldestVersion)
ConflictSet::~ConflictSet() { ConflictSet::~ConflictSet() {
if (impl) { if (impl) {
impl->~Impl(); impl->~Impl();
free(impl); safe_free(impl);
} }
} }
@@ -142,6 +142,6 @@ ConflictSet_create(int64_t oldestVersion) {
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) { __attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
using Impl = ConflictSet::Impl; using Impl = ConflictSet::Impl;
((Impl *)cs)->~Impl(); ((Impl *)cs)->~Impl();
free(cs); safe_free(cs);
} }
} }

View File

@@ -41,45 +41,47 @@ operator<=>(const std::span<const uint8_t> &lhs,
// GCOVR_EXCL_START // GCOVR_EXCL_START
#if SHOW_MEMORY #if SHOW_MEMORY
#ifdef __APPLE__
#include <malloc/malloc.h>
#else
#include <malloc.h>
#endif
inline int64_t mallocBytes = 0; inline int64_t mallocBytes = 0;
inline int64_t peakMallocBytes = 0; inline int64_t peakMallocBytes = 0;
constexpr auto kIntMallocHeaderSize = 16;
#endif #endif
// malloc that aborts on OOM and thus always returns a non-null pointer // malloc that aborts on OOM and thus always returns a non-null pointer. Must be
// paired with `safe_free`.
__attribute__((always_inline)) inline void *safe_malloc(size_t s) { __attribute__((always_inline)) inline void *safe_malloc(size_t s) {
#if SHOW_MEMORY
mallocBytes += s;
if (mallocBytes > peakMallocBytes) {
peakMallocBytes = mallocBytes;
}
void *p = malloc(s + kIntMallocHeaderSize);
if (p == nullptr) {
abort();
}
memcpy(p, &s, sizeof(s));
return (char *)p + kIntMallocHeaderSize;
#else
void *p = malloc(s); void *p = malloc(s);
if (p == nullptr) { if (p == nullptr) {
abort(); abort();
} }
#if SHOW_MEMORY
#ifdef __APPLE__
mallocBytes += s;
#else
mallocBytes += malloc_usable_size(p);
#endif
if (mallocBytes > peakMallocBytes) {
peakMallocBytes = mallocBytes;
}
#endif
return p; return p;
#endif
} }
// Must be paired with `safe_malloc`.
//
// There's nothing safer about this than free. Only called safe_free for // There's nothing safer about this than free. Only called safe_free for
// symmetry with safe_malloc. // symmetry with safe_malloc.
__attribute__((always_inline)) inline void safe_free(void *p) { __attribute__((always_inline)) inline void safe_free(void *p) {
#if SHOW_MEMORY #if SHOW_MEMORY
#ifdef __APPLE__ size_t s;
mallocBytes -= malloc_size(p); memcpy(&s, (char *)p - kIntMallocHeaderSize, sizeof(s));
mallocBytes -= s;
free((char *)p - kIntMallocHeaderSize);
#else #else
mallocBytes -= malloc_usable_size(p);
#endif
#endif
free(p); free(p);
#endif
} }
// ==================== BEGIN ARENA IMPL ==================== // ==================== BEGIN ARENA IMPL ====================
@@ -164,7 +166,7 @@ inline Arena::Arena(int initialSize) : impl(nullptr) {
inline void onDestroy(Arena::ArenaImpl *impl) { inline void onDestroy(Arena::ArenaImpl *impl) {
while (impl) { while (impl) {
auto *prev = impl->prev; auto *prev = impl->prev;
free(impl); safe_free(impl);
impl = prev; impl = prev;
} }
} }

View File

@@ -149,7 +149,7 @@ private:
setMaxVersion(level, v); setMaxVersion(level, v);
} }
void destroy() { free(this); } void destroy() { safe_free(this); }
private: private:
int getNodeSize() const { int getNodeSize() const {
@@ -655,7 +655,7 @@ ConflictSet::ConflictSet(int64_t oldestVersion)
ConflictSet::~ConflictSet() { ConflictSet::~ConflictSet() {
if (impl) { if (impl) {
impl->~Impl(); impl->~Impl();
free(impl); safe_free(impl);
} }
} }