Bug 899126 - Part 1: Implement bin_unused for jemalloc3. r=glandium
authorGuilherme Goncalves <guilherme.p.gonc@gmail.com>
Fri, 19 Dec 2014 09:15:00 -0500
changeset 237918 82c158c0c951a6b551051b5f2b553a4b495e2fd8
parent 237917 3be1869800235c69da20bb58b14eaf924308457b
child 237919 efcdd91cef75abd86375da7d7cd5d61c44917ad4
push id7472
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 20:36:27 +0000
treeherdermozilla-aurora@300ca104f8fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs899126
milestone37.0a1
Bug 899126 - Part 1: Implement bin_unused for jemalloc3. r=glandium
memory/build/mozjemalloc_compat.c
--- a/memory/build/mozjemalloc_compat.c
+++ b/memory/build/mozjemalloc_compat.c
@@ -5,18 +5,21 @@
 #ifndef MOZ_JEMALLOC3
 #  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 "jemalloc/internal/jemalloc_internal_defs.h" // for JEMALLOC_HAS_ALLOCA_H
 #include "mozilla/Types.h"
 
+#include <stdbool.h>
+
 #if defined(MOZ_NATIVE_JEMALLOC)
 
 MOZ_IMPORT_API int
 je_(mallctl)(const char*, void*, size_t*, void*, size_t);
 MOZ_IMPORT_API int
 je_(mallctlnametomib)(const char *name, size_t *mibp, size_t *miblenp);
 MOZ_IMPORT_API int
 je_(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
@@ -42,27 +45,98 @@ je_(nallocx)(size_t size, int flags);
 	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 JEMALLOC_HAS_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 size_t
+compute_bin_unused(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;
+
+    // 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;
+        }
+    }
+
+    return 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
@@ -85,17 +159,18 @@ jemalloc_stats_impl(jemalloc_stats_t *st
   stats->mapped = mapped;
   stats->allocated = allocated;
   stats->waste = active - allocated;
   stats->page_cache = pdirty * page;
 
   // We could get this value out of base.c::base_pages, but that really should
   // be an upstream change, so don't worry about it for now.
   stats->bookkeeping = 0;
-  stats->bin_unused = 0;
+
+  stats->bin_unused = compute_bin_unused(narenas);
 }
 
 MOZ_JEMALLOC_API void
 jemalloc_purge_freed_pages_impl()
 {
 }
 
 MOZ_JEMALLOC_API void