js/public/MemoryMetrics.h

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef js_MemoryMetrics_h
michael@0 8 #define js_MemoryMetrics_h
michael@0 9
michael@0 10 // These declarations are highly likely to change in the future. Depend on them
michael@0 11 // at your own risk.
michael@0 12
michael@0 13 #include "mozilla/MemoryReporting.h"
michael@0 14 #include "mozilla/NullPtr.h"
michael@0 15 #include "mozilla/PodOperations.h"
michael@0 16
michael@0 17 #include <string.h>
michael@0 18
michael@0 19 #include "jsalloc.h"
michael@0 20 #include "jspubtd.h"
michael@0 21
michael@0 22 #include "js/HashTable.h"
michael@0 23 #include "js/Utility.h"
michael@0 24 #include "js/Vector.h"
michael@0 25
michael@0 26 class nsISupports; // Needed for ObjectPrivateVisitor.
michael@0 27
michael@0 28 namespace JS {
michael@0 29
michael@0 30 struct TabSizes
michael@0 31 {
michael@0 32 enum Kind {
michael@0 33 Objects,
michael@0 34 Strings,
michael@0 35 Private,
michael@0 36 Other
michael@0 37 };
michael@0 38
michael@0 39 TabSizes() { mozilla::PodZero(this); }
michael@0 40
michael@0 41 void add(Kind kind, size_t n) {
michael@0 42 switch (kind) {
michael@0 43 case Objects: objects += n; break;
michael@0 44 case Strings: strings += n; break;
michael@0 45 case Private: private_ += n; break;
michael@0 46 case Other: other += n; break;
michael@0 47 default: MOZ_CRASH("bad TabSizes kind");
michael@0 48 }
michael@0 49 }
michael@0 50
michael@0 51 size_t objects;
michael@0 52 size_t strings;
michael@0 53 size_t private_;
michael@0 54 size_t other;
michael@0 55 };
michael@0 56
michael@0 57 } // namespace JS
michael@0 58
michael@0 59 namespace js {
michael@0 60
michael@0 61 // In memory reporting, we have concept of "sundries", line items which are too
michael@0 62 // small to be worth reporting individually. Under some circumstances, a memory
michael@0 63 // reporter gets tossed into the sundries bucket if it's smaller than
michael@0 64 // MemoryReportingSundriesThreshold() bytes.
michael@0 65 //
michael@0 66 // We need to define this value here, rather than in the code which actually
michael@0 67 // generates the memory reports, because NotableStringInfo uses this value.
michael@0 68 JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
michael@0 69
michael@0 70 // This hash policy avoids flattening ropes (which perturbs the site being
michael@0 71 // measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
michael@0 72 // on every hash and match! Beware.
michael@0 73 struct InefficientNonFlatteningStringHashPolicy
michael@0 74 {
michael@0 75 typedef JSString *Lookup;
michael@0 76 static HashNumber hash(const Lookup &l);
michael@0 77 static bool match(const JSString *const &k, const Lookup &l);
michael@0 78 };
michael@0 79
michael@0 80 struct CStringHashPolicy
michael@0 81 {
michael@0 82 typedef const char *Lookup;
michael@0 83 static HashNumber hash(const Lookup &l);
michael@0 84 static bool match(const char *const &k, const Lookup &l);
michael@0 85 };
michael@0 86
michael@0 87 // This file features many classes with numerous size_t fields, and each such
michael@0 88 // class has one or more methods that need to operate on all of these fields.
michael@0 89 // Writing these individually is error-prone -- it's easy to add a new field
michael@0 90 // without updating all the required methods. So we define a single macro list
michael@0 91 // in each class to name the fields (and notable characteristics of them), and
michael@0 92 // then use the following macros to transform those lists into the required
michael@0 93 // methods.
michael@0 94 //
michael@0 95 // In some classes, one or more of the macro arguments aren't used. We use '_'
michael@0 96 // for those.
michael@0 97 //
michael@0 98 #define DECL_SIZE(kind, gc, mSize) size_t mSize;
michael@0 99 #define ZERO_SIZE(kind, gc, mSize) mSize(0),
michael@0 100 #define COPY_OTHER_SIZE(kind, gc, mSize) mSize(other.mSize),
michael@0 101 #define ADD_OTHER_SIZE(kind, gc, mSize) mSize += other.mSize;
michael@0 102 #define SUB_OTHER_SIZE(kind, gc, mSize) MOZ_ASSERT(mSize >= other.mSize); \
michael@0 103 mSize -= other.mSize;
michael@0 104 #define ADD_SIZE_TO_N(kind, gc, mSize) n += mSize;
michael@0 105 #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc) ? mSize : 0;
michael@0 106 #define ADD_TO_TAB_SIZES(kind, gc, mSize) sizes->add(JS::TabSizes::kind, mSize);
michael@0 107
michael@0 108 // Used to annotate which size_t fields measure live GC things and which don't.
michael@0 109 enum {
michael@0 110 NotLiveGCThing = false,
michael@0 111 IsLiveGCThing = true
michael@0 112 };
michael@0 113
michael@0 114 } // namespace js
michael@0 115
michael@0 116 namespace JS {
michael@0 117
michael@0 118 // Data for tracking memory usage of things hanging off objects.
michael@0 119 struct ObjectsExtraSizes
michael@0 120 {
michael@0 121 #define FOR_EACH_SIZE(macro) \
michael@0 122 macro(Objects, NotLiveGCThing, mallocHeapSlots) \
michael@0 123 macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
michael@0 124 macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
michael@0 125 macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
michael@0 126 macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
michael@0 127 macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
michael@0 128 macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
michael@0 129 macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
michael@0 130 macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
michael@0 131 macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
michael@0 132 macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
michael@0 133
michael@0 134 ObjectsExtraSizes()
michael@0 135 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 136 dummy()
michael@0 137 {}
michael@0 138
michael@0 139 void add(const ObjectsExtraSizes &other) {
michael@0 140 FOR_EACH_SIZE(ADD_OTHER_SIZE)
michael@0 141 }
michael@0 142
michael@0 143 size_t sizeOfLiveGCThings() const {
michael@0 144 size_t n = 0;
michael@0 145 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
michael@0 146 return n;
michael@0 147 }
michael@0 148
michael@0 149 void addToTabSizes(TabSizes *sizes) const {
michael@0 150 FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
michael@0 151 }
michael@0 152
michael@0 153 FOR_EACH_SIZE(DECL_SIZE)
michael@0 154 int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
michael@0 155
michael@0 156 #undef FOR_EACH_SIZE
michael@0 157 };
michael@0 158
michael@0 159 // Data for tracking JIT-code memory usage.
michael@0 160 struct CodeSizes
michael@0 161 {
michael@0 162 #define FOR_EACH_SIZE(macro) \
michael@0 163 macro(_, _, ion) \
michael@0 164 macro(_, _, baseline) \
michael@0 165 macro(_, _, regexp) \
michael@0 166 macro(_, _, other) \
michael@0 167 macro(_, _, unused)
michael@0 168
michael@0 169 CodeSizes()
michael@0 170 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 171 dummy()
michael@0 172 {}
michael@0 173
michael@0 174 FOR_EACH_SIZE(DECL_SIZE)
michael@0 175 int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
michael@0 176
michael@0 177 #undef FOR_EACH_SIZE
michael@0 178 };
michael@0 179
michael@0 180 // Data for tracking GC memory usage.
michael@0 181 struct GCSizes
michael@0 182 {
michael@0 183 #define FOR_EACH_SIZE(macro) \
michael@0 184 macro(_, _, marker) \
michael@0 185 macro(_, _, nurseryCommitted) \
michael@0 186 macro(_, _, nurseryDecommitted) \
michael@0 187 macro(_, _, nurseryHugeSlots) \
michael@0 188 macro(_, _, storeBufferVals) \
michael@0 189 macro(_, _, storeBufferCells) \
michael@0 190 macro(_, _, storeBufferSlots) \
michael@0 191 macro(_, _, storeBufferWholeCells) \
michael@0 192 macro(_, _, storeBufferRelocVals) \
michael@0 193 macro(_, _, storeBufferRelocCells) \
michael@0 194 macro(_, _, storeBufferGenerics)
michael@0 195
michael@0 196 GCSizes()
michael@0 197 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 198 dummy()
michael@0 199 {}
michael@0 200
michael@0 201 FOR_EACH_SIZE(DECL_SIZE)
michael@0 202 int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
michael@0 203
michael@0 204 #undef FOR_EACH_SIZE
michael@0 205 };
michael@0 206
michael@0 207 // This class holds information about the memory taken up by identical copies of
michael@0 208 // a particular string. Multiple JSStrings may have their sizes aggregated
michael@0 209 // together into one StringInfo object. Note that two strings with identical
michael@0 210 // chars will not be aggregated together if one is a short string and the other
michael@0 211 // is not.
michael@0 212 struct StringInfo
michael@0 213 {
michael@0 214 #define FOR_EACH_SIZE(macro) \
michael@0 215 macro(Strings, IsLiveGCThing, gcHeap) \
michael@0 216 macro(Strings, NotLiveGCThing, mallocHeap) \
michael@0 217
michael@0 218 StringInfo()
michael@0 219 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 220 numCopies(0)
michael@0 221 {}
michael@0 222
michael@0 223 void add(const StringInfo &other) {
michael@0 224 FOR_EACH_SIZE(ADD_OTHER_SIZE);
michael@0 225 numCopies++;
michael@0 226 }
michael@0 227
michael@0 228 void subtract(const StringInfo &other) {
michael@0 229 FOR_EACH_SIZE(SUB_OTHER_SIZE);
michael@0 230 numCopies--;
michael@0 231 }
michael@0 232
michael@0 233 bool isNotable() const {
michael@0 234 static const size_t NotabilityThreshold = 16 * 1024;
michael@0 235 size_t n = 0;
michael@0 236 FOR_EACH_SIZE(ADD_SIZE_TO_N)
michael@0 237 return n >= NotabilityThreshold;
michael@0 238 }
michael@0 239
michael@0 240 size_t sizeOfLiveGCThings() const {
michael@0 241 size_t n = 0;
michael@0 242 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
michael@0 243 return n;
michael@0 244 }
michael@0 245
michael@0 246 void addToTabSizes(TabSizes *sizes) const {
michael@0 247 FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
michael@0 248 }
michael@0 249
michael@0 250 FOR_EACH_SIZE(DECL_SIZE)
michael@0 251 uint32_t numCopies; // How many copies of the string have we seen?
michael@0 252
michael@0 253 #undef FOR_EACH_SIZE
michael@0 254 };
michael@0 255
michael@0 256 // Holds data about a notable string (one which, counting all duplicates, uses
michael@0 257 // more than a certain amount of memory) so we can report it individually.
michael@0 258 //
michael@0 259 // The only difference between this class and StringInfo is that
michael@0 260 // NotableStringInfo holds a copy of some or all of the string's chars.
michael@0 261 struct NotableStringInfo : public StringInfo
michael@0 262 {
michael@0 263 static const size_t MAX_SAVED_CHARS = 1024;
michael@0 264
michael@0 265 NotableStringInfo();
michael@0 266 NotableStringInfo(JSString *str, const StringInfo &info);
michael@0 267 NotableStringInfo(NotableStringInfo &&info);
michael@0 268 NotableStringInfo &operator=(NotableStringInfo &&info);
michael@0 269
michael@0 270 ~NotableStringInfo() {
michael@0 271 js_free(buffer);
michael@0 272 }
michael@0 273
michael@0 274 char *buffer;
michael@0 275 size_t length;
michael@0 276
michael@0 277 private:
michael@0 278 NotableStringInfo(const NotableStringInfo& info) MOZ_DELETE;
michael@0 279 };
michael@0 280
michael@0 281 // This class holds information about the memory taken up by script sources
michael@0 282 // from a particular file.
michael@0 283 struct ScriptSourceInfo
michael@0 284 {
michael@0 285 #define FOR_EACH_SIZE(macro) \
michael@0 286 macro(_, _, compressed) \
michael@0 287 macro(_, _, uncompressed) \
michael@0 288 macro(_, _, misc)
michael@0 289
michael@0 290 ScriptSourceInfo()
michael@0 291 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 292 numScripts(0)
michael@0 293 {}
michael@0 294
michael@0 295 void add(const ScriptSourceInfo &other) {
michael@0 296 FOR_EACH_SIZE(ADD_OTHER_SIZE)
michael@0 297 numScripts++;
michael@0 298 }
michael@0 299
michael@0 300 void subtract(const ScriptSourceInfo &other) {
michael@0 301 FOR_EACH_SIZE(SUB_OTHER_SIZE)
michael@0 302 numScripts--;
michael@0 303 }
michael@0 304
michael@0 305 bool isNotable() const {
michael@0 306 static const size_t NotabilityThreshold = 16 * 1024;
michael@0 307 size_t n = 0;
michael@0 308 FOR_EACH_SIZE(ADD_SIZE_TO_N)
michael@0 309 return n >= NotabilityThreshold;
michael@0 310 }
michael@0 311
michael@0 312 FOR_EACH_SIZE(DECL_SIZE)
michael@0 313 uint32_t numScripts; // How many ScriptSources come from this file? (It
michael@0 314 // can be more than one in XML files that have
michael@0 315 // multiple scripts in CDATA sections.)
michael@0 316 #undef FOR_EACH_SIZE
michael@0 317 };
michael@0 318
michael@0 319 // Holds data about a notable script source file (one whose combined
michael@0 320 // script sources use more than a certain amount of memory) so we can report it
michael@0 321 // individually.
michael@0 322 //
michael@0 323 // The only difference between this class and ScriptSourceInfo is that this
michael@0 324 // class holds a copy of the filename.
michael@0 325 struct NotableScriptSourceInfo : public ScriptSourceInfo
michael@0 326 {
michael@0 327 NotableScriptSourceInfo();
michael@0 328 NotableScriptSourceInfo(const char *filename, const ScriptSourceInfo &info);
michael@0 329 NotableScriptSourceInfo(NotableScriptSourceInfo &&info);
michael@0 330 NotableScriptSourceInfo &operator=(NotableScriptSourceInfo &&info);
michael@0 331
michael@0 332 ~NotableScriptSourceInfo() {
michael@0 333 js_free(filename_);
michael@0 334 }
michael@0 335
michael@0 336 char *filename_;
michael@0 337
michael@0 338 private:
michael@0 339 NotableScriptSourceInfo(const NotableScriptSourceInfo& info) MOZ_DELETE;
michael@0 340 };
michael@0 341
michael@0 342 // These measurements relate directly to the JSRuntime, and not to zones and
michael@0 343 // compartments within it.
michael@0 344 struct RuntimeSizes
michael@0 345 {
michael@0 346 #define FOR_EACH_SIZE(macro) \
michael@0 347 macro(_, _, object) \
michael@0 348 macro(_, _, atomsTable) \
michael@0 349 macro(_, _, contexts) \
michael@0 350 macro(_, _, dtoa) \
michael@0 351 macro(_, _, temporary) \
michael@0 352 macro(_, _, regexpData) \
michael@0 353 macro(_, _, interpreterStack) \
michael@0 354 macro(_, _, mathCache) \
michael@0 355 macro(_, _, sourceDataCache) \
michael@0 356 macro(_, _, scriptData) \
michael@0 357
michael@0 358 RuntimeSizes()
michael@0 359 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 360 scriptSourceInfo(),
michael@0 361 code(),
michael@0 362 gc(),
michael@0 363 notableScriptSources()
michael@0 364 {
michael@0 365 allScriptSources = js_new<ScriptSourcesHashMap>();
michael@0 366 if (!allScriptSources || !allScriptSources->init())
michael@0 367 MOZ_CRASH("oom");
michael@0 368 }
michael@0 369
michael@0 370 ~RuntimeSizes() {
michael@0 371 // |allScriptSources| is usually deleted and set to nullptr before this
michael@0 372 // destructor runs. But there are failure cases due to OOMs that may
michael@0 373 // prevent that, so it doesn't hurt to try again here.
michael@0 374 js_delete(allScriptSources);
michael@0 375 }
michael@0 376
michael@0 377 // The script source measurements in |scriptSourceInfo| are initially for
michael@0 378 // all script sources. At the end, if the measurement granularity is
michael@0 379 // FineGrained, we subtract the measurements of the notable script sources
michael@0 380 // and move them into |notableScriptSources|.
michael@0 381 FOR_EACH_SIZE(DECL_SIZE)
michael@0 382 ScriptSourceInfo scriptSourceInfo;
michael@0 383 CodeSizes code;
michael@0 384 GCSizes gc;
michael@0 385
michael@0 386 typedef js::HashMap<const char*, ScriptSourceInfo,
michael@0 387 js::CStringHashPolicy,
michael@0 388 js::SystemAllocPolicy> ScriptSourcesHashMap;
michael@0 389
michael@0 390 // |allScriptSources| is only used transiently. During the reporting phase
michael@0 391 // it is filled with info about every script source in the runtime. It's
michael@0 392 // then used to fill in |notableScriptSources| (which actually gets
michael@0 393 // reported), and immediately discarded afterwards.
michael@0 394 ScriptSourcesHashMap *allScriptSources;
michael@0 395 js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> notableScriptSources;
michael@0 396
michael@0 397 #undef FOR_EACH_SIZE
michael@0 398 };
michael@0 399
michael@0 400 struct ZoneStats
michael@0 401 {
michael@0 402 #define FOR_EACH_SIZE(macro) \
michael@0 403 macro(Other, NotLiveGCThing, gcHeapArenaAdmin) \
michael@0 404 macro(Other, NotLiveGCThing, unusedGCThings) \
michael@0 405 macro(Other, IsLiveGCThing, lazyScriptsGCHeap) \
michael@0 406 macro(Other, NotLiveGCThing, lazyScriptsMallocHeap) \
michael@0 407 macro(Other, IsLiveGCThing, jitCodesGCHeap) \
michael@0 408 macro(Other, IsLiveGCThing, typeObjectsGCHeap) \
michael@0 409 macro(Other, NotLiveGCThing, typeObjectsMallocHeap) \
michael@0 410 macro(Other, NotLiveGCThing, typePool) \
michael@0 411 macro(Other, NotLiveGCThing, baselineStubsOptimized) \
michael@0 412
michael@0 413 ZoneStats()
michael@0 414 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 415 stringInfo(),
michael@0 416 extra(),
michael@0 417 allStrings(nullptr),
michael@0 418 notableStrings(),
michael@0 419 isTotals(true)
michael@0 420 {}
michael@0 421
michael@0 422 ZoneStats(ZoneStats &&other)
michael@0 423 : FOR_EACH_SIZE(COPY_OTHER_SIZE)
michael@0 424 stringInfo(mozilla::Move(other.stringInfo)),
michael@0 425 extra(other.extra),
michael@0 426 allStrings(other.allStrings),
michael@0 427 notableStrings(mozilla::Move(other.notableStrings)),
michael@0 428 isTotals(other.isTotals)
michael@0 429 {
michael@0 430 other.allStrings = nullptr;
michael@0 431 MOZ_ASSERT(!other.isTotals);
michael@0 432 }
michael@0 433
michael@0 434 ~ZoneStats() {
michael@0 435 // |allStrings| is usually deleted and set to nullptr before this
michael@0 436 // destructor runs. But there are failure cases due to OOMs that may
michael@0 437 // prevent that, so it doesn't hurt to try again here.
michael@0 438 js_delete(allStrings);
michael@0 439 }
michael@0 440
michael@0 441 bool initStrings(JSRuntime *rt);
michael@0 442
michael@0 443 void addSizes(const ZoneStats &other) {
michael@0 444 MOZ_ASSERT(isTotals);
michael@0 445 FOR_EACH_SIZE(ADD_OTHER_SIZE)
michael@0 446 stringInfo.add(other.stringInfo);
michael@0 447 }
michael@0 448
michael@0 449 size_t sizeOfLiveGCThings() const {
michael@0 450 MOZ_ASSERT(isTotals);
michael@0 451 size_t n = 0;
michael@0 452 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
michael@0 453 n += stringInfo.sizeOfLiveGCThings();
michael@0 454 return n;
michael@0 455 }
michael@0 456
michael@0 457 void addToTabSizes(JS::TabSizes *sizes) const {
michael@0 458 MOZ_ASSERT(isTotals);
michael@0 459 FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
michael@0 460 stringInfo.addToTabSizes(sizes);
michael@0 461 }
michael@0 462
michael@0 463 // These string measurements are initially for all strings. At the end,
michael@0 464 // if the measurement granularity is FineGrained, we subtract the
michael@0 465 // measurements of the notable script sources and move them into
michael@0 466 // |notableStrings|.
michael@0 467 FOR_EACH_SIZE(DECL_SIZE)
michael@0 468 StringInfo stringInfo;
michael@0 469 void *extra; // This field can be used by embedders.
michael@0 470
michael@0 471 typedef js::HashMap<JSString*, StringInfo,
michael@0 472 js::InefficientNonFlatteningStringHashPolicy,
michael@0 473 js::SystemAllocPolicy> StringsHashMap;
michael@0 474
michael@0 475 // |allStrings| is only used transiently. During the zone traversal it is
michael@0 476 // filled with info about every string in the zone. It's then used to fill
michael@0 477 // in |notableStrings| (which actually gets reported), and immediately
michael@0 478 // discarded afterwards.
michael@0 479 StringsHashMap *allStrings;
michael@0 480 js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
michael@0 481 bool isTotals;
michael@0 482
michael@0 483 #undef FOR_EACH_SIZE
michael@0 484 };
michael@0 485
michael@0 486 struct CompartmentStats
michael@0 487 {
michael@0 488 #define FOR_EACH_SIZE(macro) \
michael@0 489 macro(Objects, IsLiveGCThing, objectsGCHeapOrdinary) \
michael@0 490 macro(Objects, IsLiveGCThing, objectsGCHeapFunction) \
michael@0 491 macro(Objects, IsLiveGCThing, objectsGCHeapDenseArray) \
michael@0 492 macro(Objects, IsLiveGCThing, objectsGCHeapSlowArray) \
michael@0 493 macro(Objects, IsLiveGCThing, objectsGCHeapCrossCompartmentWrapper) \
michael@0 494 macro(Private, NotLiveGCThing, objectsPrivate) \
michael@0 495 macro(Other, IsLiveGCThing, shapesGCHeapTreeGlobalParented) \
michael@0 496 macro(Other, IsLiveGCThing, shapesGCHeapTreeNonGlobalParented) \
michael@0 497 macro(Other, IsLiveGCThing, shapesGCHeapDict) \
michael@0 498 macro(Other, IsLiveGCThing, shapesGCHeapBase) \
michael@0 499 macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
michael@0 500 macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
michael@0 501 macro(Other, NotLiveGCThing, shapesMallocHeapTreeShapeKids) \
michael@0 502 macro(Other, NotLiveGCThing, shapesMallocHeapCompartmentTables) \
michael@0 503 macro(Other, IsLiveGCThing, scriptsGCHeap) \
michael@0 504 macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
michael@0 505 macro(Other, NotLiveGCThing, baselineData) \
michael@0 506 macro(Other, NotLiveGCThing, baselineStubsFallback) \
michael@0 507 macro(Other, NotLiveGCThing, ionData) \
michael@0 508 macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \
michael@0 509 macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \
michael@0 510 macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
michael@0 511 macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \
michael@0 512 macro(Other, NotLiveGCThing, compartmentObject) \
michael@0 513 macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
michael@0 514 macro(Other, NotLiveGCThing, regexpCompartment) \
michael@0 515 macro(Other, NotLiveGCThing, debuggeesSet) \
michael@0 516 macro(Other, NotLiveGCThing, savedStacksSet)
michael@0 517
michael@0 518 CompartmentStats()
michael@0 519 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 520 objectsExtra(),
michael@0 521 extra()
michael@0 522 {}
michael@0 523
michael@0 524 CompartmentStats(const CompartmentStats &other)
michael@0 525 : FOR_EACH_SIZE(COPY_OTHER_SIZE)
michael@0 526 objectsExtra(other.objectsExtra),
michael@0 527 extra(other.extra)
michael@0 528 {}
michael@0 529
michael@0 530 void add(const CompartmentStats &other) {
michael@0 531 FOR_EACH_SIZE(ADD_OTHER_SIZE)
michael@0 532 objectsExtra.add(other.objectsExtra);
michael@0 533 // Do nothing with |extra|.
michael@0 534 }
michael@0 535
michael@0 536 size_t sizeOfLiveGCThings() const {
michael@0 537 size_t n = 0;
michael@0 538 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
michael@0 539 n += objectsExtra.sizeOfLiveGCThings();
michael@0 540 // Do nothing with |extra|.
michael@0 541 return n;
michael@0 542 }
michael@0 543
michael@0 544 void addToTabSizes(TabSizes *sizes) const {
michael@0 545 FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
michael@0 546 objectsExtra.addToTabSizes(sizes);
michael@0 547 // Do nothing with |extra|.
michael@0 548 }
michael@0 549
michael@0 550 FOR_EACH_SIZE(DECL_SIZE)
michael@0 551 ObjectsExtraSizes objectsExtra;
michael@0 552 void *extra; // This field can be used by embedders.
michael@0 553
michael@0 554 #undef FOR_EACH_SIZE
michael@0 555 };
michael@0 556
michael@0 557 typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
michael@0 558 typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
michael@0 559
michael@0 560 struct RuntimeStats
michael@0 561 {
michael@0 562 #define FOR_EACH_SIZE(macro) \
michael@0 563 macro(_, _, gcHeapChunkTotal) \
michael@0 564 macro(_, _, gcHeapDecommittedArenas) \
michael@0 565 macro(_, _, gcHeapUnusedChunks) \
michael@0 566 macro(_, _, gcHeapUnusedArenas) \
michael@0 567 macro(_, _, gcHeapChunkAdmin) \
michael@0 568 macro(_, _, gcHeapGCThings) \
michael@0 569
michael@0 570 RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
michael@0 571 : FOR_EACH_SIZE(ZERO_SIZE)
michael@0 572 runtime(),
michael@0 573 cTotals(),
michael@0 574 zTotals(),
michael@0 575 compartmentStatsVector(),
michael@0 576 zoneStatsVector(),
michael@0 577 currZoneStats(nullptr),
michael@0 578 mallocSizeOf_(mallocSizeOf)
michael@0 579 {}
michael@0 580
michael@0 581 // Here's a useful breakdown of the GC heap.
michael@0 582 //
michael@0 583 // - rtStats.gcHeapChunkTotal
michael@0 584 // - decommitted bytes
michael@0 585 // - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks)
michael@0 586 // - unused bytes
michael@0 587 // - rtStats.gcHeapUnusedChunks (empty chunks)
michael@0 588 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
michael@0 589 // - rtStats.zTotals.unusedGCThings (empty GC thing slots within non-empty arenas)
michael@0 590 // - used bytes
michael@0 591 // - rtStats.gcHeapChunkAdmin
michael@0 592 // - rtStats.zTotals.gcHeapArenaAdmin
michael@0 593 // - rtStats.gcHeapGCThings (in-use GC things)
michael@0 594 // == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings()
michael@0 595 //
michael@0 596 // It's possible that some arenas in empty chunks may be decommitted, but
michael@0 597 // we don't count those under rtStats.gcHeapDecommittedArenas because (a)
michael@0 598 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
michael@0 599 // multiple of the chunk size, which is good.
michael@0 600
michael@0 601 FOR_EACH_SIZE(DECL_SIZE)
michael@0 602
michael@0 603 RuntimeSizes runtime;
michael@0 604
michael@0 605 CompartmentStats cTotals; // The sum of this runtime's compartments' measurements.
michael@0 606 ZoneStats zTotals; // The sum of this runtime's zones' measurements.
michael@0 607
michael@0 608 CompartmentStatsVector compartmentStatsVector;
michael@0 609 ZoneStatsVector zoneStatsVector;
michael@0 610
michael@0 611 ZoneStats *currZoneStats;
michael@0 612
michael@0 613 mozilla::MallocSizeOf mallocSizeOf_;
michael@0 614
michael@0 615 virtual void initExtraCompartmentStats(JSCompartment *c, CompartmentStats *cstats) = 0;
michael@0 616 virtual void initExtraZoneStats(JS::Zone *zone, ZoneStats *zstats) = 0;
michael@0 617
michael@0 618 #undef FOR_EACH_SIZE
michael@0 619 };
michael@0 620
michael@0 621 class ObjectPrivateVisitor
michael@0 622 {
michael@0 623 public:
michael@0 624 // Within CollectRuntimeStats, this method is called for each JS object
michael@0 625 // that has an nsISupports pointer.
michael@0 626 virtual size_t sizeOfIncludingThis(nsISupports *aSupports) = 0;
michael@0 627
michael@0 628 // A callback that gets a JSObject's nsISupports pointer, if it has one.
michael@0 629 // Note: this function does *not* addref |iface|.
michael@0 630 typedef bool(*GetISupportsFun)(JSObject *obj, nsISupports **iface);
michael@0 631 GetISupportsFun getISupports_;
michael@0 632
michael@0 633 ObjectPrivateVisitor(GetISupportsFun getISupports)
michael@0 634 : getISupports_(getISupports)
michael@0 635 {}
michael@0 636 };
michael@0 637
michael@0 638 extern JS_PUBLIC_API(bool)
michael@0 639 CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv);
michael@0 640
michael@0 641 extern JS_PUBLIC_API(size_t)
michael@0 642 SystemCompartmentCount(JSRuntime *rt);
michael@0 643
michael@0 644 extern JS_PUBLIC_API(size_t)
michael@0 645 UserCompartmentCount(JSRuntime *rt);
michael@0 646
michael@0 647 extern JS_PUBLIC_API(size_t)
michael@0 648 PeakSizeOfTemporary(const JSRuntime *rt);
michael@0 649
michael@0 650 extern JS_PUBLIC_API(bool)
michael@0 651 AddSizeOfTab(JSRuntime *rt, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
michael@0 652 ObjectPrivateVisitor *opv, TabSizes *sizes);
michael@0 653
michael@0 654 } // namespace JS
michael@0 655
michael@0 656 #undef DECL_SIZE
michael@0 657 #undef ZERO_SIZE
michael@0 658 #undef COPY_OTHER_SIZE
michael@0 659 #undef ADD_OTHER_SIZE
michael@0 660 #undef SUB_OTHER_SIZE
michael@0 661 #undef ADD_SIZE_TO_N
michael@0 662 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
michael@0 663 #undef ADD_TO_TAB_SIZES
michael@0 664
michael@0 665 #endif /* js_MemoryMetrics_h */

mercurial