Bug 1692971 [wpt PR 27638] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / js / public / MemoryMetrics.h
blobadf68f31cd54efc7e361f708555f389dd70997e2
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 "jspubtd.h"
21 #include "js/AllocPolicy.h"
22 #include "js/GCAPI.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.
30 namespace JS {
32 struct TabSizes {
33 TabSizes() = default;
35 enum Kind { Objects, Strings, Private, Other };
37 void add(Kind kind, size_t n) {
38 switch (kind) {
39 case Objects:
40 objects_ += n;
41 break;
42 case Strings:
43 strings_ += n;
44 break;
45 case Private:
46 private_ += n;
47 break;
48 case Other:
49 other_ += n;
50 break;
51 default:
52 MOZ_CRASH("bad TabSizes kind");
56 size_t objects_ = 0;
57 size_t strings_ = 0;
58 size_t private_ = 0;
59 size_t other_ = 0;
62 /** These are the measurements used by Servo. */
63 struct ServoSizes {
64 ServoSizes() = default;
66 enum Kind {
67 GCHeapUsed,
68 GCHeapUnused,
69 GCHeapAdmin,
70 GCHeapDecommitted,
71 MallocHeap,
72 NonHeap,
73 Ignore
76 void add(Kind kind, size_t n) {
77 switch (kind) {
78 case GCHeapUsed:
79 gcHeapUsed += n;
80 break;
81 case GCHeapUnused:
82 gcHeapUnused += n;
83 break;
84 case GCHeapAdmin:
85 gcHeapAdmin += n;
86 break;
87 case GCHeapDecommitted:
88 gcHeapDecommitted += n;
89 break;
90 case MallocHeap:
91 mallocHeap += n;
92 break;
93 case NonHeap:
94 nonHeap += n;
95 break;
96 case Ignore: /* do nothing */
97 break;
98 default:
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;
108 size_t nonHeap = 0;
111 } // namespace JS
113 namespace js {
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
143 // methods.
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 '_'
151 // for those.
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]>) \
163 ? mSize \
164 : 0;
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);
170 } // namespace js
172 namespace JS {
174 struct ClassInfo {
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 {
193 size_t n = 0;
194 FOR_EACH_SIZE(ADD_SIZE_TO_N);
195 return n;
198 bool isNotable() const {
199 static const size_t NotabilityThreshold = 16 * 1024;
200 return sizeOfAllThings() >= NotabilityThreshold;
203 size_t sizeOfLiveGCThings() const {
204 size_t n = 0;
205 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
206 return n;
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;
219 #undef FOR_EACH_SIZE
222 struct ShapeInfo {
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 {
238 size_t n = 0;
239 FOR_EACH_SIZE(ADD_SIZE_TO_N);
240 return n;
243 size_t sizeOfLiveGCThings() const {
244 size_t n = 0;
245 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
246 return n;
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);
257 #undef FOR_EACH_SIZE
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
263 * individually.
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. */
279 struct CodeSizes {
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);
295 #undef FOR_EACH_SIZE
298 /** Data for tracking GC memory usage. */
299 struct GCSizes {
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)
312 GCSizes() = default;
314 void addToServoSizes(ServoSizes* sizes) const {
315 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
318 FOR_EACH_SIZE(DECL_SIZE_ZERO);
320 #undef FOR_EACH_SIZE
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
328 * is not.
330 struct StringInfo {
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);
341 numCopies++;
344 void subtract(const StringInfo& other) {
345 FOR_EACH_SIZE(SUB_OTHER_SIZE);
346 numCopies--;
349 bool isNotable() const {
350 static const size_t NotabilityThreshold = 16 * 1024;
351 size_t n = 0;
352 FOR_EACH_SIZE(ADD_SIZE_TO_N);
353 return n >= NotabilityThreshold;
356 size_t sizeOfLiveGCThings() const {
357 size_t n = 0;
358 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
359 return n;
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?
372 #undef FOR_EACH_SIZE
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;
392 size_t length = 0;
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);
406 numScripts++;
409 void subtract(const ScriptSourceInfo& other) {
410 FOR_EACH_SIZE(SUB_OTHER_SIZE);
411 numScripts--;
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;
420 size_t n = 0;
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.)
430 #undef FOR_EACH_SIZE
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
436 * individually.
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;
466 #undef FOR_EACH_SIZE
470 * Measurements that not associated with any individual runtime.
472 struct GlobalStats {
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_;
484 #undef FOR_EACH_SIZE
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;
522 GCSizes gc;
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;
536 #undef FOR_EACH_SIZE
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) {
557 switch (kind) {
558 case JS::TraceKind::Object:
559 object += n;
560 break;
561 case JS::TraceKind::String:
562 string += n;
563 break;
564 case JS::TraceKind::Symbol:
565 symbol += n;
566 break;
567 case JS::TraceKind::BigInt:
568 bigInt += n;
569 break;
570 case JS::TraceKind::Script:
571 script += n;
572 break;
573 case JS::TraceKind::Shape:
574 shape += n;
575 break;
576 case JS::TraceKind::BaseShape:
577 baseShape += n;
578 break;
579 case JS::TraceKind::JitCode:
580 jitcode += n;
581 break;
582 case JS::TraceKind::ObjectGroup:
583 objectGroup += n;
584 break;
585 case JS::TraceKind::Scope:
586 scope += n;
587 break;
588 case JS::TraceKind::RegExpShared:
589 regExpShared += n;
590 break;
591 default:
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 {
601 size_t n = 0;
602 FOR_EACH_SIZE(ADD_SIZE_TO_N);
603 return 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);
616 #undef FOR_EACH_SIZE
619 struct ZoneStats {
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;
644 void initStrings();
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);
656 size_t n = 0;
657 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
658 n += stringInfo.sizeOfLiveGCThings();
659 n += shapeInfo.sizeOfLiveGCThings();
660 return n;
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
685 // |notableStrings|.
686 UnusedGCThingSizes unusedGCThings;
687 StringInfo stringInfo;
688 ShapeInfo shapeInfo;
689 CodeSizes code;
690 void* extra = nullptr; // This field can be used by embedders.
692 typedef js::HashMap<JSString*, StringInfo,
693 js::InefficientNonFlatteningStringHashPolicy,
694 js::SystemAllocPolicy>
695 StringsHashMap;
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;
705 #undef FOR_EACH_SIZE
708 struct RealmStats {
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
712 // zero.
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
735 void initClasses();
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);
745 size_t n = 0;
746 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
747 n += classInfo.sizeOfLiveGCThings();
748 return n;
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|.
768 ClassInfo classInfo;
769 void* extra = nullptr; // This field can be used by embedders.
771 typedef js::HashMap<const char*, ClassInfo, mozilla::CStringHasher,
772 js::SystemAllocPolicy>
773 ClassesHashMap;
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;
780 #undef FOR_EACH_SIZE
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
791 // values.
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)
809 // - unused bytes
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)
814 // - used bytes
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;
850 #undef FOR_EACH_SIZE
853 class ObjectPrivateVisitor {
854 public:
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,
873 bool anonymize);
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,
886 TabSizes* sizes);
888 extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx,
889 mozilla::MallocSizeOf mallocSizeOf,
890 ObjectPrivateVisitor* opv,
891 ServoSizes* sizes);
893 } // namespace JS
895 #undef DECL_SIZE_ZERO
896 #undef ADD_OTHER_SIZE
897 #undef SUB_OTHER_SIZE
898 #undef ADD_SIZE_TO_N
899 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
900 #undef ADD_TO_TAB_SIZES
902 #endif /* js_MemoryMetrics_h */