1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_MemoryMetrics_h
8 #define js_MemoryMetrics_h
10 // These declarations are highly likely to change in the future. Depend on them
13 #include "mozilla/Maybe.h"
14 #include "mozilla/MemoryReporting.h"
17 #include <type_traits>
21 #include "js/AllocPolicy.h"
22 #include "js/HashTable.h"
23 #include "js/TraceKind.h"
24 #include "js/TypeDecls.h"
25 #include "js/Utility.h"
26 #include "js/Vector.h"
28 class nsISupports
; // Needed for ObjectPrivateVisitor.
31 class SystemAllocPolicy
;
39 class JS_PUBLIC_API AutoRequireNoGC
;
44 enum Kind
{ Objects
, Strings
, Private
, Other
};
46 void add(Kind kind
, size_t n
) {
61 MOZ_CRASH("bad TabSizes kind");
71 /** These are the measurements used by Servo. */
73 ServoSizes() = default;
85 void add(Kind kind
, size_t n
) {
96 case GCHeapDecommitted
:
97 gcHeapDecommitted
+= n
;
105 case Ignore
: /* do nothing */
108 MOZ_CRASH("bad ServoSizes kind");
112 size_t gcHeapUsed
= 0;
113 size_t gcHeapUnused
= 0;
114 size_t gcHeapAdmin
= 0;
115 size_t gcHeapDecommitted
= 0;
116 size_t mallocHeap
= 0;
125 * In memory reporting, we have concept of "sundries", line items which are too
126 * small to be worth reporting individually. Under some circumstances, a memory
127 * reporter gets tossed into the sundries bucket if it's smaller than
128 * MemoryReportingSundriesThreshold() bytes.
130 * We need to define this value here, rather than in the code which actually
131 * generates the memory reports, because NotableStringInfo uses this value.
133 JS_PUBLIC_API
size_t MemoryReportingSundriesThreshold();
136 * This hash policy avoids flattening ropes (which perturbs the site being
137 * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
138 * on every hash and match! Beware.
140 struct InefficientNonFlatteningStringHashPolicy
{
141 typedef JSString
* Lookup
;
142 static HashNumber
hash(const Lookup
& l
);
143 static bool match(const JSString
* const& k
, const Lookup
& l
);
146 // This file features many classes with numerous size_t fields, and each such
147 // class has one or more methods that need to operate on all of these fields.
148 // Writing these individually is error-prone -- it's easy to add a new field
149 // without updating all the required methods. So we define a single macro list
150 // in each class to name the fields (and notable characteristics of them), and
151 // then use the following macros to transform those lists into the required
154 // - The |tabKind| value is used when measuring TabSizes.
156 // - The |servoKind| value is used when measuring ServoSizes and also for
157 // the various sizeOfLiveGCThings() methods.
159 // In some classes, one or more of the macro arguments aren't used. We use '_'
162 #define DECL_SIZE_ZERO(tabKind, servoKind, mSize) size_t mSize = 0;
163 #define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
164 #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
165 MOZ_ASSERT(mSize >= other.mSize); \
166 mSize -= other.mSize;
167 #define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
168 #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
169 /* Avoid self-comparison warnings by comparing enums indirectly. */ \
170 n += (std::is_same_v<int[ServoSizes::servoKind], \
171 int[ServoSizes::GCHeapUsed]>) \
174 #define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) \
175 sizes->add(JS::TabSizes::tabKind, mSize);
176 #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \
177 sizes->add(JS::ServoSizes::servoKind, mSize);
184 #define FOR_EACH_SIZE(MACRO) \
185 MACRO(Objects, GCHeapUsed, objectsGCHeap) \
186 MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
187 MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
188 MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
189 MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData) \
190 MACRO(Objects, MallocHeap, objectsMallocHeapGlobalVarNamesSet) \
191 MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
192 MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
193 MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
194 MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
195 MACRO(Objects, NonHeap, objectsNonHeapElementsWasmShared) \
196 MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
198 ClassInfo() = default;
200 void add(const ClassInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
202 void subtract(const ClassInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
204 size_t sizeOfAllThings() const {
206 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
210 bool isNotable() const {
211 static const size_t NotabilityThreshold
= 16 * 1024;
212 return sizeOfAllThings() >= NotabilityThreshold
;
215 size_t sizeOfLiveGCThings() const {
217 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
221 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
223 void addToServoSizes(ServoSizes
* sizes
) const {
224 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
227 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
233 #define FOR_EACH_SIZE(MACRO) \
234 MACRO(Other, GCHeapUsed, shapesGCHeapShared) \
235 MACRO(Other, GCHeapUsed, shapesGCHeapDict) \
236 MACRO(Other, GCHeapUsed, shapesGCHeapBase) \
237 MACRO(Other, MallocHeap, shapesMallocHeapCache)
239 ShapeInfo() = default;
241 void add(const ShapeInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
243 void subtract(const ShapeInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
245 size_t sizeOfAllThings() const {
247 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
251 size_t sizeOfLiveGCThings() const {
253 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
257 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
259 void addToServoSizes(ServoSizes
* sizes
) const {
260 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
263 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
269 * Holds data about a notable class (one whose combined object and shape
270 * instances use more than a certain amount of memory) so we can report it
273 * The only difference between this class and ClassInfo is that this class
274 * holds a copy of the filename.
276 struct NotableClassInfo
: public ClassInfo
{
277 NotableClassInfo() = default;
278 NotableClassInfo(NotableClassInfo
&&) = default;
279 NotableClassInfo(const NotableClassInfo
& info
) = delete;
281 NotableClassInfo(const char* className
, const ClassInfo
& info
);
283 UniqueChars className_
= nullptr;
286 /** Data for tracking JIT-code memory usage. */
288 #define FOR_EACH_SIZE(MACRO) \
289 MACRO(_, NonHeap, ion) \
290 MACRO(_, NonHeap, baseline) \
291 MACRO(_, NonHeap, regexp) \
292 MACRO(_, NonHeap, other) \
293 MACRO(_, NonHeap, unused)
295 CodeSizes() = default;
297 void addToServoSizes(ServoSizes
* sizes
) const {
298 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
301 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
306 /** Data for tracking GC memory usage. */
308 // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
309 // because we don't consider the nursery to be part of the GC heap.
310 #define FOR_EACH_SIZE(MACRO) \
311 MACRO(_, MallocHeap, marker) \
312 MACRO(_, NonHeap, nurseryCommitted) \
313 MACRO(_, MallocHeap, nurseryMallocedBuffers) \
314 MACRO(_, MallocHeap, nurseryMallocedBlockCache) \
315 MACRO(_, MallocHeap, nurseryTrailerBlockSets) \
316 MACRO(_, MallocHeap, storeBufferVals) \
317 MACRO(_, MallocHeap, storeBufferCells) \
318 MACRO(_, MallocHeap, storeBufferSlots) \
319 MACRO(_, MallocHeap, storeBufferWasmAnyRefs) \
320 MACRO(_, MallocHeap, storeBufferWholeCells) \
321 MACRO(_, MallocHeap, storeBufferGenerics)
325 void addToServoSizes(ServoSizes
* sizes
) const {
326 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
329 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
335 * This class holds information about the memory taken up by identical copies of
336 * a particular string. Multiple JSStrings may have their sizes aggregated
337 * together into one StringInfo object. Note that two strings with identical
338 * chars will not be aggregated together if one is a short string and the other
342 #define FOR_EACH_SIZE(MACRO) \
343 MACRO(Strings, GCHeapUsed, gcHeapLatin1) \
344 MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \
345 MACRO(Strings, MallocHeap, mallocHeapLatin1) \
346 MACRO(Strings, MallocHeap, mallocHeapTwoByte)
348 StringInfo() = default;
350 void add(const StringInfo
& other
) {
351 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
355 void subtract(const StringInfo
& other
) {
356 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
360 bool isNotable() const {
361 static const size_t NotabilityThreshold
= 16 * 1024;
363 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
364 return n
>= NotabilityThreshold
;
367 size_t sizeOfLiveGCThings() const {
369 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
373 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
375 void addToServoSizes(ServoSizes
* sizes
) const {
376 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
379 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
381 uint32_t numCopies
= 0; // How many copies of the string have we seen?
387 * Holds data about a notable string (one which, counting all duplicates, uses
388 * more than a certain amount of memory) so we can report it individually.
390 * The only difference between this class and StringInfo is that
391 * NotableStringInfo holds a copy of some or all of the string's chars.
393 struct NotableStringInfo
: public StringInfo
{
394 static const size_t MAX_SAVED_CHARS
= 1024;
396 NotableStringInfo() = default;
397 NotableStringInfo(NotableStringInfo
&&) = default;
398 NotableStringInfo(const NotableStringInfo
&) = delete;
400 NotableStringInfo(JSString
* str
, const StringInfo
& info
);
402 UniqueChars buffer
= nullptr;
407 * This class holds information about the memory taken up by script sources
408 * from a particular file.
410 struct ScriptSourceInfo
{
411 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc)
413 ScriptSourceInfo() = default;
415 void add(const ScriptSourceInfo
& other
) {
416 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
420 void subtract(const ScriptSourceInfo
& other
) {
421 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
425 void addToServoSizes(ServoSizes
* sizes
) const {
426 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
429 bool isNotable() const {
430 static const size_t NotabilityThreshold
= 16 * 1024;
432 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
433 return n
>= NotabilityThreshold
;
436 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
438 uint32_t numScripts
= 0; // How many ScriptSources come from this file? (It
439 // can be more than one in XML files that have
440 // multiple scripts in CDATA sections.)
445 * Holds data about a notable script source file (one whose combined
446 * script sources use more than a certain amount of memory) so we can report it
449 * The only difference between this class and ScriptSourceInfo is that this
450 * class holds a copy of the filename.
452 struct NotableScriptSourceInfo
: public ScriptSourceInfo
{
453 NotableScriptSourceInfo() = default;
454 NotableScriptSourceInfo(NotableScriptSourceInfo
&&) = default;
455 NotableScriptSourceInfo(const NotableScriptSourceInfo
&) = delete;
457 NotableScriptSourceInfo(const char* filename
, const ScriptSourceInfo
& info
);
459 UniqueChars filename_
= nullptr;
462 struct HelperThreadStats
{
463 #define FOR_EACH_SIZE(MACRO) \
464 MACRO(_, MallocHeap, stateData) \
465 MACRO(_, MallocHeap, ionCompileTask) \
466 MACRO(_, MallocHeap, wasmCompile) \
467 MACRO(_, MallocHeap, contexts)
469 HelperThreadStats() = default;
471 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
473 unsigned idleThreadCount
= 0;
474 unsigned activeThreadCount
= 0;
480 * Measurements that not associated with any individual runtime.
483 explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf
)
484 : mallocSizeOf_(mallocSizeOf
) {}
486 HelperThreadStats helperThread
;
488 mozilla::MallocSizeOf mallocSizeOf_
;
492 * These measurements relate directly to the JSRuntime, and not to zones,
493 * compartments, and realms within it.
495 struct RuntimeSizes
{
496 #define FOR_EACH_SIZE(MACRO) \
497 MACRO(_, MallocHeap, object) \
498 MACRO(_, MallocHeap, atomsTable) \
499 MACRO(_, MallocHeap, atomsMarkBitmaps) \
500 MACRO(_, MallocHeap, selfHostStencil) \
501 MACRO(_, MallocHeap, contexts) \
502 MACRO(_, MallocHeap, temporary) \
503 MACRO(_, MallocHeap, interpreterStack) \
504 MACRO(_, MallocHeap, sharedImmutableStringsCache) \
505 MACRO(_, MallocHeap, sharedIntlData) \
506 MACRO(_, MallocHeap, uncompressedSourceCache) \
507 MACRO(_, MallocHeap, scriptData) \
508 MACRO(_, MallocHeap, wasmRuntime) \
509 MACRO(_, Ignore, wasmGuardPages) \
510 MACRO(_, MallocHeap, jitLazyLink)
512 RuntimeSizes() { allScriptSources
.emplace(); }
514 void addToServoSizes(ServoSizes
* sizes
) const {
515 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
516 scriptSourceInfo
.addToServoSizes(sizes
);
517 gc
.addToServoSizes(sizes
);
520 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
522 // The script source measurements in |scriptSourceInfo| are initially for
523 // all script sources. At the end, if the measurement granularity is
524 // FineGrained, we subtract the measurements of the notable script sources
525 // and move them into |notableScriptSources|.
526 ScriptSourceInfo scriptSourceInfo
;
529 typedef js::HashMap
<const char*, ScriptSourceInfo
, mozilla::CStringHasher
,
530 js::SystemAllocPolicy
>
531 ScriptSourcesHashMap
;
533 // |allScriptSources| is only used transiently. During the reporting phase
534 // it is filled with info about every script source in the runtime. It's
535 // then used to fill in |notableScriptSources| (which actually gets
536 // reported), and immediately discarded afterwards.
537 mozilla::Maybe
<ScriptSourcesHashMap
> allScriptSources
;
538 js::Vector
<NotableScriptSourceInfo
, 0, js::SystemAllocPolicy
>
539 notableScriptSources
;
544 struct UnusedGCThingSizes
{
545 #define FOR_EACH_SIZE(MACRO) \
546 MACRO(Other, GCHeapUnused, object) \
547 MACRO(Other, GCHeapUnused, script) \
548 MACRO(Other, GCHeapUnused, shape) \
549 MACRO(Other, GCHeapUnused, baseShape) \
550 MACRO(Other, GCHeapUnused, getterSetter) \
551 MACRO(Other, GCHeapUnused, propMap) \
552 MACRO(Other, GCHeapUnused, string) \
553 MACRO(Other, GCHeapUnused, symbol) \
554 MACRO(Other, GCHeapUnused, bigInt) \
555 MACRO(Other, GCHeapUnused, jitcode) \
556 MACRO(Other, GCHeapUnused, scope) \
557 MACRO(Other, GCHeapUnused, regExpShared)
559 UnusedGCThingSizes() = default;
560 UnusedGCThingSizes(UnusedGCThingSizes
&& other
) = default;
562 void addToKind(JS::TraceKind kind
, intptr_t n
) {
564 case JS::TraceKind::Object
:
567 case JS::TraceKind::String
:
570 case JS::TraceKind::Symbol
:
573 case JS::TraceKind::BigInt
:
576 case JS::TraceKind::Script
:
579 case JS::TraceKind::Shape
:
582 case JS::TraceKind::BaseShape
:
585 case JS::TraceKind::GetterSetter
:
588 case JS::TraceKind::PropMap
:
591 case JS::TraceKind::JitCode
:
594 case JS::TraceKind::Scope
:
597 case JS::TraceKind::RegExpShared
:
601 MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
605 void addSizes(const UnusedGCThingSizes
& other
) {
606 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
609 size_t totalSize() const {
611 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
615 void addToTabSizes(JS::TabSizes
* sizes
) const {
616 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
619 void addToServoSizes(JS::ServoSizes
* sizes
) const {
620 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
623 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
629 #define FOR_EACH_SIZE(MACRO) \
630 MACRO(Other, GCHeapUsed, symbolsGCHeap) \
631 MACRO(Other, GCHeapUsed, bigIntsGCHeap) \
632 MACRO(Other, MallocHeap, bigIntsMallocHeap) \
633 MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \
634 MACRO(Other, GCHeapUsed, jitCodesGCHeap) \
635 MACRO(Other, GCHeapUsed, getterSettersGCHeap) \
636 MACRO(Other, GCHeapUsed, compactPropMapsGCHeap) \
637 MACRO(Other, GCHeapUsed, normalPropMapsGCHeap) \
638 MACRO(Other, GCHeapUsed, dictPropMapsGCHeap) \
639 MACRO(Other, MallocHeap, propMapChildren) \
640 MACRO(Other, MallocHeap, propMapTables) \
641 MACRO(Other, GCHeapUsed, scopesGCHeap) \
642 MACRO(Other, MallocHeap, scopesMallocHeap) \
643 MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
644 MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
645 MACRO(Other, MallocHeap, zoneObject) \
646 MACRO(Other, MallocHeap, regexpZone) \
647 MACRO(Other, MallocHeap, jitZone) \
648 MACRO(Other, MallocHeap, cacheIRStubs) \
649 MACRO(Other, MallocHeap, uniqueIdMap) \
650 MACRO(Other, MallocHeap, initialPropMapTable) \
651 MACRO(Other, MallocHeap, shapeTables) \
652 MACRO(Other, MallocHeap, compartmentObjects) \
653 MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
654 MACRO(Other, MallocHeap, compartmentsPrivateData) \
655 MACRO(Other, MallocHeap, scriptCountsMap)
657 ZoneStats() = default;
658 ZoneStats(ZoneStats
&& other
) = default;
662 void addSizes(const ZoneStats
& other
) {
663 MOZ_ASSERT(isTotals
);
664 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
665 unusedGCThings
.addSizes(other
.unusedGCThings
);
666 stringInfo
.add(other
.stringInfo
);
667 shapeInfo
.add(other
.shapeInfo
);
670 size_t sizeOfLiveGCThings() const {
671 MOZ_ASSERT(isTotals
);
673 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
674 n
+= stringInfo
.sizeOfLiveGCThings();
675 n
+= shapeInfo
.sizeOfLiveGCThings();
679 void addToTabSizes(JS::TabSizes
* sizes
) const {
680 MOZ_ASSERT(isTotals
);
681 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
682 unusedGCThings
.addToTabSizes(sizes
);
683 stringInfo
.addToTabSizes(sizes
);
684 shapeInfo
.addToTabSizes(sizes
);
687 void addToServoSizes(JS::ServoSizes
* sizes
) const {
688 MOZ_ASSERT(isTotals
);
689 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
690 unusedGCThings
.addToServoSizes(sizes
);
691 stringInfo
.addToServoSizes(sizes
);
692 shapeInfo
.addToServoSizes(sizes
);
693 code
.addToServoSizes(sizes
);
696 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
698 // These string measurements are initially for all strings. At the end,
699 // if the measurement granularity is FineGrained, we subtract the
700 // measurements of the notable script sources and move them into
702 UnusedGCThingSizes unusedGCThings
;
703 StringInfo stringInfo
;
706 void* extra
= nullptr; // This field can be used by embedders.
708 typedef js::HashMap
<JSString
*, StringInfo
,
709 js::InefficientNonFlatteningStringHashPolicy
,
710 js::SystemAllocPolicy
>
713 // |allStrings| is only used transiently. During the zone traversal it is
714 // filled with info about every string in the zone. It's then used to fill
715 // in |notableStrings| (which actually gets reported), and immediately
716 // discarded afterwards.
717 mozilla::Maybe
<StringsHashMap
> allStrings
;
718 js::Vector
<NotableStringInfo
, 0, js::SystemAllocPolicy
> notableStrings
;
719 bool isTotals
= true;
725 // We assume that |objectsPrivate| is on the malloc heap, but it's not
726 // actually guaranteed. But for Servo, at least, it's a moot point because
727 // it doesn't provide an ObjectPrivateVisitor so the value will always be
729 #define FOR_EACH_SIZE(MACRO) \
730 MACRO(Private, MallocHeap, objectsPrivate) \
731 MACRO(Other, GCHeapUsed, scriptsGCHeap) \
732 MACRO(Other, MallocHeap, scriptsMallocHeapData) \
733 MACRO(Other, MallocHeap, baselineData) \
734 MACRO(Other, MallocHeap, allocSites) \
735 MACRO(Other, MallocHeap, ionData) \
736 MACRO(Other, MallocHeap, jitScripts) \
737 MACRO(Other, MallocHeap, realmObject) \
738 MACRO(Other, MallocHeap, realmTables) \
739 MACRO(Other, MallocHeap, innerViewsTable) \
740 MACRO(Other, MallocHeap, objectMetadataTable) \
741 MACRO(Other, MallocHeap, savedStacksSet) \
742 MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable)
744 RealmStats() = default;
745 RealmStats(RealmStats
&& other
) = default;
747 RealmStats(const RealmStats
&) = delete; // disallow copying
751 void addSizes(const RealmStats
& other
) {
752 MOZ_ASSERT(isTotals
);
753 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
754 classInfo
.add(other
.classInfo
);
757 size_t sizeOfLiveGCThings() const {
758 MOZ_ASSERT(isTotals
);
760 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
761 n
+= classInfo
.sizeOfLiveGCThings();
765 void addToTabSizes(TabSizes
* sizes
) const {
766 MOZ_ASSERT(isTotals
);
767 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
768 classInfo
.addToTabSizes(sizes
);
771 void addToServoSizes(ServoSizes
* sizes
) const {
772 MOZ_ASSERT(isTotals
);
773 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
774 classInfo
.addToServoSizes(sizes
);
777 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
779 // The class measurements in |classInfo| are initially for all classes. At
780 // the end, if the measurement granularity is FineGrained, we subtract the
781 // measurements of the notable classes and move them into |notableClasses|.
783 void* extra
= nullptr; // This field can be used by embedders.
785 typedef js::HashMap
<const char*, ClassInfo
, mozilla::CStringHasher
,
786 js::SystemAllocPolicy
>
789 // These are similar to |allStrings| and |notableStrings| in ZoneStats.
790 mozilla::Maybe
<ClassesHashMap
> allClasses
;
791 js::Vector
<NotableClassInfo
, 0, js::SystemAllocPolicy
> notableClasses
;
792 bool isTotals
= true;
797 typedef js::Vector
<RealmStats
, 0, js::SystemAllocPolicy
> RealmStatsVector
;
798 typedef js::Vector
<ZoneStats
, 0, js::SystemAllocPolicy
> ZoneStatsVector
;
800 struct RuntimeStats
{
801 // |gcHeapChunkTotal| is ignored because it's the sum of all the other
802 // values. |gcHeapGCThings| is ignored because it's the sum of some of the
803 // values from the zones and compartments. Both of those values are not
804 // reported directly, but are just present for sanity-checking other
806 #define FOR_EACH_SIZE(MACRO) \
807 MACRO(_, Ignore, gcHeapChunkTotal) \
808 MACRO(_, GCHeapDecommitted, gcHeapDecommittedPages) \
809 MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \
810 MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \
811 MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \
812 MACRO(_, Ignore, gcHeapGCThings)
814 explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf
)
815 : mallocSizeOf_(mallocSizeOf
) {}
817 // Here's a useful breakdown of the GC heap.
819 // - rtStats.gcHeapChunkTotal
820 // - decommitted bytes
821 // - rtStats.gcHeapDecommittedPages
822 // (decommitted pages in non-empty chunks)
824 // - rtStats.gcHeapUnusedChunks (empty chunks)
825 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
826 // - rtStats.zTotals.unusedGCThings.totalSize()
827 // (empty GC thing slots within non-empty arenas)
829 // - rtStats.gcHeapChunkAdmin
830 // - rtStats.zTotals.gcHeapArenaAdmin
831 // - rtStats.gcHeapGCThings (in-use GC things)
832 // == (rtStats.zTotals.sizeOfLiveGCThings() +
833 // rtStats.cTotals.sizeOfLiveGCThings())
835 // It's possible that some pages in empty chunks may be decommitted, but
836 // we don't count those under rtStats.gcHeapDecommittedPages because (a)
837 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
838 // multiple of the chunk size, which is good.
840 void addToServoSizes(ServoSizes
* sizes
) const {
841 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
842 runtime
.addToServoSizes(sizes
);
845 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
847 RuntimeSizes runtime
;
849 RealmStats realmTotals
; // The sum of this runtime's realms' measurements.
850 ZoneStats zTotals
; // The sum of this runtime's zones' measurements.
852 RealmStatsVector realmStatsVector
;
853 ZoneStatsVector zoneStatsVector
;
855 ZoneStats
* currZoneStats
= nullptr;
857 mozilla::MallocSizeOf mallocSizeOf_
;
859 virtual void initExtraRealmStats(JS::Realm
* realm
, RealmStats
* rstats
,
860 const JS::AutoRequireNoGC
& nogc
) = 0;
861 virtual void initExtraZoneStats(JS::Zone
* zone
, ZoneStats
* zstats
,
862 const JS::AutoRequireNoGC
& nogc
) = 0;
867 class ObjectPrivateVisitor
{
869 // Within CollectRuntimeStats, this method is called for each JS object
870 // that has an nsISupports pointer.
871 virtual size_t sizeOfIncludingThis(nsISupports
* aSupports
) = 0;
873 // A callback that gets a JSObject's nsISupports pointer, if it has one.
874 // Note: this function does *not* addref |iface|.
875 typedef bool (*GetISupportsFun
)(JSObject
* obj
, nsISupports
** iface
);
876 GetISupportsFun getISupports_
;
878 explicit ObjectPrivateVisitor(GetISupportsFun getISupports
)
879 : getISupports_(getISupports
) {}
882 extern JS_PUBLIC_API
bool CollectGlobalStats(GlobalStats
* gStats
);
884 extern JS_PUBLIC_API
bool CollectRuntimeStats(JSContext
* cx
,
885 RuntimeStats
* rtStats
,
886 ObjectPrivateVisitor
* opv
,
889 extern JS_PUBLIC_API
size_t SystemCompartmentCount(JSContext
* cx
);
890 extern JS_PUBLIC_API
size_t UserCompartmentCount(JSContext
* cx
);
892 extern JS_PUBLIC_API
size_t SystemRealmCount(JSContext
* cx
);
893 extern JS_PUBLIC_API
size_t UserRealmCount(JSContext
* cx
);
895 extern JS_PUBLIC_API
size_t PeakSizeOfTemporary(const JSContext
* cx
);
897 extern JS_PUBLIC_API
bool AddSizeOfTab(JSContext
* cx
, JS::HandleObject obj
,
898 mozilla::MallocSizeOf mallocSizeOf
,
899 ObjectPrivateVisitor
* opv
,
902 extern JS_PUBLIC_API
bool AddServoSizeOf(JSContext
* cx
,
903 mozilla::MallocSizeOf mallocSizeOf
,
904 ObjectPrivateVisitor
* opv
,
909 #undef DECL_SIZE_ZERO
910 #undef ADD_OTHER_SIZE
911 #undef SUB_OTHER_SIZE
913 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
914 #undef ADD_TO_TAB_SIZES
916 #endif /* js_MemoryMetrics_h */