123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 js_MemoryMetrics_h
- #define js_MemoryMetrics_h
- // These declarations are highly likely to change in the future. Depend on them
- // at your own risk.
- #include "mozilla/MemoryReporting.h"
- #include "mozilla/TypeTraits.h"
- #include <string.h>
- #include "jsalloc.h"
- #include "jspubtd.h"
- #include "js/HashTable.h"
- #include "js/TracingAPI.h"
- #include "js/Utility.h"
- #include "js/Vector.h"
- class nsISupports; // Needed for ObjectPrivateVisitor.
- namespace JS {
- struct TabSizes
- {
- enum Kind {
- Objects,
- Strings,
- Private,
- Other
- };
- TabSizes()
- : objects(0)
- , strings(0)
- , private_(0)
- , other(0)
- {
- }
- void add(Kind kind, size_t n) {
- switch (kind) {
- case Objects: objects += n; break;
- case Strings: strings += n; break;
- case Private: private_ += n; break;
- case Other: other += n; break;
- default: MOZ_CRASH("bad TabSizes kind");
- }
- }
- size_t objects;
- size_t strings;
- size_t private_;
- size_t other;
- };
- /** These are the measurements used by Servo. */
- struct ServoSizes
- {
- enum Kind {
- GCHeapUsed,
- GCHeapUnused,
- GCHeapAdmin,
- GCHeapDecommitted,
- MallocHeap,
- NonHeap,
- Ignore
- };
- ServoSizes() = default;
- void add(Kind kind, size_t n) {
- switch (kind) {
- case GCHeapUsed: gcHeapUsed += n; break;
- case GCHeapUnused: gcHeapUnused += n; break;
- case GCHeapAdmin: gcHeapAdmin += n; break;
- case GCHeapDecommitted: gcHeapDecommitted += n; break;
- case MallocHeap: mallocHeap += n; break;
- case NonHeap: nonHeap += n; break;
- case Ignore: /* do nothing */ break;
- default: MOZ_CRASH("bad ServoSizes kind");
- }
- }
- size_t gcHeapUsed = 0;
- size_t gcHeapUnused = 0;
- size_t gcHeapAdmin = 0;
- size_t gcHeapDecommitted = 0;
- size_t mallocHeap = 0;
- size_t nonHeap = 0;
- };
- } // namespace JS
- namespace js {
- /**
- * In memory reporting, we have concept of "sundries", line items which are too
- * small to be worth reporting individually. Under some circumstances, a memory
- * reporter gets tossed into the sundries bucket if it's smaller than
- * MemoryReportingSundriesThreshold() bytes.
- *
- * We need to define this value here, rather than in the code which actually
- * generates the memory reports, because NotableStringInfo uses this value.
- */
- JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
- /**
- * This hash policy avoids flattening ropes (which perturbs the site being
- * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
- * on every hash and match! Beware.
- */
- struct InefficientNonFlatteningStringHashPolicy
- {
- typedef JSString* Lookup;
- static HashNumber hash(const Lookup& l);
- static bool match(const JSString* const& k, const Lookup& l);
- };
- struct CStringHashPolicy
- {
- typedef const char* Lookup;
- static HashNumber hash(const Lookup& l);
- static bool match(const char* const& k, const Lookup& l);
- };
- // This file features many classes with numerous size_t fields, and each such
- // class has one or more methods that need to operate on all of these fields.
- // Writing these individually is error-prone -- it's easy to add a new field
- // without updating all the required methods. So we define a single macro list
- // in each class to name the fields (and notable characteristics of them), and
- // then use the following macros to transform those lists into the required
- // methods.
- //
- // - The |tabKind| value is used when measuring TabSizes.
- //
- // - The |servoKind| value is used when measuring ServoSizes and also for
- // the various sizeOfLiveGCThings() methods.
- //
- // In some classes, one or more of the macro arguments aren't used. We use '_'
- // for those.
- //
- #define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize;
- #define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0),
- #define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize),
- #define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
- #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
- MOZ_ASSERT(mSize >= other.mSize); \
- mSize -= other.mSize;
- #define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
- #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
- /* Avoid self-comparison warnings by comparing enums indirectly. */ \
- n += (mozilla::IsSame<int[ServoSizes::servoKind], int[ServoSizes::GCHeapUsed]>::value) \
- ? mSize \
- : 0;
- #define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize);
- #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize);
- } // namespace js
- namespace JS {
- struct ClassInfo
- {
- #define FOR_EACH_SIZE(macro) \
- macro(Objects, GCHeapUsed, objectsGCHeap) \
- macro(Objects, MallocHeap, objectsMallocHeapSlots) \
- macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
- macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
- macro(Objects, MallocHeap, objectsMallocHeapMisc) \
- macro(Objects, NonHeap, objectsNonHeapElementsNormal) \
- macro(Objects, NonHeap, objectsNonHeapElementsShared) \
- macro(Objects, NonHeap, objectsNonHeapElementsWasm) \
- macro(Objects, NonHeap, objectsNonHeapCodeWasm)
- ClassInfo()
- : FOR_EACH_SIZE(ZERO_SIZE)
- wasmGuardPages(0)
- {}
- void add(const ClassInfo& other) {
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- }
- void subtract(const ClassInfo& other) {
- FOR_EACH_SIZE(SUB_OTHER_SIZE)
- }
- size_t sizeOfAllThings() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N)
- return n;
- }
- bool isNotable() const {
- static const size_t NotabilityThreshold = 16 * 1024;
- return sizeOfAllThings() >= NotabilityThreshold;
- }
- size_t sizeOfLiveGCThings() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
- return n;
- }
- void addToTabSizes(TabSizes* sizes) const {
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
- }
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- size_t wasmGuardPages;
- #undef FOR_EACH_SIZE
- };
- struct ShapeInfo
- {
- #define FOR_EACH_SIZE(macro) \
- macro(Other, GCHeapUsed, shapesGCHeapTree) \
- macro(Other, GCHeapUsed, shapesGCHeapDict) \
- macro(Other, GCHeapUsed, shapesGCHeapBase) \
- macro(Other, MallocHeap, shapesMallocHeapTreeTables) \
- macro(Other, MallocHeap, shapesMallocHeapDictTables) \
- macro(Other, MallocHeap, shapesMallocHeapTreeKids)
- ShapeInfo()
- : FOR_EACH_SIZE(ZERO_SIZE)
- dummy()
- {}
- void add(const ShapeInfo& other) {
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- }
- void subtract(const ShapeInfo& other) {
- FOR_EACH_SIZE(SUB_OTHER_SIZE)
- }
- size_t sizeOfAllThings() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N)
- return n;
- }
- size_t sizeOfLiveGCThings() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
- return n;
- }
- void addToTabSizes(TabSizes* sizes) const {
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
- }
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
- #undef FOR_EACH_SIZE
- };
- /**
- * Holds data about a notable class (one whose combined object and shape
- * instances use more than a certain amount of memory) so we can report it
- * individually.
- *
- * The only difference between this class and ClassInfo is that this class
- * holds a copy of the filename.
- */
- struct NotableClassInfo : public ClassInfo
- {
- NotableClassInfo();
- NotableClassInfo(const char* className, const ClassInfo& info);
- NotableClassInfo(NotableClassInfo&& info);
- NotableClassInfo& operator=(NotableClassInfo&& info);
- ~NotableClassInfo() {
- js_free(className_);
- }
- char* className_;
- private:
- NotableClassInfo(const NotableClassInfo& info) = delete;
- };
- /** Data for tracking JIT-code memory usage. */
- struct CodeSizes
- {
- #define FOR_EACH_SIZE(macro) \
- macro(_, NonHeap, ion) \
- macro(_, NonHeap, baseline) \
- macro(_, NonHeap, regexp) \
- macro(_, NonHeap, other) \
- macro(_, NonHeap, unused)
- CodeSizes()
- : FOR_EACH_SIZE(ZERO_SIZE)
- dummy()
- {}
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
- #undef FOR_EACH_SIZE
- };
- /** Data for tracking GC memory usage. */
- struct GCSizes
- {
- // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
- // because we don't consider the nursery to be part of the GC heap.
- #define FOR_EACH_SIZE(macro) \
- macro(_, MallocHeap, marker) \
- macro(_, NonHeap, nurseryCommitted) \
- macro(_, MallocHeap, nurseryMallocedBuffers) \
- macro(_, MallocHeap, storeBufferVals) \
- macro(_, MallocHeap, storeBufferCells) \
- macro(_, MallocHeap, storeBufferSlots) \
- macro(_, MallocHeap, storeBufferWholeCells) \
- macro(_, MallocHeap, storeBufferGenerics)
- GCSizes()
- : FOR_EACH_SIZE(ZERO_SIZE)
- dummy()
- {}
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
- #undef FOR_EACH_SIZE
- };
- /**
- * This class holds information about the memory taken up by identical copies of
- * a particular string. Multiple JSStrings may have their sizes aggregated
- * together into one StringInfo object. Note that two strings with identical
- * chars will not be aggregated together if one is a short string and the other
- * is not.
- */
- struct StringInfo
- {
- #define FOR_EACH_SIZE(macro) \
- macro(Strings, GCHeapUsed, gcHeapLatin1) \
- macro(Strings, GCHeapUsed, gcHeapTwoByte) \
- macro(Strings, MallocHeap, mallocHeapLatin1) \
- macro(Strings, MallocHeap, mallocHeapTwoByte)
- StringInfo()
- : FOR_EACH_SIZE(ZERO_SIZE)
- numCopies(0)
- {}
- void add(const StringInfo& other) {
- FOR_EACH_SIZE(ADD_OTHER_SIZE);
- numCopies++;
- }
- void subtract(const StringInfo& other) {
- FOR_EACH_SIZE(SUB_OTHER_SIZE);
- numCopies--;
- }
- bool isNotable() const {
- static const size_t NotabilityThreshold = 16 * 1024;
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N)
- return n >= NotabilityThreshold;
- }
- size_t sizeOfLiveGCThings() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
- return n;
- }
- void addToTabSizes(TabSizes* sizes) const {
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
- }
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- uint32_t numCopies; // How many copies of the string have we seen?
- #undef FOR_EACH_SIZE
- };
- /**
- * Holds data about a notable string (one which, counting all duplicates, uses
- * more than a certain amount of memory) so we can report it individually.
- *
- * The only difference between this class and StringInfo is that
- * NotableStringInfo holds a copy of some or all of the string's chars.
- */
- struct NotableStringInfo : public StringInfo
- {
- static const size_t MAX_SAVED_CHARS = 1024;
- NotableStringInfo();
- NotableStringInfo(JSString* str, const StringInfo& info);
- NotableStringInfo(NotableStringInfo&& info);
- NotableStringInfo& operator=(NotableStringInfo&& info);
- ~NotableStringInfo() {
- js_free(buffer);
- }
- char* buffer;
- size_t length;
- private:
- NotableStringInfo(const NotableStringInfo& info) = delete;
- };
- /**
- * This class holds information about the memory taken up by script sources
- * from a particular file.
- */
- struct ScriptSourceInfo
- {
- #define FOR_EACH_SIZE(macro) \
- macro(_, MallocHeap, misc)
- ScriptSourceInfo()
- : FOR_EACH_SIZE(ZERO_SIZE)
- numScripts(0)
- {}
- void add(const ScriptSourceInfo& other) {
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- numScripts++;
- }
- void subtract(const ScriptSourceInfo& other) {
- FOR_EACH_SIZE(SUB_OTHER_SIZE)
- numScripts--;
- }
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- bool isNotable() const {
- static const size_t NotabilityThreshold = 16 * 1024;
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N)
- return n >= NotabilityThreshold;
- }
- FOR_EACH_SIZE(DECL_SIZE)
- uint32_t numScripts; // How many ScriptSources come from this file? (It
- // can be more than one in XML files that have
- // multiple scripts in CDATA sections.)
- #undef FOR_EACH_SIZE
- };
- /**
- * Holds data about a notable script source file (one whose combined
- * script sources use more than a certain amount of memory) so we can report it
- * individually.
- *
- * The only difference between this class and ScriptSourceInfo is that this
- * class holds a copy of the filename.
- */
- struct NotableScriptSourceInfo : public ScriptSourceInfo
- {
- NotableScriptSourceInfo();
- NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info);
- NotableScriptSourceInfo(NotableScriptSourceInfo&& info);
- NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info);
- ~NotableScriptSourceInfo() {
- js_free(filename_);
- }
- char* filename_;
- private:
- NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete;
- };
- /**
- * These measurements relate directly to the JSRuntime, and not to zones and
- * compartments within it.
- */
- struct RuntimeSizes
- {
- #define FOR_EACH_SIZE(macro) \
- macro(_, MallocHeap, object) \
- macro(_, MallocHeap, atomsTable) \
- macro(_, MallocHeap, contexts) \
- macro(_, MallocHeap, temporary) \
- macro(_, MallocHeap, interpreterStack) \
- macro(_, MallocHeap, mathCache) \
- macro(_, MallocHeap, sharedImmutableStringsCache) \
- macro(_, MallocHeap, sharedIntlData) \
- macro(_, MallocHeap, uncompressedSourceCache) \
- macro(_, MallocHeap, scriptData)
- RuntimeSizes()
- : FOR_EACH_SIZE(ZERO_SIZE)
- scriptSourceInfo(),
- code(),
- gc(),
- notableScriptSources()
- {
- allScriptSources = js_new<ScriptSourcesHashMap>();
- if (!allScriptSources || !allScriptSources->init())
- MOZ_CRASH("oom");
- }
- ~RuntimeSizes() {
- // |allScriptSources| is usually deleted and set to nullptr before this
- // destructor runs. But there are failure cases due to OOMs that may
- // prevent that, so it doesn't hurt to try again here.
- js_delete(allScriptSources);
- }
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- scriptSourceInfo.addToServoSizes(sizes);
- code.addToServoSizes(sizes);
- gc.addToServoSizes(sizes);
- }
- // The script source measurements in |scriptSourceInfo| are initially for
- // all script sources. At the end, if the measurement granularity is
- // FineGrained, we subtract the measurements of the notable script sources
- // and move them into |notableScriptSources|.
- FOR_EACH_SIZE(DECL_SIZE)
- ScriptSourceInfo scriptSourceInfo;
- CodeSizes code;
- GCSizes gc;
- typedef js::HashMap<const char*, ScriptSourceInfo,
- js::CStringHashPolicy,
- js::SystemAllocPolicy> ScriptSourcesHashMap;
- // |allScriptSources| is only used transiently. During the reporting phase
- // it is filled with info about every script source in the runtime. It's
- // then used to fill in |notableScriptSources| (which actually gets
- // reported), and immediately discarded afterwards.
- ScriptSourcesHashMap* allScriptSources;
- js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> notableScriptSources;
- #undef FOR_EACH_SIZE
- };
- struct UnusedGCThingSizes
- {
- #define FOR_EACH_SIZE(macro) \
- macro(Other, GCHeapUnused, object) \
- macro(Other, GCHeapUnused, script) \
- macro(Other, GCHeapUnused, lazyScript) \
- macro(Other, GCHeapUnused, shape) \
- macro(Other, GCHeapUnused, baseShape) \
- macro(Other, GCHeapUnused, objectGroup) \
- macro(Other, GCHeapUnused, string) \
- macro(Other, GCHeapUnused, symbol) \
- macro(Other, GCHeapUnused, jitcode) \
- macro(Other, GCHeapUnused, scope)
- UnusedGCThingSizes()
- : FOR_EACH_SIZE(ZERO_SIZE)
- dummy()
- {}
- UnusedGCThingSizes(UnusedGCThingSizes&& other)
- : FOR_EACH_SIZE(COPY_OTHER_SIZE)
- dummy()
- {}
- void addToKind(JS::TraceKind kind, intptr_t n) {
- switch (kind) {
- case JS::TraceKind::Object: object += n; break;
- case JS::TraceKind::String: string += n; break;
- case JS::TraceKind::Symbol: symbol += n; break;
- case JS::TraceKind::Script: script += n; break;
- case JS::TraceKind::Shape: shape += n; break;
- case JS::TraceKind::BaseShape: baseShape += n; break;
- case JS::TraceKind::JitCode: jitcode += n; break;
- case JS::TraceKind::LazyScript: lazyScript += n; break;
- case JS::TraceKind::ObjectGroup: objectGroup += n; break;
- case JS::TraceKind::Scope: scope += n; break;
- default:
- MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
- }
- }
- void addSizes(const UnusedGCThingSizes& other) {
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- }
- size_t totalSize() const {
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N)
- return n;
- }
- void addToTabSizes(JS::TabSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
- }
- void addToServoSizes(JS::ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- }
- FOR_EACH_SIZE(DECL_SIZE)
- int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
- #undef FOR_EACH_SIZE
- };
- struct ZoneStats
- {
- #define FOR_EACH_SIZE(macro) \
- macro(Other, GCHeapUsed, symbolsGCHeap) \
- macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \
- macro(Other, GCHeapUsed, lazyScriptsGCHeap) \
- macro(Other, MallocHeap, lazyScriptsMallocHeap) \
- macro(Other, GCHeapUsed, jitCodesGCHeap) \
- macro(Other, GCHeapUsed, objectGroupsGCHeap) \
- macro(Other, MallocHeap, objectGroupsMallocHeap) \
- macro(Other, GCHeapUsed, scopesGCHeap) \
- macro(Other, MallocHeap, scopesMallocHeap) \
- macro(Other, MallocHeap, typePool) \
- macro(Other, MallocHeap, baselineStubsOptimized) \
- macro(Other, MallocHeap, uniqueIdMap) \
- macro(Other, MallocHeap, shapeTables)
- ZoneStats()
- : FOR_EACH_SIZE(ZERO_SIZE)
- unusedGCThings(),
- stringInfo(),
- shapeInfo(),
- extra(),
- allStrings(nullptr),
- notableStrings(),
- isTotals(true)
- {}
- ZoneStats(ZoneStats&& other)
- : FOR_EACH_SIZE(COPY_OTHER_SIZE)
- unusedGCThings(mozilla::Move(other.unusedGCThings)),
- stringInfo(mozilla::Move(other.stringInfo)),
- shapeInfo(mozilla::Move(other.shapeInfo)),
- extra(other.extra),
- allStrings(other.allStrings),
- notableStrings(mozilla::Move(other.notableStrings)),
- isTotals(other.isTotals)
- {
- other.allStrings = nullptr;
- MOZ_ASSERT(!other.isTotals);
- }
- ~ZoneStats() {
- // |allStrings| is usually deleted and set to nullptr before this
- // destructor runs. But there are failure cases due to OOMs that may
- // prevent that, so it doesn't hurt to try again here.
- js_delete(allStrings);
- }
- bool initStrings(JSRuntime* rt);
- void addSizes(const ZoneStats& other) {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- unusedGCThings.addSizes(other.unusedGCThings);
- stringInfo.add(other.stringInfo);
- shapeInfo.add(other.shapeInfo);
- }
- size_t sizeOfLiveGCThings() const {
- MOZ_ASSERT(isTotals);
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
- n += stringInfo.sizeOfLiveGCThings();
- n += shapeInfo.sizeOfLiveGCThings();
- return n;
- }
- void addToTabSizes(JS::TabSizes* sizes) const {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
- unusedGCThings.addToTabSizes(sizes);
- stringInfo.addToTabSizes(sizes);
- shapeInfo.addToTabSizes(sizes);
- }
- void addToServoSizes(JS::ServoSizes *sizes) const {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- unusedGCThings.addToServoSizes(sizes);
- stringInfo.addToServoSizes(sizes);
- shapeInfo.addToServoSizes(sizes);
- }
- // These string measurements are initially for all strings. At the end,
- // if the measurement granularity is FineGrained, we subtract the
- // measurements of the notable script sources and move them into
- // |notableStrings|.
- FOR_EACH_SIZE(DECL_SIZE)
- UnusedGCThingSizes unusedGCThings;
- StringInfo stringInfo;
- ShapeInfo shapeInfo;
- void* extra; // This field can be used by embedders.
- typedef js::HashMap<JSString*, StringInfo,
- js::InefficientNonFlatteningStringHashPolicy,
- js::SystemAllocPolicy> StringsHashMap;
- // |allStrings| is only used transiently. During the zone traversal it is
- // filled with info about every string in the zone. It's then used to fill
- // in |notableStrings| (which actually gets reported), and immediately
- // discarded afterwards.
- StringsHashMap* allStrings;
- js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
- bool isTotals;
- #undef FOR_EACH_SIZE
- };
- struct CompartmentStats
- {
- // We assume that |objectsPrivate| is on the malloc heap, but it's not
- // actually guaranteed. But for Servo, at least, it's a moot point because
- // it doesn't provide an ObjectPrivateVisitor so the value will always be
- // zero.
- #define FOR_EACH_SIZE(macro) \
- macro(Private, MallocHeap, objectsPrivate) \
- macro(Other, GCHeapUsed, scriptsGCHeap) \
- macro(Other, MallocHeap, scriptsMallocHeapData) \
- macro(Other, MallocHeap, baselineData) \
- macro(Other, MallocHeap, baselineStubsFallback) \
- macro(Other, MallocHeap, ionData) \
- macro(Other, MallocHeap, typeInferenceTypeScripts) \
- macro(Other, MallocHeap, typeInferenceAllocationSiteTables) \
- macro(Other, MallocHeap, typeInferenceArrayTypeTables) \
- macro(Other, MallocHeap, typeInferenceObjectTypeTables) \
- macro(Other, MallocHeap, compartmentObject) \
- macro(Other, MallocHeap, compartmentTables) \
- macro(Other, MallocHeap, innerViewsTable) \
- macro(Other, MallocHeap, lazyArrayBuffersTable) \
- macro(Other, MallocHeap, objectMetadataTable) \
- macro(Other, MallocHeap, crossCompartmentWrappersTable) \
- macro(Other, MallocHeap, regexpCompartment) \
- macro(Other, MallocHeap, savedStacksSet) \
- macro(Other, MallocHeap, varNamesSet) \
- macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
- macro(Other, MallocHeap, jitCompartment) \
- macro(Other, MallocHeap, privateData)
- CompartmentStats()
- : FOR_EACH_SIZE(ZERO_SIZE)
- classInfo(),
- extra(),
- allClasses(nullptr),
- notableClasses(),
- isTotals(true)
- {}
- CompartmentStats(CompartmentStats&& other)
- : FOR_EACH_SIZE(COPY_OTHER_SIZE)
- classInfo(mozilla::Move(other.classInfo)),
- extra(other.extra),
- allClasses(other.allClasses),
- notableClasses(mozilla::Move(other.notableClasses)),
- isTotals(other.isTotals)
- {
- other.allClasses = nullptr;
- MOZ_ASSERT(!other.isTotals);
- }
- CompartmentStats(const CompartmentStats&) = delete; // disallow copying
- ~CompartmentStats() {
- // |allClasses| is usually deleted and set to nullptr before this
- // destructor runs. But there are failure cases due to OOMs that may
- // prevent that, so it doesn't hurt to try again here.
- js_delete(allClasses);
- }
- bool initClasses(JSRuntime* rt);
- void addSizes(const CompartmentStats& other) {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_OTHER_SIZE)
- classInfo.add(other.classInfo);
- }
- size_t sizeOfLiveGCThings() const {
- MOZ_ASSERT(isTotals);
- size_t n = 0;
- FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
- n += classInfo.sizeOfLiveGCThings();
- return n;
- }
- void addToTabSizes(TabSizes* sizes) const {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
- classInfo.addToTabSizes(sizes);
- }
- void addToServoSizes(ServoSizes *sizes) const {
- MOZ_ASSERT(isTotals);
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
- classInfo.addToServoSizes(sizes);
- }
- // The class measurements in |classInfo| are initially for all classes. At
- // the end, if the measurement granularity is FineGrained, we subtract the
- // measurements of the notable classes and move them into |notableClasses|.
- FOR_EACH_SIZE(DECL_SIZE)
- ClassInfo classInfo;
- void* extra; // This field can be used by embedders.
- typedef js::HashMap<const char*, ClassInfo,
- js::CStringHashPolicy,
- js::SystemAllocPolicy> ClassesHashMap;
- // These are similar to |allStrings| and |notableStrings| in ZoneStats.
- ClassesHashMap* allClasses;
- js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses;
- bool isTotals;
- #undef FOR_EACH_SIZE
- };
- typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
- typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
- struct RuntimeStats
- {
- // |gcHeapChunkTotal| is ignored because it's the sum of all the other
- // values. |gcHeapGCThings| is ignored because it's the sum of some of the
- // values from the zones and compartments. Both of those values are not
- // reported directly, but are just present for sanity-checking other
- // values.
- #define FOR_EACH_SIZE(macro) \
- macro(_, Ignore, gcHeapChunkTotal) \
- macro(_, GCHeapDecommitted, gcHeapDecommittedArenas) \
- macro(_, GCHeapUnused, gcHeapUnusedChunks) \
- macro(_, GCHeapUnused, gcHeapUnusedArenas) \
- macro(_, GCHeapAdmin, gcHeapChunkAdmin) \
- macro(_, Ignore, gcHeapGCThings)
- explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
- : FOR_EACH_SIZE(ZERO_SIZE)
- runtime(),
- cTotals(),
- zTotals(),
- compartmentStatsVector(),
- zoneStatsVector(),
- currZoneStats(nullptr),
- mallocSizeOf_(mallocSizeOf)
- {}
- // Here's a useful breakdown of the GC heap.
- //
- // - rtStats.gcHeapChunkTotal
- // - decommitted bytes
- // - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks)
- // - unused bytes
- // - rtStats.gcHeapUnusedChunks (empty chunks)
- // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
- // - rtStats.zTotals.unusedGCThings.totalSize() (empty GC thing slots within non-empty arenas)
- // - used bytes
- // - rtStats.gcHeapChunkAdmin
- // - rtStats.zTotals.gcHeapArenaAdmin
- // - rtStats.gcHeapGCThings (in-use GC things)
- // == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings()
- //
- // It's possible that some arenas in empty chunks may be decommitted, but
- // we don't count those under rtStats.gcHeapDecommittedArenas because (a)
- // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
- // multiple of the chunk size, which is good.
- void addToServoSizes(ServoSizes *sizes) const {
- FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
- runtime.addToServoSizes(sizes);
- }
- FOR_EACH_SIZE(DECL_SIZE)
- RuntimeSizes runtime;
- CompartmentStats cTotals; // The sum of this runtime's compartments' measurements.
- ZoneStats zTotals; // The sum of this runtime's zones' measurements.
- CompartmentStatsVector compartmentStatsVector;
- ZoneStatsVector zoneStatsVector;
- ZoneStats* currZoneStats;
- mozilla::MallocSizeOf mallocSizeOf_;
- virtual void initExtraCompartmentStats(JSCompartment* c, CompartmentStats* cstats) = 0;
- virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0;
- #undef FOR_EACH_SIZE
- };
- class ObjectPrivateVisitor
- {
- public:
- // Within CollectRuntimeStats, this method is called for each JS object
- // that has an nsISupports pointer.
- virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0;
- // A callback that gets a JSObject's nsISupports pointer, if it has one.
- // Note: this function does *not* addref |iface|.
- typedef bool(*GetISupportsFun)(JSObject* obj, nsISupports** iface);
- GetISupportsFun getISupports_;
- explicit ObjectPrivateVisitor(GetISupportsFun getISupports)
- : getISupports_(getISupports)
- {}
- };
- extern JS_PUBLIC_API(bool)
- CollectRuntimeStats(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv, bool anonymize);
- extern JS_PUBLIC_API(size_t)
- SystemCompartmentCount(JSContext* cx);
- extern JS_PUBLIC_API(size_t)
- UserCompartmentCount(JSContext* cx);
- extern JS_PUBLIC_API(size_t)
- PeakSizeOfTemporary(const JSContext* cx);
- extern JS_PUBLIC_API(bool)
- AddSizeOfTab(JSContext* cx, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
- ObjectPrivateVisitor* opv, TabSizes* sizes);
- extern JS_PUBLIC_API(bool)
- AddServoSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf,
- ObjectPrivateVisitor *opv, ServoSizes *sizes);
- } // namespace JS
- #undef DECL_SIZE
- #undef ZERO_SIZE
- #undef COPY_OTHER_SIZE
- #undef ADD_OTHER_SIZE
- #undef SUB_OTHER_SIZE
- #undef ADD_SIZE_TO_N
- #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
- #undef ADD_TO_TAB_SIZES
- #endif /* js_MemoryMetrics_h */
|