mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1735250 - Provide a less-magic array size for jemalloc_stats r=glandium
jemalloc_stats takes an array for its second argument. It expects this array to have enough space for all the bins, previously the maximum was set as a magic number. To make it dependent on the configured bins this patch replaces the compile-time constant with a function. Differential Revision: https://phabricator.services.mozilla.com/D127761
This commit is contained in:
parent
1b721fc414
commit
1a20d57362
@ -63,11 +63,14 @@ MALLOC_DECL(malloc_good_size, size_t, size_t)
|
||||
# endif
|
||||
|
||||
# if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC
|
||||
// The 2nd argument points to an optional array exactly JEMALLOC_MAX_STATS_BINS
|
||||
// long to be filled in (if non-null). Any unused bin has it's size set to zero.
|
||||
// The 2nd argument points to an optional array exactly
|
||||
// jemalloc_stats_num_bins() long to be filled in (if non-null).
|
||||
MALLOC_DECL(jemalloc_stats_internal, void, jemalloc_stats_t*,
|
||||
jemalloc_bin_stats_t*)
|
||||
|
||||
// Return the size of the jemalloc_bin_stats_t array.
|
||||
MALLOC_DECL(jemalloc_stats_num_bins, size_t)
|
||||
|
||||
// On some operating systems (Mac), we use madvise(MADV_FREE) to hand pages
|
||||
// back to the operating system. On Mac, the operating system doesn't take
|
||||
// this memory back immediately; instead, the OS takes it back only when the
|
||||
|
@ -3966,8 +3966,6 @@ static bool malloc_init_hard() {
|
||||
gRealPageSize = gPageSize = (size_t)result;
|
||||
#endif
|
||||
|
||||
MOZ_RELEASE_ASSERT(JEMALLOC_MAX_STATS_BINS >= NUM_SMALL_CLASSES);
|
||||
|
||||
// Get runtime configuration.
|
||||
if ((opts = getenv("MALLOC_OPTIONS"))) {
|
||||
for (i = 0; opts[i] != '\0'; i++) {
|
||||
@ -4326,10 +4324,7 @@ inline void MozJemalloc::jemalloc_stats_internal(
|
||||
return;
|
||||
}
|
||||
if (aBinStats) {
|
||||
// An assertion in malloc_init_hard will guarantee that
|
||||
// JEMALLOC_MAX_STATS_BINS >= NUM_SMALL_CLASSES.
|
||||
memset(aBinStats, 0,
|
||||
sizeof(jemalloc_bin_stats_t) * JEMALLOC_MAX_STATS_BINS);
|
||||
memset(aBinStats, 0, sizeof(jemalloc_bin_stats_t) * NUM_SMALL_CLASSES);
|
||||
}
|
||||
|
||||
// Gather runtime settings.
|
||||
@ -4455,6 +4450,11 @@ inline void MozJemalloc::jemalloc_stats_internal(
|
||||
aStats->page_cache + aStats->bookkeeping);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t MozJemalloc::jemalloc_stats_num_bins() {
|
||||
return NUM_SMALL_CLASSES;
|
||||
}
|
||||
|
||||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
|
||||
// Explicitly remove all of this chunk's MADV_FREE'd pages from memory.
|
||||
|
@ -113,9 +113,6 @@ typedef struct {
|
||||
size_t bytes_per_run; // The number of bytes per run, including headers.
|
||||
} jemalloc_bin_stats_t;
|
||||
|
||||
// This is the total number of bins.
|
||||
#define JEMALLOC_MAX_STATS_BINS 51
|
||||
|
||||
enum PtrInfoTag {
|
||||
// The pointer is not currently known to the allocator.
|
||||
// 'addr', 'size', and 'arenaId' are always 0.
|
||||
|
@ -11,6 +11,7 @@
|
||||
// necessary:
|
||||
// - malloc_good_size (used to be called je_malloc_usable_in_advance)
|
||||
// - jemalloc_stats
|
||||
// - jemalloc_stats_num_bins
|
||||
// - jemalloc_purge_freed_pages
|
||||
// - jemalloc_free_dirty_pages
|
||||
// - jemalloc_thread_local_arena
|
||||
|
@ -35,6 +35,7 @@
|
||||
//
|
||||
// - jemalloc specific functions:
|
||||
// - jemalloc_stats
|
||||
// - jemalloc_stats_num_bins
|
||||
// - jemalloc_purge_freed_pages
|
||||
// - jemalloc_free_dirty_pages
|
||||
// - jemalloc_thread_local_arena
|
||||
|
@ -773,7 +773,10 @@ class Replay {
|
||||
}
|
||||
mOps++;
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_bin_stats_t bin_stats[JEMALLOC_MAX_STATS_BINS];
|
||||
// Using a variable length array here is a GCC & Clang extension. But it
|
||||
// allows us to place this on the stack and not alter jemalloc's profiling.
|
||||
const size_t num_bins = ::jemalloc_stats_num_bins();
|
||||
jemalloc_bin_stats_t bin_stats[num_bins];
|
||||
::jemalloc_stats_internal(&stats, bin_stats);
|
||||
|
||||
#ifdef XP_LINUX
|
||||
@ -788,7 +791,8 @@ class Replay {
|
||||
size_t large_used = 0;
|
||||
size_t huge_slop = 0;
|
||||
size_t huge_used = 0;
|
||||
size_t bin_slop[JEMALLOC_MAX_STATS_BINS] = {0};
|
||||
size_t bin_slop[num_bins];
|
||||
memset(bin_slop, 0, sizeof(size_t) * num_bins);
|
||||
|
||||
for (size_t slot_id = 0; slot_id < mNumUsedSlots; slot_id++) {
|
||||
MemSlot& slot = mSlots[slot_id];
|
||||
@ -806,7 +810,7 @@ class Replay {
|
||||
(stats.subpage_max ? stats.subpage_max : stats.quantum_wide_max)) {
|
||||
// We know that this is an inefficient linear search, but there's a
|
||||
// small number of bins and this is simple.
|
||||
for (unsigned i = 0; i < JEMALLOC_MAX_STATS_BINS; i++) {
|
||||
for (unsigned i = 0; i < num_bins; i++) {
|
||||
auto& bin = bin_stats[i];
|
||||
if (used == bin.size) {
|
||||
bin_slop[i] += slop;
|
||||
@ -866,23 +870,20 @@ class Replay {
|
||||
"unused (c)", "total (c)", "used (c)", "non-full (r)", "total (r)",
|
||||
"used (r)");
|
||||
for (auto& bin : bin_stats) {
|
||||
if (bin.size) {
|
||||
FdPrintf(mStdErr, "%8zu %8zuKiB %7zuKiB %7zu%% %12zu %9zu %7zu%%\n",
|
||||
bin.size, bin.bytes_unused / 1024, bin.bytes_total / 1024,
|
||||
percent(bin.bytes_total - bin.bytes_unused, bin.bytes_total),
|
||||
bin.num_non_full_runs, bin.num_runs,
|
||||
percent(bin.num_runs - bin.num_non_full_runs, bin.num_runs));
|
||||
}
|
||||
MOZ_ASSERT(bin.size);
|
||||
FdPrintf(mStdErr, "%8zu %8zuKiB %7zuKiB %7zu%% %12zu %9zu %7zu%%\n",
|
||||
bin.size, bin.bytes_unused / 1024, bin.bytes_total / 1024,
|
||||
percent(bin.bytes_total - bin.bytes_unused, bin.bytes_total),
|
||||
bin.num_non_full_runs, bin.num_runs,
|
||||
percent(bin.num_runs - bin.num_non_full_runs, bin.num_runs));
|
||||
}
|
||||
|
||||
FdPrintf(mStdErr, "\n%5s %8s %9s %7s\n", "bin", "slop", "used", "percent");
|
||||
for (unsigned i = 0; i < JEMALLOC_MAX_STATS_BINS; i++) {
|
||||
for (unsigned i = 0; i < num_bins; i++) {
|
||||
auto& bin = bin_stats[i];
|
||||
if (bin.size) {
|
||||
size_t used = bin.bytes_total - bin.bytes_unused;
|
||||
FdPrintf(mStdErr, "%5zu %8zu %9zu %6zu%%\n", bin.size, bin_slop[i],
|
||||
used, percent(bin_slop[i], used));
|
||||
}
|
||||
size_t used = bin.bytes_total - bin.bytes_unused;
|
||||
FdPrintf(mStdErr, "%5zu %8zu %9zu %6zu%%\n", bin.size, bin_slop[i], used,
|
||||
percent(bin_slop[i], used));
|
||||
}
|
||||
FdPrintf(mStdErr, "%5s %8zu %9zu %6zu%%\n", "large", large_slop, large_used,
|
||||
percent(large_slop, large_used));
|
||||
@ -896,22 +897,21 @@ class Replay {
|
||||
/*
|
||||
* Create and print frequency distributions of memory requests.
|
||||
*/
|
||||
void print_distributions(
|
||||
jemalloc_stats_t& stats,
|
||||
jemalloc_bin_stats_t (&bin_stats)[JEMALLOC_MAX_STATS_BINS]) {
|
||||
void print_distributions(jemalloc_stats_t& stats,
|
||||
jemalloc_bin_stats_t* bin_stats) {
|
||||
const size_t num_bins = ::jemalloc_stats_num_bins();
|
||||
|
||||
// We compute distributions for all of the bins for small allocations
|
||||
// (JEMALLOC_MAX_STATS_BINS) plus two more distributions for larger
|
||||
// allocations.
|
||||
Distribution dists[JEMALLOC_MAX_STATS_BINS + 2];
|
||||
// (num_bins) plus two more distributions for larger allocations.
|
||||
Distribution dists[num_bins + 2];
|
||||
|
||||
unsigned last_size = 0;
|
||||
unsigned num_dists = 0;
|
||||
for (auto& bin : bin_stats) {
|
||||
if (bin.size == 0) {
|
||||
break;
|
||||
}
|
||||
for (unsigned i = 0; i < num_bins; i++) {
|
||||
auto& bin = bin_stats[i];
|
||||
auto& dist = dists[num_dists++];
|
||||
|
||||
MOZ_ASSERT(bin.size);
|
||||
if (bin.size <= 16) {
|
||||
// 1 byte buckets.
|
||||
dist = Distribution(bin.size, last_size, 1);
|
||||
@ -938,7 +938,7 @@ class Replay {
|
||||
Distribution(stats.page_size * 4, stats.page_size, stats.page_size / 4);
|
||||
num_dists++;
|
||||
|
||||
MOZ_RELEASE_ASSERT(num_dists <= JEMALLOC_MAX_STATS_BINS + 2);
|
||||
MOZ_RELEASE_ASSERT(num_dists <= num_bins + 2);
|
||||
|
||||
for (size_t slot_id = 0; slot_id < mNumUsedSlots; slot_id++) {
|
||||
MemSlot& slot = mSlots[slot_id];
|
||||
|
@ -1206,7 +1206,8 @@ class JemallocHeapReporter final : public nsIMemoryReporter {
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize) override {
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_bin_stats_t bin_stats[JEMALLOC_MAX_STATS_BINS];
|
||||
const size_t num_bins = jemalloc_stats_num_bins();
|
||||
jemalloc_bin_stats_t bin_stats[num_bins];
|
||||
jemalloc_stats(&stats, bin_stats);
|
||||
|
||||
// clang-format off
|
||||
@ -1225,9 +1226,7 @@ class JemallocHeapReporter final : public nsIMemoryReporter {
|
||||
// because KIND_HEAP memory means "counted in heap-allocated", which
|
||||
// this is not.
|
||||
for (auto& bin : bin_stats) {
|
||||
if (!bin.size) {
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(bin.size);
|
||||
nsPrintfCString path("explicit/heap-overhead/bin-unused/bin-%zu",
|
||||
bin.size);
|
||||
aHandleReport->Callback(EmptyCString(), path, KIND_NONHEAP, UNITS_BYTES,
|
||||
|
Loading…
Reference in New Issue
Block a user