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"
23 #include "js/HashTable.h"
24 #include "js/TracingAPI.h"
25 #include "js/Utility.h"
26 #include "js/Vector.h"
28 class nsISupports
; // Needed for ObjectPrivateVisitor.
35 enum Kind
{ Objects
, Strings
, Private
, Other
};
37 void add(Kind kind
, size_t n
) {
52 MOZ_CRASH("bad TabSizes kind");
62 /** These are the measurements used by Servo. */
64 ServoSizes() = default;
76 void add(Kind kind
, size_t n
) {
87 case GCHeapDecommitted
:
88 gcHeapDecommitted
+= n
;
96 case Ignore
: /* do nothing */
99 MOZ_CRASH("bad ServoSizes kind");
103 size_t gcHeapUsed
= 0;
104 size_t gcHeapUnused
= 0;
105 size_t gcHeapAdmin
= 0;
106 size_t gcHeapDecommitted
= 0;
107 size_t mallocHeap
= 0;
116 * In memory reporting, we have concept of "sundries", line items which are too
117 * small to be worth reporting individually. Under some circumstances, a memory
118 * reporter gets tossed into the sundries bucket if it's smaller than
119 * MemoryReportingSundriesThreshold() bytes.
121 * We need to define this value here, rather than in the code which actually
122 * generates the memory reports, because NotableStringInfo uses this value.
124 JS_FRIEND_API
size_t MemoryReportingSundriesThreshold();
127 * This hash policy avoids flattening ropes (which perturbs the site being
128 * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
129 * on every hash and match! Beware.
131 struct InefficientNonFlatteningStringHashPolicy
{
132 typedef JSString
* Lookup
;
133 static HashNumber
hash(const Lookup
& l
);
134 static bool match(const JSString
* const& k
, const Lookup
& l
);
137 // This file features many classes with numerous size_t fields, and each such
138 // class has one or more methods that need to operate on all of these fields.
139 // Writing these individually is error-prone -- it's easy to add a new field
140 // without updating all the required methods. So we define a single macro list
141 // in each class to name the fields (and notable characteristics of them), and
142 // then use the following macros to transform those lists into the required
145 // - The |tabKind| value is used when measuring TabSizes.
147 // - The |servoKind| value is used when measuring ServoSizes and also for
148 // the various sizeOfLiveGCThings() methods.
150 // In some classes, one or more of the macro arguments aren't used. We use '_'
153 #define DECL_SIZE_ZERO(tabKind, servoKind, mSize) size_t mSize = 0;
154 #define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
155 #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
156 MOZ_ASSERT(mSize >= other.mSize); \
157 mSize -= other.mSize;
158 #define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
159 #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
160 /* Avoid self-comparison warnings by comparing enums indirectly. */ \
161 n += (std::is_same_v<int[ServoSizes::servoKind], \
162 int[ServoSizes::GCHeapUsed]>) \
165 #define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) \
166 sizes->add(JS::TabSizes::tabKind, mSize);
167 #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \
168 sizes->add(JS::ServoSizes::servoKind, mSize);
175 #define FOR_EACH_SIZE(MACRO) \
176 MACRO(Objects, GCHeapUsed, objectsGCHeap) \
177 MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
178 MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
179 MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
180 MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
181 MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
182 MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
183 MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
184 MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
186 ClassInfo() = default;
188 void add(const ClassInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
190 void subtract(const ClassInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
192 size_t sizeOfAllThings() const {
194 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
198 bool isNotable() const {
199 static const size_t NotabilityThreshold
= 16 * 1024;
200 return sizeOfAllThings() >= NotabilityThreshold
;
203 size_t sizeOfLiveGCThings() const {
205 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
209 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
211 void addToServoSizes(ServoSizes
* sizes
) const {
212 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
215 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
217 size_t wasmGuardPages
= 0;
223 #define FOR_EACH_SIZE(MACRO) \
224 MACRO(Other, GCHeapUsed, shapesGCHeapTree) \
225 MACRO(Other, GCHeapUsed, shapesGCHeapDict) \
226 MACRO(Other, GCHeapUsed, shapesGCHeapBase) \
227 MACRO(Other, MallocHeap, shapesMallocHeapTreeTables) \
228 MACRO(Other, MallocHeap, shapesMallocHeapDictTables) \
229 MACRO(Other, MallocHeap, shapesMallocHeapTreeChildren)
231 ShapeInfo() = default;
233 void add(const ShapeInfo
& other
) { FOR_EACH_SIZE(ADD_OTHER_SIZE
); }
235 void subtract(const ShapeInfo
& other
) { FOR_EACH_SIZE(SUB_OTHER_SIZE
); }
237 size_t sizeOfAllThings() const {
239 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
243 size_t sizeOfLiveGCThings() const {
245 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
249 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
251 void addToServoSizes(ServoSizes
* sizes
) const {
252 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
255 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
261 * Holds data about a notable class (one whose combined object and shape
262 * instances use more than a certain amount of memory) so we can report it
265 * The only difference between this class and ClassInfo is that this class
266 * holds a copy of the filename.
268 struct NotableClassInfo
: public ClassInfo
{
269 NotableClassInfo() = default;
270 NotableClassInfo(NotableClassInfo
&&) = default;
271 NotableClassInfo(const NotableClassInfo
& info
) = delete;
273 NotableClassInfo(const char* className
, const ClassInfo
& info
);
275 UniqueChars className_
= nullptr;
278 /** Data for tracking JIT-code memory usage. */
280 #define FOR_EACH_SIZE(MACRO) \
281 MACRO(_, NonHeap, ion) \
282 MACRO(_, NonHeap, baseline) \
283 MACRO(_, NonHeap, regexp) \
284 MACRO(_, NonHeap, other) \
285 MACRO(_, NonHeap, unused)
287 CodeSizes() = default;
289 void addToServoSizes(ServoSizes
* sizes
) const {
290 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
293 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
298 /** Data for tracking GC memory usage. */
300 // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
301 // because we don't consider the nursery to be part of the GC heap.
302 #define FOR_EACH_SIZE(MACRO) \
303 MACRO(_, MallocHeap, marker) \
304 MACRO(_, NonHeap, nurseryCommitted) \
305 MACRO(_, MallocHeap, nurseryMallocedBuffers) \
306 MACRO(_, MallocHeap, storeBufferVals) \
307 MACRO(_, MallocHeap, storeBufferCells) \
308 MACRO(_, MallocHeap, storeBufferSlots) \
309 MACRO(_, MallocHeap, storeBufferWholeCells) \
310 MACRO(_, MallocHeap, storeBufferGenerics)
314 void addToServoSizes(ServoSizes
* sizes
) const {
315 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
318 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
324 * This class holds information about the memory taken up by identical copies of
325 * a particular string. Multiple JSStrings may have their sizes aggregated
326 * together into one StringInfo object. Note that two strings with identical
327 * chars will not be aggregated together if one is a short string and the other
331 #define FOR_EACH_SIZE(MACRO) \
332 MACRO(Strings, GCHeapUsed, gcHeapLatin1) \
333 MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \
334 MACRO(Strings, MallocHeap, mallocHeapLatin1) \
335 MACRO(Strings, MallocHeap, mallocHeapTwoByte)
337 StringInfo() = default;
339 void add(const StringInfo
& other
) {
340 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
344 void subtract(const StringInfo
& other
) {
345 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
349 bool isNotable() const {
350 static const size_t NotabilityThreshold
= 16 * 1024;
352 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
353 return n
>= NotabilityThreshold
;
356 size_t sizeOfLiveGCThings() const {
358 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
362 void addToTabSizes(TabSizes
* sizes
) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES
); }
364 void addToServoSizes(ServoSizes
* sizes
) const {
365 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
368 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
370 uint32_t numCopies
= 0; // How many copies of the string have we seen?
376 * Holds data about a notable string (one which, counting all duplicates, uses
377 * more than a certain amount of memory) so we can report it individually.
379 * The only difference between this class and StringInfo is that
380 * NotableStringInfo holds a copy of some or all of the string's chars.
382 struct NotableStringInfo
: public StringInfo
{
383 static const size_t MAX_SAVED_CHARS
= 1024;
385 NotableStringInfo() = default;
386 NotableStringInfo(NotableStringInfo
&&) = default;
387 NotableStringInfo(const NotableStringInfo
&) = delete;
389 NotableStringInfo(JSString
* str
, const StringInfo
& info
);
391 UniqueChars buffer
= nullptr;
396 * This class holds information about the memory taken up by script sources
397 * from a particular file.
399 struct ScriptSourceInfo
{
400 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc)
402 ScriptSourceInfo() = default;
404 void add(const ScriptSourceInfo
& other
) {
405 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
409 void subtract(const ScriptSourceInfo
& other
) {
410 FOR_EACH_SIZE(SUB_OTHER_SIZE
);
414 void addToServoSizes(ServoSizes
* sizes
) const {
415 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
418 bool isNotable() const {
419 static const size_t NotabilityThreshold
= 16 * 1024;
421 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
422 return n
>= NotabilityThreshold
;
425 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
427 uint32_t numScripts
= 0; // How many ScriptSources come from this file? (It
428 // can be more than one in XML files that have
429 // multiple scripts in CDATA sections.)
434 * Holds data about a notable script source file (one whose combined
435 * script sources use more than a certain amount of memory) so we can report it
438 * The only difference between this class and ScriptSourceInfo is that this
439 * class holds a copy of the filename.
441 struct NotableScriptSourceInfo
: public ScriptSourceInfo
{
442 NotableScriptSourceInfo() = default;
443 NotableScriptSourceInfo(NotableScriptSourceInfo
&&) = default;
444 NotableScriptSourceInfo(const NotableScriptSourceInfo
&) = delete;
446 NotableScriptSourceInfo(const char* filename
, const ScriptSourceInfo
& info
);
448 UniqueChars filename_
= nullptr;
451 struct HelperThreadStats
{
452 #define FOR_EACH_SIZE(MACRO) \
453 MACRO(_, MallocHeap, stateData) \
454 MACRO(_, MallocHeap, parseTask) \
455 MACRO(_, MallocHeap, ionCompileTask) \
456 MACRO(_, MallocHeap, wasmCompile) \
457 MACRO(_, MallocHeap, contexts)
459 HelperThreadStats() = default;
461 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
463 unsigned idleThreadCount
= 0;
464 unsigned activeThreadCount
= 0;
470 * Measurements that not associated with any individual runtime.
473 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, tracelogger)
475 explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf
)
476 : mallocSizeOf_(mallocSizeOf
) {}
478 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
480 HelperThreadStats helperThread
;
482 mozilla::MallocSizeOf mallocSizeOf_
;
488 * These measurements relate directly to the JSRuntime, and not to zones,
489 * compartments, and realms within it.
491 struct RuntimeSizes
{
492 #define FOR_EACH_SIZE(MACRO) \
493 MACRO(_, MallocHeap, object) \
494 MACRO(_, MallocHeap, atomsTable) \
495 MACRO(_, MallocHeap, atomsMarkBitmaps) \
496 MACRO(_, MallocHeap, contexts) \
497 MACRO(_, MallocHeap, temporary) \
498 MACRO(_, MallocHeap, interpreterStack) \
499 MACRO(_, MallocHeap, sharedImmutableStringsCache) \
500 MACRO(_, MallocHeap, sharedIntlData) \
501 MACRO(_, MallocHeap, uncompressedSourceCache) \
502 MACRO(_, MallocHeap, scriptData) \
503 MACRO(_, MallocHeap, tracelogger) \
504 MACRO(_, MallocHeap, wasmRuntime) \
505 MACRO(_, MallocHeap, jitLazyLink)
507 RuntimeSizes() { allScriptSources
.emplace(); }
509 void addToServoSizes(ServoSizes
* sizes
) const {
510 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
511 scriptSourceInfo
.addToServoSizes(sizes
);
512 gc
.addToServoSizes(sizes
);
515 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
517 // The script source measurements in |scriptSourceInfo| are initially for
518 // all script sources. At the end, if the measurement granularity is
519 // FineGrained, we subtract the measurements of the notable script sources
520 // and move them into |notableScriptSources|.
521 ScriptSourceInfo scriptSourceInfo
;
524 typedef js::HashMap
<const char*, ScriptSourceInfo
, mozilla::CStringHasher
,
525 js::SystemAllocPolicy
>
526 ScriptSourcesHashMap
;
528 // |allScriptSources| is only used transiently. During the reporting phase
529 // it is filled with info about every script source in the runtime. It's
530 // then used to fill in |notableScriptSources| (which actually gets
531 // reported), and immediately discarded afterwards.
532 mozilla::Maybe
<ScriptSourcesHashMap
> allScriptSources
;
533 js::Vector
<NotableScriptSourceInfo
, 0, js::SystemAllocPolicy
>
534 notableScriptSources
;
539 struct UnusedGCThingSizes
{
540 #define FOR_EACH_SIZE(MACRO) \
541 MACRO(Other, GCHeapUnused, object) \
542 MACRO(Other, GCHeapUnused, script) \
543 MACRO(Other, GCHeapUnused, shape) \
544 MACRO(Other, GCHeapUnused, baseShape) \
545 MACRO(Other, GCHeapUnused, objectGroup) \
546 MACRO(Other, GCHeapUnused, string) \
547 MACRO(Other, GCHeapUnused, symbol) \
548 MACRO(Other, GCHeapUnused, bigInt) \
549 MACRO(Other, GCHeapUnused, jitcode) \
550 MACRO(Other, GCHeapUnused, scope) \
551 MACRO(Other, GCHeapUnused, regExpShared)
553 UnusedGCThingSizes() = default;
554 UnusedGCThingSizes(UnusedGCThingSizes
&& other
) = default;
556 void addToKind(JS::TraceKind kind
, intptr_t n
) {
558 case JS::TraceKind::Object
:
561 case JS::TraceKind::String
:
564 case JS::TraceKind::Symbol
:
567 case JS::TraceKind::BigInt
:
570 case JS::TraceKind::Script
:
573 case JS::TraceKind::Shape
:
576 case JS::TraceKind::BaseShape
:
579 case JS::TraceKind::JitCode
:
582 case JS::TraceKind::ObjectGroup
:
585 case JS::TraceKind::Scope
:
588 case JS::TraceKind::RegExpShared
:
592 MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
596 void addSizes(const UnusedGCThingSizes
& other
) {
597 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
600 size_t totalSize() const {
602 FOR_EACH_SIZE(ADD_SIZE_TO_N
);
606 void addToTabSizes(JS::TabSizes
* sizes
) const {
607 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
610 void addToServoSizes(JS::ServoSizes
* sizes
) const {
611 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
614 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
620 #define FOR_EACH_SIZE(MACRO) \
621 MACRO(Other, GCHeapUsed, symbolsGCHeap) \
622 MACRO(Other, GCHeapUsed, bigIntsGCHeap) \
623 MACRO(Other, MallocHeap, bigIntsMallocHeap) \
624 MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \
625 MACRO(Other, GCHeapUsed, jitCodesGCHeap) \
626 MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \
627 MACRO(Other, GCHeapUsed, scopesGCHeap) \
628 MACRO(Other, MallocHeap, scopesMallocHeap) \
629 MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
630 MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
631 MACRO(Other, MallocHeap, regexpZone) \
632 MACRO(Other, MallocHeap, jitZone) \
633 MACRO(Other, MallocHeap, baselineStubsOptimized) \
634 MACRO(Other, MallocHeap, uniqueIdMap) \
635 MACRO(Other, MallocHeap, shapeTables) \
636 MACRO(Other, MallocHeap, compartmentObjects) \
637 MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
638 MACRO(Other, MallocHeap, compartmentsPrivateData) \
639 MACRO(Other, MallocHeap, scriptCountsMap)
641 ZoneStats() = default;
642 ZoneStats(ZoneStats
&& other
) = default;
646 void addSizes(const ZoneStats
& other
) {
647 MOZ_ASSERT(isTotals
);
648 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
649 unusedGCThings
.addSizes(other
.unusedGCThings
);
650 stringInfo
.add(other
.stringInfo
);
651 shapeInfo
.add(other
.shapeInfo
);
654 size_t sizeOfLiveGCThings() const {
655 MOZ_ASSERT(isTotals
);
657 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
658 n
+= stringInfo
.sizeOfLiveGCThings();
659 n
+= shapeInfo
.sizeOfLiveGCThings();
663 void addToTabSizes(JS::TabSizes
* sizes
) const {
664 MOZ_ASSERT(isTotals
);
665 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
666 unusedGCThings
.addToTabSizes(sizes
);
667 stringInfo
.addToTabSizes(sizes
);
668 shapeInfo
.addToTabSizes(sizes
);
671 void addToServoSizes(JS::ServoSizes
* sizes
) const {
672 MOZ_ASSERT(isTotals
);
673 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
674 unusedGCThings
.addToServoSizes(sizes
);
675 stringInfo
.addToServoSizes(sizes
);
676 shapeInfo
.addToServoSizes(sizes
);
677 code
.addToServoSizes(sizes
);
680 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
682 // These string measurements are initially for all strings. At the end,
683 // if the measurement granularity is FineGrained, we subtract the
684 // measurements of the notable script sources and move them into
686 UnusedGCThingSizes unusedGCThings
;
687 StringInfo stringInfo
;
690 void* extra
= nullptr; // This field can be used by embedders.
692 typedef js::HashMap
<JSString
*, StringInfo
,
693 js::InefficientNonFlatteningStringHashPolicy
,
694 js::SystemAllocPolicy
>
697 // |allStrings| is only used transiently. During the zone traversal it is
698 // filled with info about every string in the zone. It's then used to fill
699 // in |notableStrings| (which actually gets reported), and immediately
700 // discarded afterwards.
701 mozilla::Maybe
<StringsHashMap
> allStrings
;
702 js::Vector
<NotableStringInfo
, 0, js::SystemAllocPolicy
> notableStrings
;
703 bool isTotals
= true;
709 // We assume that |objectsPrivate| is on the malloc heap, but it's not
710 // actually guaranteed. But for Servo, at least, it's a moot point because
711 // it doesn't provide an ObjectPrivateVisitor so the value will always be
713 #define FOR_EACH_SIZE(MACRO) \
714 MACRO(Private, MallocHeap, objectsPrivate) \
715 MACRO(Other, GCHeapUsed, scriptsGCHeap) \
716 MACRO(Other, MallocHeap, scriptsMallocHeapData) \
717 MACRO(Other, MallocHeap, baselineData) \
718 MACRO(Other, MallocHeap, baselineStubsFallback) \
719 MACRO(Other, MallocHeap, ionData) \
720 MACRO(Other, MallocHeap, jitScripts) \
721 MACRO(Other, MallocHeap, realmObject) \
722 MACRO(Other, MallocHeap, realmTables) \
723 MACRO(Other, MallocHeap, innerViewsTable) \
724 MACRO(Other, MallocHeap, objectMetadataTable) \
725 MACRO(Other, MallocHeap, savedStacksSet) \
726 MACRO(Other, MallocHeap, varNamesSet) \
727 MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
728 MACRO(Other, MallocHeap, jitRealm)
730 RealmStats() = default;
731 RealmStats(RealmStats
&& other
) = default;
733 RealmStats(const RealmStats
&) = delete; // disallow copying
737 void addSizes(const RealmStats
& other
) {
738 MOZ_ASSERT(isTotals
);
739 FOR_EACH_SIZE(ADD_OTHER_SIZE
);
740 classInfo
.add(other
.classInfo
);
743 size_t sizeOfLiveGCThings() const {
744 MOZ_ASSERT(isTotals
);
746 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING
);
747 n
+= classInfo
.sizeOfLiveGCThings();
751 void addToTabSizes(TabSizes
* sizes
) const {
752 MOZ_ASSERT(isTotals
);
753 FOR_EACH_SIZE(ADD_TO_TAB_SIZES
);
754 classInfo
.addToTabSizes(sizes
);
757 void addToServoSizes(ServoSizes
* sizes
) const {
758 MOZ_ASSERT(isTotals
);
759 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
760 classInfo
.addToServoSizes(sizes
);
763 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
765 // The class measurements in |classInfo| are initially for all classes. At
766 // the end, if the measurement granularity is FineGrained, we subtract the
767 // measurements of the notable classes and move them into |notableClasses|.
769 void* extra
= nullptr; // This field can be used by embedders.
771 typedef js::HashMap
<const char*, ClassInfo
, mozilla::CStringHasher
,
772 js::SystemAllocPolicy
>
775 // These are similar to |allStrings| and |notableStrings| in ZoneStats.
776 mozilla::Maybe
<ClassesHashMap
> allClasses
;
777 js::Vector
<NotableClassInfo
, 0, js::SystemAllocPolicy
> notableClasses
;
778 bool isTotals
= true;
783 typedef js::Vector
<RealmStats
, 0, js::SystemAllocPolicy
> RealmStatsVector
;
784 typedef js::Vector
<ZoneStats
, 0, js::SystemAllocPolicy
> ZoneStatsVector
;
786 struct RuntimeStats
{
787 // |gcHeapChunkTotal| is ignored because it's the sum of all the other
788 // values. |gcHeapGCThings| is ignored because it's the sum of some of the
789 // values from the zones and compartments. Both of those values are not
790 // reported directly, but are just present for sanity-checking other
792 #define FOR_EACH_SIZE(MACRO) \
793 MACRO(_, Ignore, gcHeapChunkTotal) \
794 MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \
795 MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \
796 MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \
797 MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \
798 MACRO(_, Ignore, gcHeapGCThings)
800 explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf
)
801 : mallocSizeOf_(mallocSizeOf
) {}
803 // Here's a useful breakdown of the GC heap.
805 // - rtStats.gcHeapChunkTotal
806 // - decommitted bytes
807 // - rtStats.gcHeapDecommittedArenas
808 // (decommitted arenas in non-empty chunks)
810 // - rtStats.gcHeapUnusedChunks (empty chunks)
811 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
812 // - rtStats.zTotals.unusedGCThings.totalSize()
813 // (empty GC thing slots within non-empty arenas)
815 // - rtStats.gcHeapChunkAdmin
816 // - rtStats.zTotals.gcHeapArenaAdmin
817 // - rtStats.gcHeapGCThings (in-use GC things)
818 // == (rtStats.zTotals.sizeOfLiveGCThings() +
819 // rtStats.cTotals.sizeOfLiveGCThings())
821 // It's possible that some arenas in empty chunks may be decommitted, but
822 // we don't count those under rtStats.gcHeapDecommittedArenas because (a)
823 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
824 // multiple of the chunk size, which is good.
826 void addToServoSizes(ServoSizes
* sizes
) const {
827 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES
);
828 runtime
.addToServoSizes(sizes
);
831 FOR_EACH_SIZE(DECL_SIZE_ZERO
);
833 RuntimeSizes runtime
;
835 RealmStats realmTotals
; // The sum of this runtime's realms' measurements.
836 ZoneStats zTotals
; // The sum of this runtime's zones' measurements.
838 RealmStatsVector realmStatsVector
;
839 ZoneStatsVector zoneStatsVector
;
841 ZoneStats
* currZoneStats
= nullptr;
843 mozilla::MallocSizeOf mallocSizeOf_
;
845 virtual void initExtraRealmStats(JS::Realm
* realm
, RealmStats
* rstats
,
846 const JS::AutoRequireNoGC
& nogc
) = 0;
847 virtual void initExtraZoneStats(JS::Zone
* zone
, ZoneStats
* zstats
,
848 const JS::AutoRequireNoGC
& nogc
) = 0;
853 class ObjectPrivateVisitor
{
855 // Within CollectRuntimeStats, this method is called for each JS object
856 // that has an nsISupports pointer.
857 virtual size_t sizeOfIncludingThis(nsISupports
* aSupports
) = 0;
859 // A callback that gets a JSObject's nsISupports pointer, if it has one.
860 // Note: this function does *not* addref |iface|.
861 typedef bool (*GetISupportsFun
)(JSObject
* obj
, nsISupports
** iface
);
862 GetISupportsFun getISupports_
;
864 explicit ObjectPrivateVisitor(GetISupportsFun getISupports
)
865 : getISupports_(getISupports
) {}
868 extern JS_PUBLIC_API
bool CollectGlobalStats(GlobalStats
* gStats
);
870 extern JS_PUBLIC_API
bool CollectRuntimeStats(JSContext
* cx
,
871 RuntimeStats
* rtStats
,
872 ObjectPrivateVisitor
* opv
,
875 extern JS_PUBLIC_API
size_t SystemCompartmentCount(JSContext
* cx
);
876 extern JS_PUBLIC_API
size_t UserCompartmentCount(JSContext
* cx
);
878 extern JS_PUBLIC_API
size_t SystemRealmCount(JSContext
* cx
);
879 extern JS_PUBLIC_API
size_t UserRealmCount(JSContext
* cx
);
881 extern JS_PUBLIC_API
size_t PeakSizeOfTemporary(const JSContext
* cx
);
883 extern JS_PUBLIC_API
bool AddSizeOfTab(JSContext
* cx
, JS::HandleObject obj
,
884 mozilla::MallocSizeOf mallocSizeOf
,
885 ObjectPrivateVisitor
* opv
,
888 extern JS_PUBLIC_API
bool AddServoSizeOf(JSContext
* cx
,
889 mozilla::MallocSizeOf mallocSizeOf
,
890 ObjectPrivateVisitor
* opv
,
895 #undef DECL_SIZE_ZERO
896 #undef ADD_OTHER_SIZE
897 #undef SUB_OTHER_SIZE
899 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
900 #undef ADD_TO_TAB_SIZES
902 #endif /* js_MemoryMetrics_h */