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, objectsMallocHeapMisc) \
190 MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
191 MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
192 MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
193 MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
195 ClassInfo() = default;
197 void add(const ClassInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
199 void subtract(const ClassInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
201 size_t sizeOfAllThings() const {
203 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
207 bool isNotable() const {
208 static const size_t NotabilityThreshold
= 16 * 1024;
209 return sizeOfAllThings() >= NotabilityThreshold
;
212 size_t sizeOfLiveGCThings() const {
214 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
218 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
220 void addToServoSizes(ServoSizes
* sizes
) const {
221 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
224 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
226 size_t wasmGuardPages
= 0;
232 #define FOR_EACH_SIZE(MACRO) \
233 MACRO(Other, GCHeapUsed, shapesGCHeapShared) \
234 MACRO(Other, GCHeapUsed, shapesGCHeapDict) \
235 MACRO(Other, GCHeapUsed, shapesGCHeapBase) \
236 MACRO(Other, MallocHeap, shapesMallocHeapCache)
238 ShapeInfo() = default;
240 void add(const ShapeInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
242 void subtract(const ShapeInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
244 size_t sizeOfAllThings() const {
246 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
250 size_t sizeOfLiveGCThings() const {
252 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
256 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
258 void addToServoSizes(ServoSizes
* sizes
) const {
259 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
262 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
268 * Holds data about a notable class (one whose combined object and shape
269 * instances use more than a certain amount of memory) so we can report it
272 * The only difference between this class and ClassInfo is that this class
273 * holds a copy of the filename.
275 struct NotableClassInfo
: public ClassInfo
{
276 NotableClassInfo() = default;
277 NotableClassInfo(NotableClassInfo
&&) = default;
278 NotableClassInfo(const NotableClassInfo
& info
) = delete;
280 NotableClassInfo(const char* className
, const ClassInfo
& info
);
282 UniqueChars className_
= nullptr;
285 /** Data for tracking JIT-code memory usage. */
287 #define FOR_EACH_SIZE(MACRO) \
288 MACRO(_, NonHeap, ion) \
289 MACRO(_, NonHeap, baseline) \
290 MACRO(_, NonHeap, regexp) \
291 MACRO(_, NonHeap, other) \
292 MACRO(_, NonHeap, unused)
294 CodeSizes() = default;
296 void addToServoSizes(ServoSizes
* sizes
) const {
297 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
300 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
305 /** Data for tracking GC memory usage. */
307 // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
308 // because we don't consider the nursery to be part of the GC heap.
309 #define FOR_EACH_SIZE(MACRO) \
310 MACRO(_, MallocHeap, marker) \
311 MACRO(_, NonHeap, nurseryCommitted) \
312 MACRO(_, MallocHeap, nurseryMallocedBuffers) \
313 MACRO(_, MallocHeap, storeBufferVals) \
314 MACRO(_, MallocHeap, storeBufferCells) \
315 MACRO(_, MallocHeap, storeBufferSlots) \
316 MACRO(_, MallocHeap, storeBufferWholeCells) \
317 MACRO(_, MallocHeap, storeBufferGenerics)
321 void addToServoSizes(ServoSizes
* sizes
) const {
322 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
325 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
331 * This class holds information about the memory taken up by identical copies of
332 * a particular string. Multiple JSStrings may have their sizes aggregated
333 * together into one StringInfo object. Note that two strings with identical
334 * chars will not be aggregated together if one is a short string and the other
338 #define FOR_EACH_SIZE(MACRO) \
339 MACRO(Strings, GCHeapUsed, gcHeapLatin1) \
340 MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \
341 MACRO(Strings, MallocHeap, mallocHeapLatin1) \
342 MACRO(Strings, MallocHeap, mallocHeapTwoByte)
344 StringInfo() = default;
346 void add(const StringInfo
& other
) {
347 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
351 void subtract(const StringInfo
& other
) {
352 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
356 bool isNotable() const {
357 static const size_t NotabilityThreshold
= 16 * 1024;
359 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
360 return n
>= NotabilityThreshold
;
363 size_t sizeOfLiveGCThings() const {
365 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
369 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
371 void addToServoSizes(ServoSizes
* sizes
) const {
372 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
375 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
377 uint32_t numCopies
= 0; // How many copies of the string have we seen?
383 * Holds data about a notable string (one which, counting all duplicates, uses
384 * more than a certain amount of memory) so we can report it individually.
386 * The only difference between this class and StringInfo is that
387 * NotableStringInfo holds a copy of some or all of the string's chars.
389 struct NotableStringInfo
: public StringInfo
{
390 static const size_t MAX_SAVED_CHARS
= 1024;
392 NotableStringInfo() = default;
393 NotableStringInfo(NotableStringInfo
&&) = default;
394 NotableStringInfo(const NotableStringInfo
&) = delete;
396 NotableStringInfo(JSString
* str
, const StringInfo
& info
);
398 UniqueChars buffer
= nullptr;
403 * This class holds information about the memory taken up by script sources
404 * from a particular file.
406 struct ScriptSourceInfo
{
407 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc)
409 ScriptSourceInfo() = default;
411 void add(const ScriptSourceInfo
& other
) {
412 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
416 void subtract(const ScriptSourceInfo
& other
) {
417 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
421 void addToServoSizes(ServoSizes
* sizes
) const {
422 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
425 bool isNotable() const {
426 static const size_t NotabilityThreshold
= 16 * 1024;
428 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
429 return n
>= NotabilityThreshold
;
432 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
434 uint32_t numScripts
= 0; // How many ScriptSources come from this file? (It
435 // can be more than one in XML files that have
436 // multiple scripts in CDATA sections.)
441 * Holds data about a notable script source file (one whose combined
442 * script sources use more than a certain amount of memory) so we can report it
445 * The only difference between this class and ScriptSourceInfo is that this
446 * class holds a copy of the filename.
448 struct NotableScriptSourceInfo
: public ScriptSourceInfo
{
449 NotableScriptSourceInfo() = default;
450 NotableScriptSourceInfo(NotableScriptSourceInfo
&&) = default;
451 NotableScriptSourceInfo(const NotableScriptSourceInfo
&) = delete;
453 NotableScriptSourceInfo(const char* filename
, const ScriptSourceInfo
& info
);
455 UniqueChars filename_
= nullptr;
458 struct HelperThreadStats
{
459 #define FOR_EACH_SIZE(MACRO) \
460 MACRO(_, MallocHeap, stateData) \
461 MACRO(_, MallocHeap, parseTask) \
462 MACRO(_, MallocHeap, ionCompileTask) \
463 MACRO(_, MallocHeap, wasmCompile) \
464 MACRO(_, MallocHeap, contexts)
466 HelperThreadStats() = default;
468 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
470 unsigned idleThreadCount
= 0;
471 unsigned activeThreadCount
= 0;
477 * Measurements that not associated with any individual runtime.
480 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, tracelogger)
482 explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf
)
483 : mallocSizeOf_(mallocSizeOf
) {}
485 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
487 HelperThreadStats helperThread
;
489 mozilla::MallocSizeOf mallocSizeOf_
;
495 * These measurements relate directly to the JSRuntime, and not to zones,
496 * compartments, and realms within it.
498 struct RuntimeSizes
{
499 #define FOR_EACH_SIZE(MACRO) \
500 MACRO(_, MallocHeap, object) \
501 MACRO(_, MallocHeap, atomsTable) \
502 MACRO(_, MallocHeap, atomsMarkBitmaps) \
503 MACRO(_, MallocHeap, contexts) \
504 MACRO(_, MallocHeap, temporary) \
505 MACRO(_, MallocHeap, interpreterStack) \
506 MACRO(_, MallocHeap, sharedImmutableStringsCache) \
507 MACRO(_, MallocHeap, sharedIntlData) \
508 MACRO(_, MallocHeap, uncompressedSourceCache) \
509 MACRO(_, MallocHeap, scriptData) \
510 MACRO(_, MallocHeap, tracelogger) \
511 MACRO(_, MallocHeap, wasmRuntime) \
512 MACRO(_, MallocHeap, jitLazyLink)
514 RuntimeSizes() { allScriptSources
.emplace(); }
516 void addToServoSizes(ServoSizes
* sizes
) const {
517 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
518 scriptSourceInfo
.addToServoSizes(sizes
);
519 gc
.addToServoSizes(sizes
);
522 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
524 // The script source measurements in |scriptSourceInfo| are initially for
525 // all script sources. At the end, if the measurement granularity is
526 // FineGrained, we subtract the measurements of the notable script sources
527 // and move them into |notableScriptSources|.
528 ScriptSourceInfo scriptSourceInfo
;
531 typedef js::HashMap
<const char*, ScriptSourceInfo
, mozilla::CStringHasher
,
532 js::SystemAllocPolicy
>
533 ScriptSourcesHashMap
;
535 // |allScriptSources| is only used transiently. During the reporting phase
536 // it is filled with info about every script source in the runtime. It's
537 // then used to fill in |notableScriptSources| (which actually gets
538 // reported), and immediately discarded afterwards.
539 mozilla::Maybe
<ScriptSourcesHashMap
> allScriptSources
;
540 js::Vector
<NotableScriptSourceInfo
, 0, js::SystemAllocPolicy
>
541 notableScriptSources
;
546 struct UnusedGCThingSizes
{
547 #define FOR_EACH_SIZE(MACRO) \
548 MACRO(Other, GCHeapUnused, object) \
549 MACRO(Other, GCHeapUnused, script) \
550 MACRO(Other, GCHeapUnused, shape) \
551 MACRO(Other, GCHeapUnused, baseShape) \
552 MACRO(Other, GCHeapUnused, getterSetter) \
553 MACRO(Other, GCHeapUnused, propMap) \
554 MACRO(Other, GCHeapUnused, string) \
555 MACRO(Other, GCHeapUnused, symbol) \
556 MACRO(Other, GCHeapUnused, bigInt) \
557 MACRO(Other, GCHeapUnused, jitcode) \
558 MACRO(Other, GCHeapUnused, scope) \
559 MACRO(Other, GCHeapUnused, regExpShared)
561 UnusedGCThingSizes() = default;
562 UnusedGCThingSizes(UnusedGCThingSizes
&& other
) = default;
564 void addToKind(JS::TraceKind kind
, intptr_t n
) {
566 case JS::TraceKind::Object
:
569 case JS::TraceKind::String
:
572 case JS::TraceKind::Symbol
:
575 case JS::TraceKind::BigInt
:
578 case JS::TraceKind::Script
:
581 case JS::TraceKind::Shape
:
584 case JS::TraceKind::BaseShape
:
587 case JS::TraceKind::GetterSetter
:
590 case JS::TraceKind::PropMap
:
593 case JS::TraceKind::JitCode
:
596 case JS::TraceKind::Scope
:
599 case JS::TraceKind::RegExpShared
:
603 MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
607 void addSizes(const UnusedGCThingSizes
& other
) {
608 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
611 size_t totalSize() const {
613 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
617 void addToTabSizes(JS::TabSizes
* sizes
) const {
618 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
621 void addToServoSizes(JS::ServoSizes
* sizes
) const {
622 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
625 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
631 #define FOR_EACH_SIZE(MACRO) \
632 MACRO(Other, GCHeapUsed, symbolsGCHeap) \
633 MACRO(Other, GCHeapUsed, bigIntsGCHeap) \
634 MACRO(Other, MallocHeap, bigIntsMallocHeap) \
635 MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \
636 MACRO(Other, GCHeapUsed, jitCodesGCHeap) \
637 MACRO(Other, GCHeapUsed, getterSettersGCHeap) \
638 MACRO(Other, GCHeapUsed, compactPropMapsGCHeap) \
639 MACRO(Other, GCHeapUsed, normalPropMapsGCHeap) \
640 MACRO(Other, GCHeapUsed, dictPropMapsGCHeap) \
641 MACRO(Other, MallocHeap, propMapChildren) \
642 MACRO(Other, MallocHeap, propMapTables) \
643 MACRO(Other, GCHeapUsed, scopesGCHeap) \
644 MACRO(Other, MallocHeap, scopesMallocHeap) \
645 MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
646 MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
647 MACRO(Other, MallocHeap, regexpZone) \
648 MACRO(Other, MallocHeap, jitZone) \
649 MACRO(Other, MallocHeap, baselineStubsOptimized) \
650 MACRO(Other, MallocHeap, uniqueIdMap) \
651 MACRO(Other, MallocHeap, initialPropMapTable) \
652 MACRO(Other, MallocHeap, shapeTables) \
653 MACRO(Other, MallocHeap, compartmentObjects) \
654 MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
655 MACRO(Other, MallocHeap, compartmentsPrivateData) \
656 MACRO(Other, MallocHeap, scriptCountsMap)
658 ZoneStats() = default;
659 ZoneStats(ZoneStats
&& other
) = default;
663 void addSizes(const ZoneStats
& other
) {
664 MOZ_ASSERT(isTotals
);
665 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
666 unusedGCThings
.addSizes(other
.unusedGCThings
);
667 stringInfo
.add(other
.stringInfo
);
668 shapeInfo
.add(other
.shapeInfo
);
671 size_t sizeOfLiveGCThings() const {
672 MOZ_ASSERT(isTotals
);
674 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
675 n
+= stringInfo
.sizeOfLiveGCThings();
676 n
+= shapeInfo
.sizeOfLiveGCThings();
680 void addToTabSizes(JS::TabSizes
* sizes
) const {
681 MOZ_ASSERT(isTotals
);
682 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
683 unusedGCThings
.addToTabSizes(sizes
);
684 stringInfo
.addToTabSizes(sizes
);
685 shapeInfo
.addToTabSizes(sizes
);
688 void addToServoSizes(JS::ServoSizes
* sizes
) const {
689 MOZ_ASSERT(isTotals
);
690 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
691 unusedGCThings
.addToServoSizes(sizes
);
692 stringInfo
.addToServoSizes(sizes
);
693 shapeInfo
.addToServoSizes(sizes
);
694 code
.addToServoSizes(sizes
);
697 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
699 // These string measurements are initially for all strings. At the end,
700 // if the measurement granularity is FineGrained, we subtract the
701 // measurements of the notable script sources and move them into
703 UnusedGCThingSizes unusedGCThings
;
704 StringInfo stringInfo
;
707 void* extra
= nullptr; // This field can be used by embedders.
709 typedef js::HashMap
<JSString
*, StringInfo
,
710 js::InefficientNonFlatteningStringHashPolicy
,
711 js::SystemAllocPolicy
>
714 // |allStrings| is only used transiently. During the zone traversal it is
715 // filled with info about every string in the zone. It's then used to fill
716 // in |notableStrings| (which actually gets reported), and immediately
717 // discarded afterwards.
718 mozilla::Maybe
<StringsHashMap
> allStrings
;
719 js::Vector
<NotableStringInfo
, 0, js::SystemAllocPolicy
> notableStrings
;
720 bool isTotals
= true;
726 // We assume that |objectsPrivate| is on the malloc heap, but it's not
727 // actually guaranteed. But for Servo, at least, it's a moot point because
728 // it doesn't provide an ObjectPrivateVisitor so the value will always be
730 #define FOR_EACH_SIZE(MACRO) \
731 MACRO(Private, MallocHeap, objectsPrivate) \
732 MACRO(Other, GCHeapUsed, scriptsGCHeap) \
733 MACRO(Other, MallocHeap, scriptsMallocHeapData) \
734 MACRO(Other, MallocHeap, baselineData) \
735 MACRO(Other, MallocHeap, baselineStubsFallback) \
736 MACRO(Other, MallocHeap, ionData) \
737 MACRO(Other, MallocHeap, jitScripts) \
738 MACRO(Other, MallocHeap, realmObject) \
739 MACRO(Other, MallocHeap, realmTables) \
740 MACRO(Other, MallocHeap, innerViewsTable) \
741 MACRO(Other, MallocHeap, objectMetadataTable) \
742 MACRO(Other, MallocHeap, savedStacksSet) \
743 MACRO(Other, MallocHeap, varNamesSet) \
744 MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
745 MACRO(Other, MallocHeap, jitRealm)
747 RealmStats() = default;
748 RealmStats(RealmStats
&& other
) = default;
750 RealmStats(const RealmStats
&) = delete; // disallow copying
754 void addSizes(const RealmStats
& other
) {
755 MOZ_ASSERT(isTotals
);
756 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
757 classInfo
.add(other
.classInfo
);
760 size_t sizeOfLiveGCThings() const {
761 MOZ_ASSERT(isTotals
);
763 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
764 n
+= classInfo
.sizeOfLiveGCThings();
768 void addToTabSizes(TabSizes
* sizes
) const {
769 MOZ_ASSERT(isTotals
);
770 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
771 classInfo
.addToTabSizes(sizes
);
774 void addToServoSizes(ServoSizes
* sizes
) const {
775 MOZ_ASSERT(isTotals
);
776 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
777 classInfo
.addToServoSizes(sizes
);
780 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
782 // The class measurements in |classInfo| are initially for all classes. At
783 // the end, if the measurement granularity is FineGrained, we subtract the
784 // measurements of the notable classes and move them into |notableClasses|.
786 void* extra
= nullptr; // This field can be used by embedders.
788 typedef js::HashMap
<const char*, ClassInfo
, mozilla::CStringHasher
,
789 js::SystemAllocPolicy
>
792 // These are similar to |allStrings| and |notableStrings| in ZoneStats.
793 mozilla::Maybe
<ClassesHashMap
> allClasses
;
794 js::Vector
<NotableClassInfo
, 0, js::SystemAllocPolicy
> notableClasses
;
795 bool isTotals
= true;
800 typedef js::Vector
<RealmStats
, 0, js::SystemAllocPolicy
> RealmStatsVector
;
801 typedef js::Vector
<ZoneStats
, 0, js::SystemAllocPolicy
> ZoneStatsVector
;
803 struct RuntimeStats
{
804 // |gcHeapChunkTotal| is ignored because it's the sum of all the other
805 // values. |gcHeapGCThings| is ignored because it's the sum of some of the
806 // values from the zones and compartments. Both of those values are not
807 // reported directly, but are just present for sanity-checking other
809 #define FOR_EACH_SIZE(MACRO) \
810 MACRO(_, Ignore, gcHeapChunkTotal) \
811 MACRO(_, GCHeapDecommitted, gcHeapDecommittedPages) \
812 MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \
813 MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \
814 MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \
815 MACRO(_, Ignore, gcHeapGCThings)
817 explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf
)
818 : mallocSizeOf_(mallocSizeOf
) {}
820 // Here's a useful breakdown of the GC heap.
822 // - rtStats.gcHeapChunkTotal
823 // - decommitted bytes
824 // - rtStats.gcHeapDecommittedPages
825 // (decommitted pages in non-empty chunks)
827 // - rtStats.gcHeapUnusedChunks (empty chunks)
828 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
829 // - rtStats.zTotals.unusedGCThings.totalSize()
830 // (empty GC thing slots within non-empty arenas)
832 // - rtStats.gcHeapChunkAdmin
833 // - rtStats.zTotals.gcHeapArenaAdmin
834 // - rtStats.gcHeapGCThings (in-use GC things)
835 // == (rtStats.zTotals.sizeOfLiveGCThings() +
836 // rtStats.cTotals.sizeOfLiveGCThings())
838 // It's possible that some pages in empty chunks may be decommitted, but
839 // we don't count those under rtStats.gcHeapDecommittedPages because (a)
840 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
841 // multiple of the chunk size, which is good.
843 void addToServoSizes(ServoSizes
* sizes
) const {
844 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
845 runtime
.addToServoSizes(sizes
);
848 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
850 RuntimeSizes runtime
;
852 RealmStats realmTotals
; // The sum of this runtime's realms' measurements.
853 ZoneStats zTotals
; // The sum of this runtime's zones' measurements.
855 RealmStatsVector realmStatsVector
;
856 ZoneStatsVector zoneStatsVector
;
858 ZoneStats
* currZoneStats
= nullptr;
860 mozilla::MallocSizeOf mallocSizeOf_
;
862 virtual void initExtraRealmStats(JS::Realm
* realm
, RealmStats
* rstats
,
863 const JS::AutoRequireNoGC
& nogc
) = 0;
864 virtual void initExtraZoneStats(JS::Zone
* zone
, ZoneStats
* zstats
,
865 const JS::AutoRequireNoGC
& nogc
) = 0;
870 class ObjectPrivateVisitor
{
872 // Within CollectRuntimeStats, this method is called for each JS object
873 // that has an nsISupports pointer.
874 virtual size_t sizeOfIncludingThis(nsISupports
* aSupports
) = 0;
876 // A callback that gets a JSObject's nsISupports pointer, if it has one.
877 // Note: this function does *not* addref |iface|.
878 typedef bool (*GetISupportsFun
)(JSObject
* obj
, nsISupports
** iface
);
879 GetISupportsFun getISupports_
;
881 explicit ObjectPrivateVisitor(GetISupportsFun getISupports
)
882 : getISupports_(getISupports
) {}
885 extern JS_PUBLIC_API
bool CollectGlobalStats(GlobalStats
* gStats
);
887 extern JS_PUBLIC_API
bool CollectRuntimeStats(JSContext
* cx
,
888 RuntimeStats
* rtStats
,
889 ObjectPrivateVisitor
* opv
,
892 extern JS_PUBLIC_API
size_t SystemCompartmentCount(JSContext
* cx
);
893 extern JS_PUBLIC_API
size_t UserCompartmentCount(JSContext
* cx
);
895 extern JS_PUBLIC_API
size_t SystemRealmCount(JSContext
* cx
);
896 extern JS_PUBLIC_API
size_t UserRealmCount(JSContext
* cx
);
898 extern JS_PUBLIC_API
size_t PeakSizeOfTemporary(const JSContext
* cx
);
900 extern JS_PUBLIC_API
bool AddSizeOfTab(JSContext
* cx
, JS::HandleObject obj
,
901 mozilla::MallocSizeOf mallocSizeOf
,
902 ObjectPrivateVisitor
* opv
,
905 extern JS_PUBLIC_API
bool AddServoSizeOf(JSContext
* cx
,
906 mozilla::MallocSizeOf mallocSizeOf
,
907 ObjectPrivateVisitor
* opv
,
912 #undef DECL_SIZE_ZERO
913 #undef ADD_OTHER_SIZE
914 #undef SUB_OTHER_SIZE
916 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
917 #undef ADD_TO_TAB_SIZES
919 #endif /* js_MemoryMetrics_h */