diff --git a/Makefile.in b/Makefile.in index cd927cfe..b211f889 100644 --- a/Makefile.in +++ b/Makefile.in @@ -222,6 +222,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/pa.c \ $(srcroot)test/unit/pack.c \ $(srcroot)test/unit/pages.c \ + $(srcroot)test/unit/peak.c \ $(srcroot)test/unit/ph.c \ $(srcroot)test/unit/prng.c \ $(srcroot)test/unit/prof_accum.c \ diff --git a/include/jemalloc/internal/peak.h b/include/jemalloc/internal/peak.h new file mode 100644 index 00000000..59da3e41 --- /dev/null +++ b/include/jemalloc/internal/peak.h @@ -0,0 +1,37 @@ +#ifndef JEMALLOC_INTERNAL_PEAK_H +#define JEMALLOC_INTERNAL_PEAK_H + +typedef struct peak_s peak_t; +struct peak_s { + /* The highest recorded peak value, after adjustment (see below). */ + uint64_t cur_max; + /* + * The difference between alloc and dalloc at the last set_zero call; + * this lets us cancel out the appropriate amount of excess. + */ + uint64_t adjustment; +}; + +#define PEAK_INITIALIZER {0, 0} + +static inline uint64_t +peak_max(peak_t *peak) { + return peak->cur_max; +} + +static inline void +peak_update(peak_t *peak, uint64_t alloc, uint64_t dalloc) { + int64_t candidate_max = (int64_t)(alloc - dalloc - peak->adjustment); + if (candidate_max > (int64_t)peak->cur_max) { + peak->cur_max = candidate_max; + } +} + +/* Resets the counter to zero; all peaks are now relative to this point. */ +static inline void +peak_set_zero(peak_t *peak, uint64_t alloc, uint64_t dalloc) { + peak->cur_max = 0; + peak->adjustment = alloc - dalloc; +} + +#endif /* JEMALLOC_INTERNAL_PEAK_H */ diff --git a/test/unit/peak.c b/test/unit/peak.c new file mode 100644 index 00000000..11129785 --- /dev/null +++ b/test/unit/peak.c @@ -0,0 +1,47 @@ +#include "test/jemalloc_test.h" + +#include "jemalloc/internal/peak.h" + +TEST_BEGIN(test_peak) { + peak_t peak = PEAK_INITIALIZER; + expect_u64_eq(0, peak_max(&peak), + "Peak should be zero at initialization"); + peak_update(&peak, 100, 50); + expect_u64_eq(50, peak_max(&peak), + "Missed update"); + peak_update(&peak, 100, 100); + expect_u64_eq(50, peak_max(&peak), "Dallocs shouldn't change peak"); + peak_update(&peak, 100, 200); + expect_u64_eq(50, peak_max(&peak), "Dallocs shouldn't change peak"); + peak_update(&peak, 200, 200); + expect_u64_eq(50, peak_max(&peak), "Haven't reached peak again"); + peak_update(&peak, 300, 200); + expect_u64_eq(100, peak_max(&peak), "Missed an update."); + peak_set_zero(&peak, 300, 200); + expect_u64_eq(0, peak_max(&peak), "No effect from zeroing"); + peak_update(&peak, 300, 300); + expect_u64_eq(0, peak_max(&peak), "Dalloc shouldn't change peak"); + peak_update(&peak, 400, 300); + expect_u64_eq(0, peak_max(&peak), "Should still be net negative"); + peak_update(&peak, 500, 300); + expect_u64_eq(100, peak_max(&peak), "Missed an update."); + /* + * Above, we set to zero while a net allocator; let's try as a + * net-deallocator. + */ + peak_set_zero(&peak, 600, 700); + expect_u64_eq(0, peak_max(&peak), "No effect from zeroing."); + peak_update(&peak, 600, 800); + expect_u64_eq(0, peak_max(&peak), "Dalloc shouldn't change peak."); + peak_update(&peak, 700, 800); + expect_u64_eq(0, peak_max(&peak), "Should still be net negative."); + peak_update(&peak, 800, 800); + expect_u64_eq(100, peak_max(&peak), "Missed an update."); +} +TEST_END + +int +main(void) { + return test_no_reentrancy( + test_peak); +}