Bug 1874684 - Part 25: Editorial updates. r=dminor
[gecko.git] / js / public / MemoryMetrics.h
blob305ab1feb0a43fa72caf56db26a289c631094a04
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
11 // at your own risk.
13 #include "mozilla/Maybe.h"
14 #include "mozilla/MemoryReporting.h"
16 #include <string.h>
17 #include <type_traits>
19 #include "jstypes.h"
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.
30 namespace js {
31 class SystemAllocPolicy;
34 namespace mozilla {
35 struct CStringHasher;
38 namespace JS {
39 class JS_PUBLIC_API AutoRequireNoGC;
41 struct TabSizes {
42 TabSizes() = default;
44 enum Kind { Objects, Strings, Private, Other };
46 void add(Kind kind, size_t n) {
47 switch (kind) {
48 case Objects:
49 objects_ += n;
50 break;
51 case Strings:
52 strings_ += n;
53 break;
54 case Private:
55 private_ += n;
56 break;
57 case Other:
58 other_ += n;
59 break;
60 default:
61 MOZ_CRASH("bad TabSizes kind");
65 size_t objects_ = 0;
66 size_t strings_ = 0;
67 size_t private_ = 0;
68 size_t other_ = 0;
71 /** These are the measurements used by Servo. */
72 struct ServoSizes {
73 ServoSizes() = default;
75 enum Kind {
76 GCHeapUsed,
77 GCHeapUnused,
78 GCHeapAdmin,
79 GCHeapDecommitted,
80 MallocHeap,
81 NonHeap,
82 Ignore
85 void add(Kind kind, size_t n) {
86 switch (kind) {
87 case GCHeapUsed:
88 gcHeapUsed += n;
89 break;
90 case GCHeapUnused:
91 gcHeapUnused += n;
92 break;
93 case GCHeapAdmin:
94 gcHeapAdmin += n;
95 break;
96 case GCHeapDecommitted:
97 gcHeapDecommitted += n;
98 break;
99 case MallocHeap:
100 mallocHeap += n;
101 break;
102 case NonHeap:
103 nonHeap += n;
104 break;
105 case Ignore: /* do nothing */
106 break;
107 default:
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;
117 size_t nonHeap = 0;
120 } // namespace JS
122 namespace js {
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
152 // methods.
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 '_'
160 // for those.
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]>) \
172 ? mSize \
173 : 0;
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);
179 } // namespace js
181 namespace JS {
183 struct ClassInfo {
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 {
205 size_t n = 0;
206 FOR_EACH_SIZE(ADD_SIZE_TO_N);
207 return n;
210 bool isNotable() const {
211 static const size_t NotabilityThreshold = 16 * 1024;
212 return sizeOfAllThings() >= NotabilityThreshold;
215 size_t sizeOfLiveGCThings() const {
216 size_t n = 0;
217 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
218 return n;
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);
229 #undef FOR_EACH_SIZE
232 struct ShapeInfo {
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 {
246 size_t n = 0;
247 FOR_EACH_SIZE(ADD_SIZE_TO_N);
248 return n;
251 size_t sizeOfLiveGCThings() const {
252 size_t n = 0;
253 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
254 return n;
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);
265 #undef FOR_EACH_SIZE
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
271 * individually.
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. */
287 struct CodeSizes {
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);
303 #undef FOR_EACH_SIZE
306 /** Data for tracking GC memory usage. */
307 struct GCSizes {
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)
323 GCSizes() = default;
325 void addToServoSizes(ServoSizes* sizes) const {
326 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
329 FOR_EACH_SIZE(DECL_SIZE_ZERO);
331 #undef FOR_EACH_SIZE
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
339 * is not.
341 struct StringInfo {
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);
352 numCopies++;
355 void subtract(const StringInfo& other) {
356 FOR_EACH_SIZE(SUB_OTHER_SIZE);
357 numCopies--;
360 bool isNotable() const {
361 static const size_t NotabilityThreshold = 16 * 1024;
362 size_t n = 0;
363 FOR_EACH_SIZE(ADD_SIZE_TO_N);
364 return n >= NotabilityThreshold;
367 size_t sizeOfLiveGCThings() const {
368 size_t n = 0;
369 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
370 return n;
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?
383 #undef FOR_EACH_SIZE
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;
403 size_t length = 0;
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);
417 numScripts++;
420 void subtract(const ScriptSourceInfo& other) {
421 FOR_EACH_SIZE(SUB_OTHER_SIZE);
422 numScripts--;
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;
431 size_t n = 0;
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.)
441 #undef FOR_EACH_SIZE
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
447 * individually.
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;
476 #undef FOR_EACH_SIZE
480 * Measurements that not associated with any individual runtime.
482 struct GlobalStats {
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;
527 GCSizes gc;
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;
541 #undef FOR_EACH_SIZE
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) {
563 switch (kind) {
564 case JS::TraceKind::Object:
565 object += n;
566 break;
567 case JS::TraceKind::String:
568 string += n;
569 break;
570 case JS::TraceKind::Symbol:
571 symbol += n;
572 break;
573 case JS::TraceKind::BigInt:
574 bigInt += n;
575 break;
576 case JS::TraceKind::Script:
577 script += n;
578 break;
579 case JS::TraceKind::Shape:
580 shape += n;
581 break;
582 case JS::TraceKind::BaseShape:
583 baseShape += n;
584 break;
585 case JS::TraceKind::GetterSetter:
586 getterSetter += n;
587 break;
588 case JS::TraceKind::PropMap:
589 propMap += n;
590 break;
591 case JS::TraceKind::JitCode:
592 jitcode += n;
593 break;
594 case JS::TraceKind::Scope:
595 scope += n;
596 break;
597 case JS::TraceKind::RegExpShared:
598 regExpShared += n;
599 break;
600 default:
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 {
610 size_t n = 0;
611 FOR_EACH_SIZE(ADD_SIZE_TO_N);
612 return 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);
625 #undef FOR_EACH_SIZE
628 struct ZoneStats {
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;
660 void initStrings();
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);
672 size_t n = 0;
673 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
674 n += stringInfo.sizeOfLiveGCThings();
675 n += shapeInfo.sizeOfLiveGCThings();
676 return n;
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
701 // |notableStrings|.
702 UnusedGCThingSizes unusedGCThings;
703 StringInfo stringInfo;
704 ShapeInfo shapeInfo;
705 CodeSizes code;
706 void* extra = nullptr; // This field can be used by embedders.
708 typedef js::HashMap<JSString*, StringInfo,
709 js::InefficientNonFlatteningStringHashPolicy,
710 js::SystemAllocPolicy>
711 StringsHashMap;
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;
721 #undef FOR_EACH_SIZE
724 struct RealmStats {
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
728 // zero.
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
749 void initClasses();
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);
759 size_t n = 0;
760 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
761 n += classInfo.sizeOfLiveGCThings();
762 return n;
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|.
782 ClassInfo classInfo;
783 void* extra = nullptr; // This field can be used by embedders.
785 typedef js::HashMap<const char*, ClassInfo, mozilla::CStringHasher,
786 js::SystemAllocPolicy>
787 ClassesHashMap;
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;
794 #undef FOR_EACH_SIZE
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
805 // values.
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)
823 // - unused bytes
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)
828 // - used bytes
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;
864 #undef FOR_EACH_SIZE
867 class ObjectPrivateVisitor {
868 public:
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,
887 bool anonymize);
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,
900 TabSizes* sizes);
902 extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx,
903 mozilla::MallocSizeOf mallocSizeOf,
904 ObjectPrivateVisitor* opv,
905 ServoSizes* sizes);
907 } // namespace JS
909 #undef DECL_SIZE_ZERO
910 #undef ADD_OTHER_SIZE
911 #undef SUB_OTHER_SIZE
912 #undef ADD_SIZE_TO_N
913 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
914 #undef ADD_TO_TAB_SIZES
916 #endif /* js_MemoryMetrics_h */