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, regexpZone) \
646 MACRO(Other, MallocHeap, jitZone) \
647 MACRO(Other, MallocHeap, baselineStubsOptimized) \
648 MACRO(Other, MallocHeap, uniqueIdMap) \
649 MACRO(Other, MallocHeap, initialPropMapTable) \
650 MACRO(Other, MallocHeap, shapeTables) \
651 MACRO(Other, MallocHeap, compartmentObjects) \
652 MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
653 MACRO(Other, MallocHeap, compartmentsPrivateData) \
654 MACRO(Other, MallocHeap, scriptCountsMap)
656 ZoneStats() = default;
657 ZoneStats(ZoneStats
&& other
) = default;
661 void addSizes(const ZoneStats
& other
) {
662 MOZ_ASSERT(isTotals
);
663 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
664 unusedGCThings
.addSizes(other
.unusedGCThings
);
665 stringInfo
.add(other
.stringInfo
);
666 shapeInfo
.add(other
.shapeInfo
);
669 size_t sizeOfLiveGCThings() const {
670 MOZ_ASSERT(isTotals
);
672 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
673 n
+= stringInfo
.sizeOfLiveGCThings();
674 n
+= shapeInfo
.sizeOfLiveGCThings();
678 void addToTabSizes(JS::TabSizes
* sizes
) const {
679 MOZ_ASSERT(isTotals
);
680 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
681 unusedGCThings
.addToTabSizes(sizes
);
682 stringInfo
.addToTabSizes(sizes
);
683 shapeInfo
.addToTabSizes(sizes
);
686 void addToServoSizes(JS::ServoSizes
* sizes
) const {
687 MOZ_ASSERT(isTotals
);
688 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
689 unusedGCThings
.addToServoSizes(sizes
);
690 stringInfo
.addToServoSizes(sizes
);
691 shapeInfo
.addToServoSizes(sizes
);
692 code
.addToServoSizes(sizes
);
695 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
697 // These string measurements are initially for all strings. At the end,
698 // if the measurement granularity is FineGrained, we subtract the
699 // measurements of the notable script sources and move them into
701 UnusedGCThingSizes unusedGCThings
;
702 StringInfo stringInfo
;
705 void* extra
= nullptr; // This field can be used by embedders.
707 typedef js::HashMap
<JSString
*, StringInfo
,
708 js::InefficientNonFlatteningStringHashPolicy
,
709 js::SystemAllocPolicy
>
712 // |allStrings| is only used transiently. During the zone traversal it is
713 // filled with info about every string in the zone. It's then used to fill
714 // in |notableStrings| (which actually gets reported), and immediately
715 // discarded afterwards.
716 mozilla::Maybe
<StringsHashMap
> allStrings
;
717 js::Vector
<NotableStringInfo
, 0, js::SystemAllocPolicy
> notableStrings
;
718 bool isTotals
= true;
724 // We assume that |objectsPrivate| is on the malloc heap, but it's not
725 // actually guaranteed. But for Servo, at least, it's a moot point because
726 // it doesn't provide an ObjectPrivateVisitor so the value will always be
728 #define FOR_EACH_SIZE(MACRO) \
729 MACRO(Private, MallocHeap, objectsPrivate) \
730 MACRO(Other, GCHeapUsed, scriptsGCHeap) \
731 MACRO(Other, MallocHeap, scriptsMallocHeapData) \
732 MACRO(Other, MallocHeap, baselineData) \
733 MACRO(Other, MallocHeap, baselineStubsFallback) \
734 MACRO(Other, MallocHeap, ionData) \
735 MACRO(Other, MallocHeap, jitScripts) \
736 MACRO(Other, MallocHeap, realmObject) \
737 MACRO(Other, MallocHeap, realmTables) \
738 MACRO(Other, MallocHeap, innerViewsTable) \
739 MACRO(Other, MallocHeap, objectMetadataTable) \
740 MACRO(Other, MallocHeap, savedStacksSet) \
741 MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable)
743 RealmStats() = default;
744 RealmStats(RealmStats
&& other
) = default;
746 RealmStats(const RealmStats
&) = delete; // disallow copying
750 void addSizes(const RealmStats
& other
) {
751 MOZ_ASSERT(isTotals
);
752 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
753 classInfo
.add(other
.classInfo
);
756 size_t sizeOfLiveGCThings() const {
757 MOZ_ASSERT(isTotals
);
759 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
760 n
+= classInfo
.sizeOfLiveGCThings();
764 void addToTabSizes(TabSizes
* sizes
) const {
765 MOZ_ASSERT(isTotals
);
766 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
767 classInfo
.addToTabSizes(sizes
);
770 void addToServoSizes(ServoSizes
* sizes
) const {
771 MOZ_ASSERT(isTotals
);
772 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
773 classInfo
.addToServoSizes(sizes
);
776 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
778 // The class measurements in |classInfo| are initially for all classes. At
779 // the end, if the measurement granularity is FineGrained, we subtract the
780 // measurements of the notable classes and move them into |notableClasses|.
782 void* extra
= nullptr; // This field can be used by embedders.
784 typedef js::HashMap
<const char*, ClassInfo
, mozilla::CStringHasher
,
785 js::SystemAllocPolicy
>
788 // These are similar to |allStrings| and |notableStrings| in ZoneStats.
789 mozilla::Maybe
<ClassesHashMap
> allClasses
;
790 js::Vector
<NotableClassInfo
, 0, js::SystemAllocPolicy
> notableClasses
;
791 bool isTotals
= true;
796 typedef js::Vector
<RealmStats
, 0, js::SystemAllocPolicy
> RealmStatsVector
;
797 typedef js::Vector
<ZoneStats
, 0, js::SystemAllocPolicy
> ZoneStatsVector
;
799 struct RuntimeStats
{
800 // |gcHeapChunkTotal| is ignored because it's the sum of all the other
801 // values. |gcHeapGCThings| is ignored because it's the sum of some of the
802 // values from the zones and compartments. Both of those values are not
803 // reported directly, but are just present for sanity-checking other
805 #define FOR_EACH_SIZE(MACRO) \
806 MACRO(_, Ignore, gcHeapChunkTotal) \
807 MACRO(_, GCHeapDecommitted, gcHeapDecommittedPages) \
808 MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \
809 MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \
810 MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \
811 MACRO(_, Ignore, gcHeapGCThings)
813 explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf
)
814 : mallocSizeOf_(mallocSizeOf
) {}
816 // Here's a useful breakdown of the GC heap.
818 // - rtStats.gcHeapChunkTotal
819 // - decommitted bytes
820 // - rtStats.gcHeapDecommittedPages
821 // (decommitted pages in non-empty chunks)
823 // - rtStats.gcHeapUnusedChunks (empty chunks)
824 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
825 // - rtStats.zTotals.unusedGCThings.totalSize()
826 // (empty GC thing slots within non-empty arenas)
828 // - rtStats.gcHeapChunkAdmin
829 // - rtStats.zTotals.gcHeapArenaAdmin
830 // - rtStats.gcHeapGCThings (in-use GC things)
831 // == (rtStats.zTotals.sizeOfLiveGCThings() +
832 // rtStats.cTotals.sizeOfLiveGCThings())
834 // It's possible that some pages in empty chunks may be decommitted, but
835 // we don't count those under rtStats.gcHeapDecommittedPages because (a)
836 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
837 // multiple of the chunk size, which is good.
839 void addToServoSizes(ServoSizes
* sizes
) const {
840 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
841 runtime
.addToServoSizes(sizes
);
844 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
846 RuntimeSizes runtime
;
848 RealmStats realmTotals
; // The sum of this runtime's realms' measurements.
849 ZoneStats zTotals
; // The sum of this runtime's zones' measurements.
851 RealmStatsVector realmStatsVector
;
852 ZoneStatsVector zoneStatsVector
;
854 ZoneStats
* currZoneStats
= nullptr;
856 mozilla::MallocSizeOf mallocSizeOf_
;
858 virtual void initExtraRealmStats(JS::Realm
* realm
, RealmStats
* rstats
,
859 const JS::AutoRequireNoGC
& nogc
) = 0;
860 virtual void initExtraZoneStats(JS::Zone
* zone
, ZoneStats
* zstats
,
861 const JS::AutoRequireNoGC
& nogc
) = 0;
866 class ObjectPrivateVisitor
{
868 // Within CollectRuntimeStats, this method is called for each JS object
869 // that has an nsISupports pointer.
870 virtual size_t sizeOfIncludingThis(nsISupports
* aSupports
) = 0;
872 // A callback that gets a JSObject's nsISupports pointer, if it has one.
873 // Note: this function does *not* addref |iface|.
874 typedef bool (*GetISupportsFun
)(JSObject
* obj
, nsISupports
** iface
);
875 GetISupportsFun getISupports_
;
877 explicit ObjectPrivateVisitor(GetISupportsFun getISupports
)
878 : getISupports_(getISupports
) {}
881 extern JS_PUBLIC_API
bool CollectGlobalStats(GlobalStats
* gStats
);
883 extern JS_PUBLIC_API
bool CollectRuntimeStats(JSContext
* cx
,
884 RuntimeStats
* rtStats
,
885 ObjectPrivateVisitor
* opv
,
888 extern JS_PUBLIC_API
size_t SystemCompartmentCount(JSContext
* cx
);
889 extern JS_PUBLIC_API
size_t UserCompartmentCount(JSContext
* cx
);
891 extern JS_PUBLIC_API
size_t SystemRealmCount(JSContext
* cx
);
892 extern JS_PUBLIC_API
size_t UserRealmCount(JSContext
* cx
);
894 extern JS_PUBLIC_API
size_t PeakSizeOfTemporary(const JSContext
* cx
);
896 extern JS_PUBLIC_API
bool AddSizeOfTab(JSContext
* cx
, JS::HandleObject obj
,
897 mozilla::MallocSizeOf mallocSizeOf
,
898 ObjectPrivateVisitor
* opv
,
901 extern JS_PUBLIC_API
bool AddServoSizeOf(JSContext
* cx
,
902 mozilla::MallocSizeOf mallocSizeOf
,
903 ObjectPrivateVisitor
* opv
,
908 #undef DECL_SIZE_ZERO
909 #undef ADD_OTHER_SIZE
910 #undef SUB_OTHER_SIZE
912 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
913 #undef ADD_TO_TAB_SIZES
915 #endif /* js_MemoryMetrics_h */