diff options
Diffstat (limited to 'memory/build/mozjemalloc_compat.c')
-rw-r--r-- | memory/build/mozjemalloc_compat.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/memory/build/mozjemalloc_compat.c b/memory/build/mozjemalloc_compat.c new file mode 100644 index 000000000..6591892c1 --- /dev/null +++ b/memory/build/mozjemalloc_compat.c @@ -0,0 +1,182 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZ_JEMALLOC4 +# error Should only compile this file when building with jemalloc 3 +#endif + +#define MOZ_JEMALLOC_IMPL + +#include "mozmemory_wrap.h" +#include "jemalloc_types.h" +#include "mozilla/Types.h" + +#include <stdbool.h> + +#if defined(MOZ_SYSTEM_JEMALLOC) +# include MALLOC_H +#else +# include "jemalloc/jemalloc.h" +#endif + +/* + * CTL_* macros are from memory/jemalloc/src/src/stats.c with changes: + * - drop `t' argument to avoid redundancy in calculating type size + * - require `i' argument for arena number explicitly + */ + +#define CTL_GET(n, v) do { \ + size_t sz = sizeof(v); \ + je_(mallctl)(n, &v, &sz, NULL, 0); \ +} while (0) + +#define CTL_I_GET(n, v, i) do { \ + size_t mib[6]; \ + size_t miblen = sizeof(mib) / sizeof(mib[0]); \ + size_t sz = sizeof(v); \ + je_(mallctlnametomib)(n, mib, &miblen); \ + mib[2] = i; \ + je_(mallctlbymib)(mib, miblen, &v, &sz, NULL, 0); \ +} while (0) + +#define CTL_IJ_GET(n, v, i, j) do { \ + size_t mib[6]; \ + size_t miblen = sizeof(mib) / sizeof(mib[0]); \ + size_t sz = sizeof(v); \ + je_(mallctlnametomib)(n, mib, &miblen); \ + mib[2] = i; \ + mib[4] = j; \ + je_(mallctlbymib)(mib, miblen, &v, &sz, NULL, 0); \ +} while (0) + +/* + * VARIABLE_ARRAY is copied from + * memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in + */ +#if __STDC_VERSION__ < 199901L +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# include <stdlib.h> +# endif +# endif +# define VARIABLE_ARRAY(type, name, count) \ + type *name = alloca(sizeof(type) * (count)) +#else +# define VARIABLE_ARRAY(type, name, count) type name[(count)] +#endif + +MOZ_MEMORY_API size_t +malloc_good_size_impl(size_t size) +{ + /* je_nallocx crashes when given a size of 0. As + * malloc_usable_size(malloc(0)) and malloc_usable_size(malloc(1)) + * return the same value, use a size of 1. */ + if (size == 0) + size = 1; + return je_(nallocx)(size, 0); +} + +static void +compute_bin_unused_and_bookkeeping(jemalloc_stats_t *stats, unsigned int narenas) +{ + size_t bin_unused = 0; + + uint32_t nregs; // number of regions per run in the j-th bin + size_t reg_size; // size of regions served by the j-th bin + size_t curruns; // number of runs belonging to a bin + size_t curregs; // number of allocated regions in a bin + + unsigned int nbins; // number of bins per arena + unsigned int i, j; + + size_t stats_metadata; + size_t stats_ametadata = 0; // total internal allocations in all arenas + + // narenas also counts uninitialized arenas, and initialized arenas + // are not guaranteed to be adjacent + VARIABLE_ARRAY(bool, initialized, narenas); + size_t isz = sizeof(initialized) / sizeof(initialized[0]); + + je_(mallctl)("arenas.initialized", initialized, &isz, NULL, 0); + CTL_GET("arenas.nbins", nbins); + + for (j = 0; j < nbins; j++) { + CTL_I_GET("arenas.bin.0.nregs", nregs, j); + CTL_I_GET("arenas.bin.0.size", reg_size, j); + + for (i = 0; i < narenas; i++) { + if (!initialized[i]) { + continue; + } + + CTL_IJ_GET("stats.arenas.0.bins.0.curruns", curruns, i, j); + CTL_IJ_GET("stats.arenas.0.bins.0.curregs", curregs, i, j); + + bin_unused += (nregs * curruns - curregs) * reg_size; + } + } + + CTL_GET("stats.metadata", stats_metadata); + + /* get the summation for all arenas, i == narenas */ + CTL_I_GET("stats.arenas.0.metadata.allocated", stats_ametadata, narenas); + + stats->bookkeeping = stats_metadata - stats_ametadata; + stats->bin_unused = bin_unused; +} + +MOZ_JEMALLOC_API void +jemalloc_stats_impl(jemalloc_stats_t *stats) +{ + unsigned narenas; + size_t active, allocated, mapped, page, pdirty; + size_t lg_chunk; + + // Refresh jemalloc's stats by updating its epoch, see ctl_refresh in + // src/ctl.c + uint64_t epoch = 0; + size_t esz = sizeof(epoch); + je_(mallctl)("epoch", &epoch, &esz, &epoch, esz); + + CTL_GET("arenas.narenas", narenas); + CTL_GET("arenas.page", page); + CTL_GET("stats.active", active); + CTL_GET("stats.allocated", allocated); + CTL_GET("stats.mapped", mapped); + CTL_GET("opt.lg_chunk", lg_chunk); + + /* get the summation for all arenas, i == narenas */ + CTL_I_GET("stats.arenas.0.pdirty", pdirty, narenas); + + stats->chunksize = (size_t) 1 << lg_chunk; + stats->mapped = mapped; + stats->allocated = allocated; + stats->waste = active - allocated; + stats->page_cache = pdirty * page; + compute_bin_unused_and_bookkeeping(stats, narenas); + stats->waste -= stats->bin_unused; +} + +MOZ_JEMALLOC_API void +jemalloc_purge_freed_pages_impl() +{ +} + +MOZ_JEMALLOC_API void +jemalloc_free_dirty_pages_impl() +{ + unsigned narenas; + size_t mib[3]; + size_t miblen = sizeof(mib) / sizeof(mib[0]); + + CTL_GET("arenas.narenas", narenas); + je_(mallctlnametomib)("arena.0.purge", mib, &miblen); + mib[1] = narenas; + je_(mallctlbymib)(mib, miblen, NULL, NULL, NULL, 0); +} |