js/public/MemoryMetrics.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/public/MemoryMetrics.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,665 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef js_MemoryMetrics_h
    1.11 +#define js_MemoryMetrics_h
    1.12 +
    1.13 +// These declarations are highly likely to change in the future. Depend on them
    1.14 +// at your own risk.
    1.15 +
    1.16 +#include "mozilla/MemoryReporting.h"
    1.17 +#include "mozilla/NullPtr.h"
    1.18 +#include "mozilla/PodOperations.h"
    1.19 +
    1.20 +#include <string.h>
    1.21 +
    1.22 +#include "jsalloc.h"
    1.23 +#include "jspubtd.h"
    1.24 +
    1.25 +#include "js/HashTable.h"
    1.26 +#include "js/Utility.h"
    1.27 +#include "js/Vector.h"
    1.28 +
    1.29 +class nsISupports;      // Needed for ObjectPrivateVisitor.
    1.30 +
    1.31 +namespace JS {
    1.32 +
    1.33 +struct TabSizes
    1.34 +{
    1.35 +    enum Kind {
    1.36 +        Objects,
    1.37 +        Strings,
    1.38 +        Private,
    1.39 +        Other
    1.40 +    };
    1.41 +
    1.42 +    TabSizes() { mozilla::PodZero(this); }
    1.43 +
    1.44 +    void add(Kind kind, size_t n) {
    1.45 +        switch (kind) {
    1.46 +            case Objects: objects  += n; break;
    1.47 +            case Strings: strings  += n; break;
    1.48 +            case Private: private_ += n; break;
    1.49 +            case Other:   other    += n; break;
    1.50 +            default:      MOZ_CRASH("bad TabSizes kind");
    1.51 +        }
    1.52 +    }
    1.53 +
    1.54 +    size_t objects;
    1.55 +    size_t strings;
    1.56 +    size_t private_;
    1.57 +    size_t other;
    1.58 +};
    1.59 +
    1.60 +} // namespace JS
    1.61 +
    1.62 +namespace js {
    1.63 +
    1.64 +// In memory reporting, we have concept of "sundries", line items which are too
    1.65 +// small to be worth reporting individually.  Under some circumstances, a memory
    1.66 +// reporter gets tossed into the sundries bucket if it's smaller than
    1.67 +// MemoryReportingSundriesThreshold() bytes.
    1.68 +//
    1.69 +// We need to define this value here, rather than in the code which actually
    1.70 +// generates the memory reports, because NotableStringInfo uses this value.
    1.71 +JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
    1.72 +
    1.73 +// This hash policy avoids flattening ropes (which perturbs the site being
    1.74 +// measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
    1.75 +// on every hash and match! Beware.
    1.76 +struct InefficientNonFlatteningStringHashPolicy
    1.77 +{
    1.78 +    typedef JSString *Lookup;
    1.79 +    static HashNumber hash(const Lookup &l);
    1.80 +    static bool match(const JSString *const &k, const Lookup &l);
    1.81 +};
    1.82 +
    1.83 +struct CStringHashPolicy
    1.84 +{
    1.85 +    typedef const char *Lookup;
    1.86 +    static HashNumber hash(const Lookup &l);
    1.87 +    static bool match(const char *const &k, const Lookup &l);
    1.88 +};
    1.89 +
    1.90 +// This file features many classes with numerous size_t fields, and each such
    1.91 +// class has one or more methods that need to operate on all of these fields.
    1.92 +// Writing these individually is error-prone -- it's easy to add a new field
    1.93 +// without updating all the required methods.  So we define a single macro list
    1.94 +// in each class to name the fields (and notable characteristics of them), and
    1.95 +// then use the following macros to transform those lists into the required
    1.96 +// methods.
    1.97 +//
    1.98 +// In some classes, one or more of the macro arguments aren't used.  We use '_'
    1.99 +// for those.
   1.100 +//
   1.101 +#define DECL_SIZE(kind, gc, mSize)                      size_t mSize;
   1.102 +#define ZERO_SIZE(kind, gc, mSize)                      mSize(0),
   1.103 +#define COPY_OTHER_SIZE(kind, gc, mSize)                mSize(other.mSize),
   1.104 +#define ADD_OTHER_SIZE(kind, gc, mSize)                 mSize += other.mSize;
   1.105 +#define SUB_OTHER_SIZE(kind, gc, mSize)                 MOZ_ASSERT(mSize >= other.mSize); \
   1.106 +                                                        mSize -= other.mSize;
   1.107 +#define ADD_SIZE_TO_N(kind, gc, mSize)                  n += mSize;
   1.108 +#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc) ? mSize : 0;
   1.109 +#define ADD_TO_TAB_SIZES(kind, gc, mSize)               sizes->add(JS::TabSizes::kind, mSize);
   1.110 +
   1.111 +// Used to annotate which size_t fields measure live GC things and which don't.
   1.112 +enum {
   1.113 +    NotLiveGCThing = false,
   1.114 +    IsLiveGCThing = true
   1.115 +};
   1.116 +
   1.117 +} // namespace js
   1.118 +
   1.119 +namespace JS {
   1.120 +
   1.121 +// Data for tracking memory usage of things hanging off objects.
   1.122 +struct ObjectsExtraSizes
   1.123 +{
   1.124 +#define FOR_EACH_SIZE(macro) \
   1.125 +    macro(Objects, NotLiveGCThing, mallocHeapSlots) \
   1.126 +    macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
   1.127 +    macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
   1.128 +    macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
   1.129 +    macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
   1.130 +    macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
   1.131 +    macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
   1.132 +    macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
   1.133 +    macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
   1.134 +    macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
   1.135 +    macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
   1.136 +
   1.137 +    ObjectsExtraSizes()
   1.138 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.139 +        dummy()
   1.140 +    {}
   1.141 +
   1.142 +    void add(const ObjectsExtraSizes &other) {
   1.143 +        FOR_EACH_SIZE(ADD_OTHER_SIZE)
   1.144 +    }
   1.145 +
   1.146 +    size_t sizeOfLiveGCThings() const {
   1.147 +        size_t n = 0;
   1.148 +        FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
   1.149 +        return n;
   1.150 +    }
   1.151 +
   1.152 +    void addToTabSizes(TabSizes *sizes) const {
   1.153 +        FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
   1.154 +    }
   1.155 +
   1.156 +    FOR_EACH_SIZE(DECL_SIZE)
   1.157 +    int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
   1.158 +
   1.159 +#undef FOR_EACH_SIZE
   1.160 +};
   1.161 +
   1.162 +// Data for tracking JIT-code memory usage.
   1.163 +struct CodeSizes
   1.164 +{
   1.165 +#define FOR_EACH_SIZE(macro) \
   1.166 +    macro(_, _, ion) \
   1.167 +    macro(_, _, baseline) \
   1.168 +    macro(_, _, regexp) \
   1.169 +    macro(_, _, other) \
   1.170 +    macro(_, _, unused)
   1.171 +
   1.172 +    CodeSizes()
   1.173 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.174 +        dummy()
   1.175 +    {}
   1.176 +
   1.177 +    FOR_EACH_SIZE(DECL_SIZE)
   1.178 +    int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
   1.179 +
   1.180 +#undef FOR_EACH_SIZE
   1.181 +};
   1.182 +
   1.183 +// Data for tracking GC memory usage.
   1.184 +struct GCSizes
   1.185 +{
   1.186 +#define FOR_EACH_SIZE(macro) \
   1.187 +    macro(_, _, marker) \
   1.188 +    macro(_, _, nurseryCommitted) \
   1.189 +    macro(_, _, nurseryDecommitted) \
   1.190 +    macro(_, _, nurseryHugeSlots) \
   1.191 +    macro(_, _, storeBufferVals) \
   1.192 +    macro(_, _, storeBufferCells) \
   1.193 +    macro(_, _, storeBufferSlots) \
   1.194 +    macro(_, _, storeBufferWholeCells) \
   1.195 +    macro(_, _, storeBufferRelocVals) \
   1.196 +    macro(_, _, storeBufferRelocCells) \
   1.197 +    macro(_, _, storeBufferGenerics)
   1.198 +
   1.199 +    GCSizes()
   1.200 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.201 +        dummy()
   1.202 +    {}
   1.203 +
   1.204 +    FOR_EACH_SIZE(DECL_SIZE)
   1.205 +    int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
   1.206 +
   1.207 +#undef FOR_EACH_SIZE
   1.208 +};
   1.209 +
   1.210 +// This class holds information about the memory taken up by identical copies of
   1.211 +// a particular string.  Multiple JSStrings may have their sizes aggregated
   1.212 +// together into one StringInfo object.  Note that two strings with identical
   1.213 +// chars will not be aggregated together if one is a short string and the other
   1.214 +// is not.
   1.215 +struct StringInfo
   1.216 +{
   1.217 +#define FOR_EACH_SIZE(macro) \
   1.218 +    macro(Strings, IsLiveGCThing,  gcHeap) \
   1.219 +    macro(Strings, NotLiveGCThing, mallocHeap) \
   1.220 +
   1.221 +    StringInfo()
   1.222 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.223 +        numCopies(0)
   1.224 +    {}
   1.225 +
   1.226 +    void add(const StringInfo &other) {
   1.227 +        FOR_EACH_SIZE(ADD_OTHER_SIZE);
   1.228 +        numCopies++;
   1.229 +    }
   1.230 +
   1.231 +    void subtract(const StringInfo &other) {
   1.232 +        FOR_EACH_SIZE(SUB_OTHER_SIZE);
   1.233 +        numCopies--;
   1.234 +    }
   1.235 +
   1.236 +    bool isNotable() const {
   1.237 +        static const size_t NotabilityThreshold = 16 * 1024;
   1.238 +        size_t n = 0;
   1.239 +        FOR_EACH_SIZE(ADD_SIZE_TO_N)
   1.240 +        return n >= NotabilityThreshold;
   1.241 +    }
   1.242 +
   1.243 +    size_t sizeOfLiveGCThings() const {
   1.244 +        size_t n = 0;
   1.245 +        FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
   1.246 +        return n;
   1.247 +    }
   1.248 +
   1.249 +    void addToTabSizes(TabSizes *sizes) const {
   1.250 +        FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
   1.251 +    }
   1.252 +
   1.253 +    FOR_EACH_SIZE(DECL_SIZE)
   1.254 +    uint32_t numCopies;     // How many copies of the string have we seen?
   1.255 +
   1.256 +#undef FOR_EACH_SIZE
   1.257 +};
   1.258 +
   1.259 +// Holds data about a notable string (one which, counting all duplicates, uses
   1.260 +// more than a certain amount of memory) so we can report it individually.
   1.261 +//
   1.262 +// The only difference between this class and StringInfo is that
   1.263 +// NotableStringInfo holds a copy of some or all of the string's chars.
   1.264 +struct NotableStringInfo : public StringInfo
   1.265 +{
   1.266 +    static const size_t MAX_SAVED_CHARS = 1024;
   1.267 +
   1.268 +    NotableStringInfo();
   1.269 +    NotableStringInfo(JSString *str, const StringInfo &info);
   1.270 +    NotableStringInfo(NotableStringInfo &&info);
   1.271 +    NotableStringInfo &operator=(NotableStringInfo &&info);
   1.272 +
   1.273 +    ~NotableStringInfo() {
   1.274 +        js_free(buffer);
   1.275 +    }
   1.276 +
   1.277 +    char *buffer;
   1.278 +    size_t length;
   1.279 +
   1.280 +  private:
   1.281 +    NotableStringInfo(const NotableStringInfo& info) MOZ_DELETE;
   1.282 +};
   1.283 +
   1.284 +// This class holds information about the memory taken up by script sources
   1.285 +// from a particular file.
   1.286 +struct ScriptSourceInfo
   1.287 +{
   1.288 +#define FOR_EACH_SIZE(macro) \
   1.289 +    macro(_, _, compressed) \
   1.290 +    macro(_, _, uncompressed) \
   1.291 +    macro(_, _, misc)
   1.292 +
   1.293 +    ScriptSourceInfo()
   1.294 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.295 +        numScripts(0)
   1.296 +    {}
   1.297 +
   1.298 +    void add(const ScriptSourceInfo &other) {
   1.299 +        FOR_EACH_SIZE(ADD_OTHER_SIZE)
   1.300 +        numScripts++;
   1.301 +    }
   1.302 +
   1.303 +    void subtract(const ScriptSourceInfo &other) {
   1.304 +        FOR_EACH_SIZE(SUB_OTHER_SIZE)
   1.305 +        numScripts--;
   1.306 +    }
   1.307 +
   1.308 +    bool isNotable() const {
   1.309 +        static const size_t NotabilityThreshold = 16 * 1024;
   1.310 +        size_t n = 0;
   1.311 +        FOR_EACH_SIZE(ADD_SIZE_TO_N)
   1.312 +        return n >= NotabilityThreshold;
   1.313 +    }
   1.314 +
   1.315 +    FOR_EACH_SIZE(DECL_SIZE)
   1.316 +    uint32_t numScripts;    // How many ScriptSources come from this file? (It
   1.317 +                            // can be more than one in XML files that have
   1.318 +                            // multiple scripts in CDATA sections.)
   1.319 +#undef FOR_EACH_SIZE
   1.320 +};
   1.321 +
   1.322 +// Holds data about a notable script source file (one whose combined
   1.323 +// script sources use more than a certain amount of memory) so we can report it
   1.324 +// individually.
   1.325 +//
   1.326 +// The only difference between this class and ScriptSourceInfo is that this
   1.327 +// class holds a copy of the filename.
   1.328 +struct NotableScriptSourceInfo : public ScriptSourceInfo
   1.329 +{
   1.330 +    NotableScriptSourceInfo();
   1.331 +    NotableScriptSourceInfo(const char *filename, const ScriptSourceInfo &info);
   1.332 +    NotableScriptSourceInfo(NotableScriptSourceInfo &&info);
   1.333 +    NotableScriptSourceInfo &operator=(NotableScriptSourceInfo &&info);
   1.334 +
   1.335 +    ~NotableScriptSourceInfo() {
   1.336 +        js_free(filename_);
   1.337 +    }
   1.338 +
   1.339 +    char *filename_;
   1.340 +
   1.341 +  private:
   1.342 +    NotableScriptSourceInfo(const NotableScriptSourceInfo& info) MOZ_DELETE;
   1.343 +};
   1.344 +
   1.345 +// These measurements relate directly to the JSRuntime, and not to zones and
   1.346 +// compartments within it.
   1.347 +struct RuntimeSizes
   1.348 +{
   1.349 +#define FOR_EACH_SIZE(macro) \
   1.350 +    macro(_, _, object) \
   1.351 +    macro(_, _, atomsTable) \
   1.352 +    macro(_, _, contexts) \
   1.353 +    macro(_, _, dtoa) \
   1.354 +    macro(_, _, temporary) \
   1.355 +    macro(_, _, regexpData) \
   1.356 +    macro(_, _, interpreterStack) \
   1.357 +    macro(_, _, mathCache) \
   1.358 +    macro(_, _, sourceDataCache) \
   1.359 +    macro(_, _, scriptData) \
   1.360 +
   1.361 +    RuntimeSizes()
   1.362 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.363 +        scriptSourceInfo(),
   1.364 +        code(),
   1.365 +        gc(),
   1.366 +        notableScriptSources()
   1.367 +    {
   1.368 +        allScriptSources = js_new<ScriptSourcesHashMap>();
   1.369 +        if (!allScriptSources || !allScriptSources->init())
   1.370 +            MOZ_CRASH("oom");
   1.371 +    }
   1.372 +
   1.373 +    ~RuntimeSizes() {
   1.374 +        // |allScriptSources| is usually deleted and set to nullptr before this
   1.375 +        // destructor runs. But there are failure cases due to OOMs that may
   1.376 +        // prevent that, so it doesn't hurt to try again here.
   1.377 +        js_delete(allScriptSources);
   1.378 +    }
   1.379 +
   1.380 +    // The script source measurements in |scriptSourceInfo| are initially for
   1.381 +    // all script sources.  At the end, if the measurement granularity is
   1.382 +    // FineGrained, we subtract the measurements of the notable script sources
   1.383 +    // and move them into |notableScriptSources|.
   1.384 +    FOR_EACH_SIZE(DECL_SIZE)
   1.385 +    ScriptSourceInfo    scriptSourceInfo;
   1.386 +    CodeSizes           code;
   1.387 +    GCSizes             gc;
   1.388 +
   1.389 +    typedef js::HashMap<const char*, ScriptSourceInfo,
   1.390 +                        js::CStringHashPolicy,
   1.391 +                        js::SystemAllocPolicy> ScriptSourcesHashMap;
   1.392 +
   1.393 +    // |allScriptSources| is only used transiently.  During the reporting phase
   1.394 +    // it is filled with info about every script source in the runtime.  It's
   1.395 +    // then used to fill in |notableScriptSources| (which actually gets
   1.396 +    // reported), and immediately discarded afterwards.
   1.397 +    ScriptSourcesHashMap *allScriptSources;
   1.398 +    js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> notableScriptSources;
   1.399 +
   1.400 +#undef FOR_EACH_SIZE
   1.401 +};
   1.402 +
   1.403 +struct ZoneStats
   1.404 +{
   1.405 +#define FOR_EACH_SIZE(macro) \
   1.406 +    macro(Other,   NotLiveGCThing, gcHeapArenaAdmin) \
   1.407 +    macro(Other,   NotLiveGCThing, unusedGCThings) \
   1.408 +    macro(Other,   IsLiveGCThing,  lazyScriptsGCHeap) \
   1.409 +    macro(Other,   NotLiveGCThing, lazyScriptsMallocHeap) \
   1.410 +    macro(Other,   IsLiveGCThing,  jitCodesGCHeap) \
   1.411 +    macro(Other,   IsLiveGCThing,  typeObjectsGCHeap) \
   1.412 +    macro(Other,   NotLiveGCThing, typeObjectsMallocHeap) \
   1.413 +    macro(Other,   NotLiveGCThing, typePool) \
   1.414 +    macro(Other,   NotLiveGCThing, baselineStubsOptimized) \
   1.415 +
   1.416 +    ZoneStats()
   1.417 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.418 +        stringInfo(),
   1.419 +        extra(),
   1.420 +        allStrings(nullptr),
   1.421 +        notableStrings(),
   1.422 +        isTotals(true)
   1.423 +    {}
   1.424 +
   1.425 +    ZoneStats(ZoneStats &&other)
   1.426 +      : FOR_EACH_SIZE(COPY_OTHER_SIZE)
   1.427 +        stringInfo(mozilla::Move(other.stringInfo)),
   1.428 +        extra(other.extra),
   1.429 +        allStrings(other.allStrings),
   1.430 +        notableStrings(mozilla::Move(other.notableStrings)),
   1.431 +        isTotals(other.isTotals)
   1.432 +    {
   1.433 +        other.allStrings = nullptr;
   1.434 +        MOZ_ASSERT(!other.isTotals);
   1.435 +    }
   1.436 +
   1.437 +    ~ZoneStats() {
   1.438 +        // |allStrings| is usually deleted and set to nullptr before this
   1.439 +        // destructor runs. But there are failure cases due to OOMs that may
   1.440 +        // prevent that, so it doesn't hurt to try again here.
   1.441 +        js_delete(allStrings);
   1.442 +    }
   1.443 +
   1.444 +    bool initStrings(JSRuntime *rt);
   1.445 +
   1.446 +    void addSizes(const ZoneStats &other) {
   1.447 +        MOZ_ASSERT(isTotals);
   1.448 +        FOR_EACH_SIZE(ADD_OTHER_SIZE)
   1.449 +        stringInfo.add(other.stringInfo);
   1.450 +    }
   1.451 +
   1.452 +    size_t sizeOfLiveGCThings() const {
   1.453 +        MOZ_ASSERT(isTotals);
   1.454 +        size_t n = 0;
   1.455 +        FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
   1.456 +        n += stringInfo.sizeOfLiveGCThings();
   1.457 +        return n;
   1.458 +    }
   1.459 +
   1.460 +    void addToTabSizes(JS::TabSizes *sizes) const {
   1.461 +        MOZ_ASSERT(isTotals);
   1.462 +        FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
   1.463 +        stringInfo.addToTabSizes(sizes);
   1.464 +    }
   1.465 +
   1.466 +    // These string measurements are initially for all strings.  At the end,
   1.467 +    // if the measurement granularity is FineGrained, we subtract the
   1.468 +    // measurements of the notable script sources and move them into
   1.469 +    // |notableStrings|.
   1.470 +    FOR_EACH_SIZE(DECL_SIZE)
   1.471 +    StringInfo stringInfo;
   1.472 +    void *extra;    // This field can be used by embedders.
   1.473 +
   1.474 +    typedef js::HashMap<JSString*, StringInfo,
   1.475 +                        js::InefficientNonFlatteningStringHashPolicy,
   1.476 +                        js::SystemAllocPolicy> StringsHashMap;
   1.477 +
   1.478 +    // |allStrings| is only used transiently.  During the zone traversal it is
   1.479 +    // filled with info about every string in the zone.  It's then used to fill
   1.480 +    // in |notableStrings| (which actually gets reported), and immediately
   1.481 +    // discarded afterwards.
   1.482 +    StringsHashMap *allStrings;
   1.483 +    js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
   1.484 +    bool isTotals;
   1.485 +
   1.486 +#undef FOR_EACH_SIZE
   1.487 +};
   1.488 +
   1.489 +struct CompartmentStats
   1.490 +{
   1.491 +#define FOR_EACH_SIZE(macro) \
   1.492 +    macro(Objects, IsLiveGCThing,  objectsGCHeapOrdinary) \
   1.493 +    macro(Objects, IsLiveGCThing,  objectsGCHeapFunction) \
   1.494 +    macro(Objects, IsLiveGCThing,  objectsGCHeapDenseArray) \
   1.495 +    macro(Objects, IsLiveGCThing,  objectsGCHeapSlowArray) \
   1.496 +    macro(Objects, IsLiveGCThing,  objectsGCHeapCrossCompartmentWrapper) \
   1.497 +    macro(Private, NotLiveGCThing, objectsPrivate) \
   1.498 +    macro(Other,   IsLiveGCThing,  shapesGCHeapTreeGlobalParented) \
   1.499 +    macro(Other,   IsLiveGCThing,  shapesGCHeapTreeNonGlobalParented) \
   1.500 +    macro(Other,   IsLiveGCThing,  shapesGCHeapDict) \
   1.501 +    macro(Other,   IsLiveGCThing,  shapesGCHeapBase) \
   1.502 +    macro(Other,   NotLiveGCThing, shapesMallocHeapTreeTables) \
   1.503 +    macro(Other,   NotLiveGCThing, shapesMallocHeapDictTables) \
   1.504 +    macro(Other,   NotLiveGCThing, shapesMallocHeapTreeShapeKids) \
   1.505 +    macro(Other,   NotLiveGCThing, shapesMallocHeapCompartmentTables) \
   1.506 +    macro(Other,   IsLiveGCThing,  scriptsGCHeap) \
   1.507 +    macro(Other,   NotLiveGCThing, scriptsMallocHeapData) \
   1.508 +    macro(Other,   NotLiveGCThing, baselineData) \
   1.509 +    macro(Other,   NotLiveGCThing, baselineStubsFallback) \
   1.510 +    macro(Other,   NotLiveGCThing, ionData) \
   1.511 +    macro(Other,   NotLiveGCThing, typeInferenceTypeScripts) \
   1.512 +    macro(Other,   NotLiveGCThing, typeInferenceAllocationSiteTables) \
   1.513 +    macro(Other,   NotLiveGCThing, typeInferenceArrayTypeTables) \
   1.514 +    macro(Other,   NotLiveGCThing, typeInferenceObjectTypeTables) \
   1.515 +    macro(Other,   NotLiveGCThing, compartmentObject) \
   1.516 +    macro(Other,   NotLiveGCThing, crossCompartmentWrappersTable) \
   1.517 +    macro(Other,   NotLiveGCThing, regexpCompartment) \
   1.518 +    macro(Other,   NotLiveGCThing, debuggeesSet) \
   1.519 +    macro(Other,   NotLiveGCThing, savedStacksSet)
   1.520 +
   1.521 +    CompartmentStats()
   1.522 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.523 +        objectsExtra(),
   1.524 +        extra()
   1.525 +    {}
   1.526 +
   1.527 +    CompartmentStats(const CompartmentStats &other)
   1.528 +      : FOR_EACH_SIZE(COPY_OTHER_SIZE)
   1.529 +        objectsExtra(other.objectsExtra),
   1.530 +        extra(other.extra)
   1.531 +    {}
   1.532 +
   1.533 +    void add(const CompartmentStats &other) {
   1.534 +        FOR_EACH_SIZE(ADD_OTHER_SIZE)
   1.535 +        objectsExtra.add(other.objectsExtra);
   1.536 +        // Do nothing with |extra|.
   1.537 +    }
   1.538 +
   1.539 +    size_t sizeOfLiveGCThings() const {
   1.540 +        size_t n = 0;
   1.541 +        FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
   1.542 +        n += objectsExtra.sizeOfLiveGCThings();
   1.543 +        // Do nothing with |extra|.
   1.544 +        return n;
   1.545 +    }
   1.546 +
   1.547 +    void addToTabSizes(TabSizes *sizes) const {
   1.548 +        FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
   1.549 +        objectsExtra.addToTabSizes(sizes);
   1.550 +        // Do nothing with |extra|.
   1.551 +    }
   1.552 +
   1.553 +    FOR_EACH_SIZE(DECL_SIZE)
   1.554 +    ObjectsExtraSizes  objectsExtra;
   1.555 +    void               *extra;  // This field can be used by embedders.
   1.556 +
   1.557 +#undef FOR_EACH_SIZE
   1.558 +};
   1.559 +
   1.560 +typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
   1.561 +typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
   1.562 +
   1.563 +struct RuntimeStats
   1.564 +{
   1.565 +#define FOR_EACH_SIZE(macro) \
   1.566 +    macro(_, _, gcHeapChunkTotal) \
   1.567 +    macro(_, _, gcHeapDecommittedArenas) \
   1.568 +    macro(_, _, gcHeapUnusedChunks) \
   1.569 +    macro(_, _, gcHeapUnusedArenas) \
   1.570 +    macro(_, _, gcHeapChunkAdmin) \
   1.571 +    macro(_, _, gcHeapGCThings) \
   1.572 +
   1.573 +    RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
   1.574 +      : FOR_EACH_SIZE(ZERO_SIZE)
   1.575 +        runtime(),
   1.576 +        cTotals(),
   1.577 +        zTotals(),
   1.578 +        compartmentStatsVector(),
   1.579 +        zoneStatsVector(),
   1.580 +        currZoneStats(nullptr),
   1.581 +        mallocSizeOf_(mallocSizeOf)
   1.582 +    {}
   1.583 +
   1.584 +    // Here's a useful breakdown of the GC heap.
   1.585 +    //
   1.586 +    // - rtStats.gcHeapChunkTotal
   1.587 +    //   - decommitted bytes
   1.588 +    //     - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks)
   1.589 +    //   - unused bytes
   1.590 +    //     - rtStats.gcHeapUnusedChunks (empty chunks)
   1.591 +    //     - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
   1.592 +    //     - rtStats.zTotals.unusedGCThings (empty GC thing slots within non-empty arenas)
   1.593 +    //   - used bytes
   1.594 +    //     - rtStats.gcHeapChunkAdmin
   1.595 +    //     - rtStats.zTotals.gcHeapArenaAdmin
   1.596 +    //     - rtStats.gcHeapGCThings (in-use GC things)
   1.597 +    //       == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings()
   1.598 +    //
   1.599 +    // It's possible that some arenas in empty chunks may be decommitted, but
   1.600 +    // we don't count those under rtStats.gcHeapDecommittedArenas because (a)
   1.601 +    // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
   1.602 +    // multiple of the chunk size, which is good.
   1.603 +
   1.604 +    FOR_EACH_SIZE(DECL_SIZE)
   1.605 +
   1.606 +    RuntimeSizes runtime;
   1.607 +
   1.608 +    CompartmentStats cTotals;   // The sum of this runtime's compartments' measurements.
   1.609 +    ZoneStats zTotals;          // The sum of this runtime's zones' measurements.
   1.610 +
   1.611 +    CompartmentStatsVector compartmentStatsVector;
   1.612 +    ZoneStatsVector zoneStatsVector;
   1.613 +
   1.614 +    ZoneStats *currZoneStats;
   1.615 +
   1.616 +    mozilla::MallocSizeOf mallocSizeOf_;
   1.617 +
   1.618 +    virtual void initExtraCompartmentStats(JSCompartment *c, CompartmentStats *cstats) = 0;
   1.619 +    virtual void initExtraZoneStats(JS::Zone *zone, ZoneStats *zstats) = 0;
   1.620 +
   1.621 +#undef FOR_EACH_SIZE
   1.622 +};
   1.623 +
   1.624 +class ObjectPrivateVisitor
   1.625 +{
   1.626 +  public:
   1.627 +    // Within CollectRuntimeStats, this method is called for each JS object
   1.628 +    // that has an nsISupports pointer.
   1.629 +    virtual size_t sizeOfIncludingThis(nsISupports *aSupports) = 0;
   1.630 +
   1.631 +    // A callback that gets a JSObject's nsISupports pointer, if it has one.
   1.632 +    // Note: this function does *not* addref |iface|.
   1.633 +    typedef bool(*GetISupportsFun)(JSObject *obj, nsISupports **iface);
   1.634 +    GetISupportsFun getISupports_;
   1.635 +
   1.636 +    ObjectPrivateVisitor(GetISupportsFun getISupports)
   1.637 +      : getISupports_(getISupports)
   1.638 +    {}
   1.639 +};
   1.640 +
   1.641 +extern JS_PUBLIC_API(bool)
   1.642 +CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv);
   1.643 +
   1.644 +extern JS_PUBLIC_API(size_t)
   1.645 +SystemCompartmentCount(JSRuntime *rt);
   1.646 +
   1.647 +extern JS_PUBLIC_API(size_t)
   1.648 +UserCompartmentCount(JSRuntime *rt);
   1.649 +
   1.650 +extern JS_PUBLIC_API(size_t)
   1.651 +PeakSizeOfTemporary(const JSRuntime *rt);
   1.652 +
   1.653 +extern JS_PUBLIC_API(bool)
   1.654 +AddSizeOfTab(JSRuntime *rt, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
   1.655 +             ObjectPrivateVisitor *opv, TabSizes *sizes);
   1.656 +
   1.657 +} // namespace JS
   1.658 +
   1.659 +#undef DECL_SIZE
   1.660 +#undef ZERO_SIZE
   1.661 +#undef COPY_OTHER_SIZE
   1.662 +#undef ADD_OTHER_SIZE
   1.663 +#undef SUB_OTHER_SIZE
   1.664 +#undef ADD_SIZE_TO_N
   1.665 +#undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
   1.666 +#undef ADD_TO_TAB_SIZES
   1.667 +
   1.668 +#endif /* js_MemoryMetrics_h */

mercurial