|
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/. */ |
|
6 |
|
7 #include "nsISupports.idl" |
|
8 |
|
9 interface nsIDOMWindow; |
|
10 interface nsIRunnable; |
|
11 interface nsISimpleEnumerator; |
|
12 |
|
13 /* |
|
14 * Memory reporters measure Firefox's memory usage. They are primarily used to |
|
15 * generate the about:memory page. You should read |
|
16 * https://wiki.mozilla.org/Memory_Reporting before writing a memory |
|
17 * reporter. |
|
18 */ |
|
19 |
|
20 [scriptable, function, uuid(3a61be3b-b93b-461a-a4f8-388214f558b1)] |
|
21 interface nsIMemoryReporterCallback : nsISupports |
|
22 { |
|
23 /* |
|
24 * The arguments to the callback are as follows. |
|
25 * |
|
26 * |
|
27 * |process| The name of the process containing this reporter. Each |
|
28 * reporter initially has "" in this field, indicating that it applies to the |
|
29 * current process. (This is true even for reporters in a child process.) |
|
30 * When a reporter from a child process is copied into the main process, the |
|
31 * copy has its 'process' field set appropriately. |
|
32 * |
|
33 * |
|
34 * |path| The path that this memory usage should be reported under. Paths |
|
35 * are '/'-delimited, eg. "a/b/c". |
|
36 * |
|
37 * Each reporter can be viewed as representing a leaf node in a tree. |
|
38 * Internal nodes of the tree don't have reporters. So, for example, the |
|
39 * reporters "explicit/a/b", "explicit/a/c", "explicit/d/e", and |
|
40 * "explicit/d/f" define this tree: |
|
41 * |
|
42 * explicit |
|
43 * |--a |
|
44 * | |--b [*] |
|
45 * | \--c [*] |
|
46 * \--d |
|
47 * |--e [*] |
|
48 * \--f [*] |
|
49 * |
|
50 * Nodes marked with a [*] have a reporter. Notice that the internal |
|
51 * nodes are implicitly defined by the paths. |
|
52 * |
|
53 * Nodes within a tree should not overlap measurements, otherwise the |
|
54 * parent node measurements will be double-counted. So in the example |
|
55 * above, |b| should not count any allocations counted by |c|, and vice |
|
56 * versa. |
|
57 * |
|
58 * All nodes within each tree must have the same units. |
|
59 * |
|
60 * If you want to include a '/' not as a path separator, e.g. because the |
|
61 * path contains a URL, you need to convert each '/' in the URL to a '\'. |
|
62 * Consumers of the path will undo this change. Any other '\' character |
|
63 * in a path will also be changed. This is clumsy but hasn't caused any |
|
64 * problems so far. |
|
65 * |
|
66 * The paths of all reporters form a set of trees. Trees can be |
|
67 * "degenerate", i.e. contain a single entry with no '/'. |
|
68 * |
|
69 * |
|
70 * |kind| There are three kinds of memory reporters. |
|
71 * |
|
72 * - HEAP: reporters measuring memory allocated by the heap allocator, |
|
73 * e.g. by calling malloc, calloc, realloc, memalign, operator new, or |
|
74 * operator new[]. Reporters in this category must have units |
|
75 * UNITS_BYTES. |
|
76 * |
|
77 * - NONHEAP: reporters measuring memory which the program explicitly |
|
78 * allocated, but does not live on the heap. Such memory is commonly |
|
79 * allocated by calling one of the OS's memory-mapping functions (e.g. |
|
80 * mmap, VirtualAlloc, or vm_allocate). Reporters in this category |
|
81 * must have units UNITS_BYTES. |
|
82 * |
|
83 * - OTHER: reporters which don't fit into either of these categories. |
|
84 * They can have any units. |
|
85 * |
|
86 * The kind only matters for reporters in the "explicit" tree; |
|
87 * aboutMemory.js uses it to calculate "heap-unclassified". |
|
88 * |
|
89 * |
|
90 * |units| The units on the reporter's amount. One of the following. |
|
91 * |
|
92 * - BYTES: The amount contains a number of bytes. |
|
93 * |
|
94 * - COUNT: The amount is an instantaneous count of things currently in |
|
95 * existence. For instance, the number of tabs currently open would have |
|
96 * units COUNT. |
|
97 * |
|
98 * - COUNT_CUMULATIVE: The amount contains the number of times some event |
|
99 * has occurred since the application started up. For instance, the |
|
100 * number of times the user has opened a new tab would have units |
|
101 * COUNT_CUMULATIVE. |
|
102 * |
|
103 * The amount returned by a reporter with units COUNT_CUMULATIVE must |
|
104 * never decrease over the lifetime of the application. |
|
105 * |
|
106 * - PERCENTAGE: The amount contains a fraction that should be expressed as |
|
107 * a percentage. NOTE! The |amount| field should be given a value 100x |
|
108 * the actual percentage; this number will be divided by 100 when shown. |
|
109 * This allows a fractional percentage to be shown even though |amount| is |
|
110 * an integer. E.g. if the actual percentage is 12.34%, |amount| should |
|
111 * be 1234. |
|
112 * |
|
113 * Values greater than 100% are allowed. |
|
114 * |
|
115 * |
|
116 * |amount| The numeric value reported by this memory reporter. Accesses |
|
117 * can fail if something goes wrong when getting the amount. |
|
118 * |
|
119 * |
|
120 * |description| A human-readable description of this memory usage report. |
|
121 */ |
|
122 void callback(in ACString process, in AUTF8String path, in int32_t kind, |
|
123 in int32_t units, in int64_t amount, |
|
124 in AUTF8String description, in nsISupports data); |
|
125 }; |
|
126 |
|
127 /* |
|
128 * An nsIMemoryReporter reports one or more memory measurements via a |
|
129 * callback function which is called once for each measurement. |
|
130 * |
|
131 * An nsIMemoryReporter that reports a single measurement is sometimes called a |
|
132 * "uni-reporter". One that reports multiple measurements is sometimes called |
|
133 * a "multi-reporter". |
|
134 * |
|
135 * aboutMemory.js is the most important consumer of memory reports. It |
|
136 * places the following constraints on reports. |
|
137 * |
|
138 * - All reports within a single sub-tree must have the same units. |
|
139 * |
|
140 * - There may be an "explicit" tree. If present, it represents |
|
141 * non-overlapping regions of memory that have been explicitly allocated with |
|
142 * an OS-level allocation (e.g. mmap/VirtualAlloc/vm_allocate) or a |
|
143 * heap-level allocation (e.g. malloc/calloc/operator new). Reporters in |
|
144 * this tree must have kind HEAP or NONHEAP, units BYTES. |
|
145 * |
|
146 * It is preferred, but not required, that report descriptions use complete |
|
147 * sentences (i.e. start with a capital letter and end with a period, or |
|
148 * similar). |
|
149 */ |
|
150 [scriptable, uuid(0884cd0f-5829-4381-979b-0f53904030ed)] |
|
151 interface nsIMemoryReporter : nsISupports |
|
152 { |
|
153 /* |
|
154 * Run the reporter. |
|
155 */ |
|
156 void collectReports(in nsIMemoryReporterCallback callback, |
|
157 in nsISupports data); |
|
158 |
|
159 /* |
|
160 * Kinds. See the |kind| comment in nsIMemoryReporterCallback. |
|
161 */ |
|
162 const int32_t KIND_NONHEAP = 0; |
|
163 const int32_t KIND_HEAP = 1; |
|
164 const int32_t KIND_OTHER = 2; |
|
165 |
|
166 /* |
|
167 * Units. See the |units| comment in nsIMemoryReporterCallback. |
|
168 */ |
|
169 const int32_t UNITS_BYTES = 0; |
|
170 const int32_t UNITS_COUNT = 1; |
|
171 const int32_t UNITS_COUNT_CUMULATIVE = 2; |
|
172 const int32_t UNITS_PERCENTAGE = 3; |
|
173 }; |
|
174 |
|
175 [scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)] |
|
176 interface nsIFinishReportingCallback : nsISupports |
|
177 { |
|
178 void callback(in nsISupports data); |
|
179 }; |
|
180 |
|
181 [scriptable, builtinclass, uuid(b6e5ec8a-71d9-48db-8ae9-68b4c5bbf2c3)] |
|
182 interface nsIMemoryReporterManager : nsISupports |
|
183 { |
|
184 /* |
|
185 * Initialize. |
|
186 */ |
|
187 void init(); |
|
188 |
|
189 /* |
|
190 * Register the given nsIMemoryReporter. The Manager service will hold a |
|
191 * strong reference to the given reporter, and will be responsible for freeing |
|
192 * the reporter at shutdown. You may manually unregister the reporter with |
|
193 * unregisterStrongReporter() at any point. |
|
194 */ |
|
195 void registerStrongReporter(in nsIMemoryReporter reporter); |
|
196 |
|
197 /* |
|
198 * Like registerReporter, but the Manager service will hold a weak reference |
|
199 * via a raw pointer to the given reporter. The reporter should be |
|
200 * unregistered before shutdown. |
|
201 * You cannot register JavaScript components with this function! Always |
|
202 * register your JavaScript components with registerStrongReporter(). |
|
203 */ |
|
204 void registerWeakReporter(in nsIMemoryReporter reporter); |
|
205 |
|
206 /* |
|
207 * Unregister the given memory reporter, which must have been registered with |
|
208 * registerStrongReporter(). You normally don't need to unregister your |
|
209 * strong reporters, as nsIMemoryReporterManager will take care of that at |
|
210 * shutdown. |
|
211 */ |
|
212 void unregisterStrongReporter(in nsIMemoryReporter reporter); |
|
213 |
|
214 /* |
|
215 * Unregister the given memory reporter, which must have been registered with |
|
216 * registerWeakReporter(). |
|
217 */ |
|
218 void unregisterWeakReporter(in nsIMemoryReporter reporter); |
|
219 |
|
220 /* |
|
221 * These functions should only be used for testing purposes. |
|
222 */ |
|
223 void blockRegistrationAndHideExistingReporters(); |
|
224 void unblockRegistrationAndRestoreOriginalReporters(); |
|
225 void registerStrongReporterEvenIfBlocked(in nsIMemoryReporter aReporter); |
|
226 |
|
227 /* |
|
228 * Get memory reports for the current process and all child processes. |
|
229 * |handleReport| is called for each report, and |finishReporting| is called |
|
230 * once all reports have been handled. |
|
231 * |
|
232 * |finishReporting| is called even if, for example, some child processes |
|
233 * fail to report back. However, calls to this method will silently and |
|
234 * immediately abort -- and |finishReporting| will not be called -- if a |
|
235 * previous getReports() call is still in flight, i.e. if it has not yet |
|
236 * finished invoking |finishReporting|. The silent abort is because the |
|
237 * in-flight request will finish soon, and the caller would very likely just |
|
238 * catch and ignore any error anyway. |
|
239 */ |
|
240 void getReports(in nsIMemoryReporterCallback handleReport, |
|
241 in nsISupports handleReportData, |
|
242 in nsIFinishReportingCallback finishReporting, |
|
243 in nsISupports finishReportingData); |
|
244 |
|
245 /* |
|
246 * As above, but: If |minimizeMemoryUsage| is true, then each process will |
|
247 * minimize its memory usage (see the |minimizeMemoryUsage| method) before |
|
248 * gathering its report. If DMD is enabled and |DMDDumpIdent| is non-empty |
|
249 * then write a DMD report to a file in the usual temporary directory (see |
|
250 * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.) |
|
251 */ |
|
252 [noscript] void |
|
253 getReportsExtended(in nsIMemoryReporterCallback handleReport, |
|
254 in nsISupports handleReportData, |
|
255 in nsIFinishReportingCallback finishReporting, |
|
256 in nsISupports finishReportingData, |
|
257 in boolean minimizeMemoryUsage, |
|
258 in AString DMDDumpIdent); |
|
259 |
|
260 /* |
|
261 * Get memory reports in the current process only. |handleReport| is called |
|
262 * for each report. |
|
263 */ |
|
264 void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport, |
|
265 in nsISupports handleReportData); |
|
266 |
|
267 /* |
|
268 * As above, but if DMD is enabled and |DMDDumpIdent| is non-empty |
|
269 * then write a DMD report to a file in the usual temporary directory (see |
|
270 * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.) |
|
271 */ |
|
272 [noscript] void |
|
273 getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport, |
|
274 in nsISupports handleReportData, |
|
275 in AString DMDDumpIdent); |
|
276 |
|
277 /* |
|
278 * The memory reporter manager, for the most part, treats reporters |
|
279 * registered with it as a black box. However, there are some |
|
280 * "distinguished" amounts (as could be reported by a memory reporter) that |
|
281 * the manager provides as attributes, because they are sufficiently |
|
282 * interesting that we want external code (e.g. telemetry) to be able to rely |
|
283 * on them. |
|
284 * |
|
285 * Note that these are not reporters and so getReports() and |
|
286 * getReportsForThisProcess() do not look at them. However, distinguished |
|
287 * amounts can be embedded in a reporter. |
|
288 * |
|
289 * Access to these attributes can fail. In particular, some of them are not |
|
290 * available on all platforms. |
|
291 * |
|
292 * If you add a new distinguished amount, please update |
|
293 * toolkit/components/aboutmemory/tests/test_memoryReporters.xul. |
|
294 * |
|
295 * |explicit| (UNITS_BYTES) The total size of explicit memory allocations, |
|
296 * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level |
|
297 * (eg. via malloc, calloc, operator new). It covers all heap allocations, |
|
298 * but will miss any OS-level ones not covered by memory reporters. |
|
299 * |
|
300 * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space |
|
301 * taken up. |
|
302 * |
|
303 * |vsizeMaxContiguous| (UNITS_BYTES) The size of the largest contiguous |
|
304 * block of virtual memory. |
|
305 * |
|
306 * |resident| (UNITS_BYTES) The resident size (a.k.a. RSS or physical memory |
|
307 * used). |
|
308 * |
|
309 * |residentFast| (UNITS_BYTES) This is like |resident|, but on Mac OS |
|
310 * |resident| can purge pages, which is slow. It also affects the result of |
|
311 * |residentFast|, and so |resident| and |residentFast| should not be used |
|
312 * together. |
|
313 * |
|
314 * |heapAllocated| (UNITS_BYTES) Memory mapped by the heap allocator. |
|
315 * |
|
316 * |heapOverheadRatio| (UNITS_PERCENTAGE) In the heap allocator, this is the |
|
317 * ratio of committed, unused bytes to allocated bytes. Like all |
|
318 * UNITS_PERCENTAGE measurements, its amount is multiplied by 100x so it can |
|
319 * be represented by an int64_t. |
|
320 * |
|
321 * |JSMainRuntimeGCHeap| (UNITS_BYTES) Size of the main JS runtime's GC |
|
322 * heap. |
|
323 * |
|
324 * |JSMainRuntimeTemporaryPeak| (UNITS_BYTES) Peak size of the transient |
|
325 * storage in the main JSRuntime. |
|
326 * |
|
327 * |JSMainRuntimeCompartments{System,User}| (UNITS_COUNT) The number of |
|
328 * {system,user} compartments in the main JS runtime. |
|
329 * |
|
330 * |imagesContentUsedUncompressed| (UNITS_BYTES) Memory used for decoded |
|
331 * images in content. |
|
332 * |
|
333 * |storageSQLite| (UNITS_BYTES) Memory used by SQLite. |
|
334 * |
|
335 * |lowMemoryEvents{Virtual,Physical}| (UNITS_COUNT_CUMULATIVE) The number |
|
336 * of low-{virtual,physical}-memory events that have occurred since the |
|
337 * process started. |
|
338 * |
|
339 * |ghostWindows| (UNITS_COUNT) The number of ghost windows. |
|
340 * |
|
341 * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. |
|
342 * major) page faults that have occurred since the process started. |
|
343 */ |
|
344 readonly attribute int64_t explicit; |
|
345 readonly attribute int64_t vsize; |
|
346 readonly attribute int64_t vsizeMaxContiguous; |
|
347 readonly attribute int64_t resident; |
|
348 readonly attribute int64_t residentFast; |
|
349 |
|
350 readonly attribute int64_t heapAllocated; |
|
351 readonly attribute int64_t heapOverheadRatio; |
|
352 |
|
353 readonly attribute int64_t JSMainRuntimeGCHeap; |
|
354 readonly attribute int64_t JSMainRuntimeTemporaryPeak; |
|
355 readonly attribute int64_t JSMainRuntimeCompartmentsSystem; |
|
356 readonly attribute int64_t JSMainRuntimeCompartmentsUser; |
|
357 |
|
358 readonly attribute int64_t imagesContentUsedUncompressed; |
|
359 |
|
360 readonly attribute int64_t storageSQLite; |
|
361 |
|
362 readonly attribute int64_t lowMemoryEventsVirtual; |
|
363 readonly attribute int64_t lowMemoryEventsPhysical; |
|
364 |
|
365 readonly attribute int64_t ghostWindows; |
|
366 |
|
367 readonly attribute int64_t pageFaultsHard; |
|
368 |
|
369 /* |
|
370 * This attribute indicates if moz_malloc_usable_size() works. |
|
371 */ |
|
372 [infallible] readonly attribute boolean hasMozMallocUsableSize; |
|
373 |
|
374 /* |
|
375 * Run a series of GC/CC's in an attempt to minimize the application's memory |
|
376 * usage. When we're finished, we invoke the given runnable if it's not |
|
377 * null. |
|
378 */ |
|
379 void minimizeMemoryUsage(in nsIRunnable callback); |
|
380 |
|
381 /* |
|
382 * Measure the memory that is known to be owned by this tab, split up into |
|
383 * several broad categories. Note that this will be an underestimate of the |
|
384 * true number, due to imperfect memory reporter coverage (corresponding to |
|
385 * about:memory's "heap-unclassified"), and due to some memory shared between |
|
386 * tabs not being counted. |
|
387 * |
|
388 * The time taken for the measurement (split into JS and non-JS parts) is |
|
389 * also returned. |
|
390 */ |
|
391 void sizeOfTab(in nsIDOMWindow window, |
|
392 out int64_t jsObjectsSize, out int64_t jsStringsSize, |
|
393 out int64_t jsOtherSize, out int64_t domSize, |
|
394 out int64_t styleSize, out int64_t otherSize, |
|
395 out int64_t totalSize, |
|
396 out double jsMilliseconds, out double nonJSMilliseconds); |
|
397 }; |
|
398 |
|
399 %{C++ |
|
400 |
|
401 #include "js/TypeDecls.h" |
|
402 #include "nsStringGlue.h" |
|
403 #include "nsTArray.h" |
|
404 #include "mozilla/Atomics.h" |
|
405 |
|
406 class nsPIDOMWindow; |
|
407 |
|
408 // nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback |
|
409 // around for backwards compatibility. |
|
410 typedef nsIMemoryReporterCallback nsIHandleReportCallback; |
|
411 |
|
412 namespace mozilla { |
|
413 |
|
414 // Register a memory reporter. The manager service will hold a strong |
|
415 // reference to this reporter. |
|
416 XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); |
|
417 |
|
418 // Register a memory reporter. The manager service will hold a weak reference |
|
419 // to this reporter. |
|
420 XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); |
|
421 |
|
422 // Unregister a weak memory reporter. |
|
423 XPCOM_API(nsresult) UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter); |
|
424 |
|
425 // The memory reporter manager provides access to several distinguished |
|
426 // amounts via attributes. Some of these amounts are provided by Gecko |
|
427 // components that cannot be accessed directly from XPCOM code. So we provide |
|
428 // the following functions for those components to be registered with the |
|
429 // manager. |
|
430 |
|
431 typedef int64_t (*InfallibleAmountFn)(); |
|
432 typedef nsresult (*FallibleAmountFn)(int64_t* aAmount); |
|
433 |
|
434 #define DECL_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \ |
|
435 nsresult Register##name##DistinguishedAmount(kind##AmountFn aAmountFn); |
|
436 #define DECL_UNREGISTER_DISTINGUISHED_AMOUNT(name) \ |
|
437 nsresult Unregister##name##DistinguishedAmount(); |
|
438 |
|
439 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap) |
|
440 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak) |
|
441 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem) |
|
442 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser) |
|
443 |
|
444 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed) |
|
445 |
|
446 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite) |
|
447 DECL_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite) |
|
448 |
|
449 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual) |
|
450 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical) |
|
451 |
|
452 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows) |
|
453 |
|
454 #undef DECL_REGISTER_DISTINGUISHED_AMOUNT |
|
455 #undef DECL_UNREGISTER_DISTINGUISHED_AMOUNT |
|
456 |
|
457 // Likewise for per-tab measurement. |
|
458 |
|
459 typedef nsresult (*JSSizeOfTabFn)(JSObject* aObj, |
|
460 size_t* aJsObjectsSize, |
|
461 size_t* aJsStringSize, |
|
462 size_t* aJsPrivateSize, |
|
463 size_t* aJsOtherSize); |
|
464 typedef nsresult (*NonJSSizeOfTabFn)(nsPIDOMWindow* aWindow, |
|
465 size_t* aDomSize, |
|
466 size_t* aStyleSize, |
|
467 size_t* aOtherSize); |
|
468 |
|
469 nsresult RegisterJSSizeOfTab(JSSizeOfTabFn aSizeOfTabFn); |
|
470 nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); |
|
471 |
|
472 } |
|
473 |
|
474 #if defined(MOZ_DMD) |
|
475 namespace mozilla { |
|
476 namespace dmd { |
|
477 // This runs all the memory reporters in the current process but does nothing |
|
478 // with the results; i.e. it does the minimal amount of work possible for DMD |
|
479 // to do its thing. It does nothing with child processes. |
|
480 void RunReportersForThisProcess(); |
|
481 } |
|
482 } |
|
483 |
|
484 #if !defined(MOZ_MEMORY) |
|
485 #error "MOZ_DMD requires MOZ_MEMORY" |
|
486 #endif |
|
487 |
|
488 #include "DMD.h" |
|
489 |
|
490 #define MOZ_REPORT(ptr) mozilla::dmd::Report(ptr) |
|
491 #define MOZ_REPORT_ON_ALLOC(ptr) mozilla::dmd::ReportOnAlloc(ptr) |
|
492 |
|
493 #else |
|
494 |
|
495 #define MOZ_REPORT(ptr) |
|
496 #define MOZ_REPORT_ON_ALLOC(ptr) |
|
497 |
|
498 #endif // defined(MOZ_DMD) |
|
499 |
|
500 // Functions generated via this macro should be used by all traversal-based |
|
501 // memory reporters. Such functions return |moz_malloc_size_of(ptr)|; this |
|
502 // will always be zero on some obscure platforms. |
|
503 // |
|
504 // You might be wondering why we have a macro that creates multiple functions |
|
505 // that differ only in their name, instead of a single MallocSizeOf function. |
|
506 // It's mostly to help with DMD integration, though it sometimes also helps |
|
507 // with debugging and temporary ad hoc profiling. The function name chosen |
|
508 // doesn't matter greatly, but it's best to make it similar to the path used by |
|
509 // the relevant memory reporter(s). |
|
510 #define MOZ_DEFINE_MALLOC_SIZE_OF(fn) \ |
|
511 static size_t fn(const void* aPtr) \ |
|
512 { \ |
|
513 MOZ_REPORT(aPtr); \ |
|
514 return moz_malloc_size_of(aPtr); \ |
|
515 } |
|
516 |
|
517 // Functions generated by the next two macros should be used by wrapping |
|
518 // allocators that report heap blocks as soon as they are allocated and |
|
519 // unreport them as soon as they are freed. Such allocators are used in cases |
|
520 // where we have third-party code that we cannot modify. The two functions |
|
521 // must always be used in tandem. |
|
522 #define MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(fn) \ |
|
523 static size_t fn(const void* aPtr) \ |
|
524 { \ |
|
525 MOZ_REPORT_ON_ALLOC(aPtr); \ |
|
526 return moz_malloc_size_of(aPtr); \ |
|
527 } |
|
528 #define MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(fn) \ |
|
529 static size_t fn(const void* aPtr) \ |
|
530 { \ |
|
531 return moz_malloc_size_of(aPtr); \ |
|
532 } |
|
533 |
|
534 namespace mozilla { |
|
535 |
|
536 // This CRTP class handles several details of wrapping allocators and should |
|
537 // be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC |
|
538 // and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE. The typical use is in a memory |
|
539 // reporter for a particular third party library: |
|
540 // |
|
541 // class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter> |
|
542 // { |
|
543 // ... |
|
544 // NS_IMETHODIMP |
|
545 // CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData) |
|
546 // { |
|
547 // return MOZ_COLLECT_REPORTER( |
|
548 // "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES, |
|
549 // MemoryAllocated(), |
|
550 // "A description of what we are reporting." |
|
551 // } |
|
552 // }; |
|
553 // |
|
554 // ...somewhere later in the code... |
|
555 // SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc, |
|
556 // MyMemoryReporter::CountingFree); |
|
557 template<typename T> |
|
558 class CountingAllocatorBase |
|
559 { |
|
560 public: |
|
561 CountingAllocatorBase() |
|
562 { |
|
563 #ifdef DEBUG |
|
564 // There must be only one instance of this class, due to |sAmount| being |
|
565 // static. |
|
566 static bool hasRun = false; |
|
567 MOZ_ASSERT(!hasRun); |
|
568 hasRun = true; |
|
569 #endif |
|
570 } |
|
571 |
|
572 static size_t |
|
573 MemoryAllocated() |
|
574 { |
|
575 return sAmount; |
|
576 } |
|
577 |
|
578 static void* |
|
579 CountingMalloc(size_t size) |
|
580 { |
|
581 void* p = malloc(size); |
|
582 sAmount += MallocSizeOfOnAlloc(p); |
|
583 return p; |
|
584 } |
|
585 |
|
586 static void* |
|
587 CountingCalloc(size_t nmemb, size_t size) |
|
588 { |
|
589 void* p = calloc(nmemb, size); |
|
590 sAmount += MallocSizeOfOnAlloc(p); |
|
591 return p; |
|
592 } |
|
593 |
|
594 static void* |
|
595 CountingRealloc(void* p, size_t size) |
|
596 { |
|
597 size_t oldsize = MallocSizeOfOnFree(p); |
|
598 void *pnew = realloc(p, size); |
|
599 if (pnew) { |
|
600 size_t newsize = MallocSizeOfOnAlloc(pnew); |
|
601 sAmount += newsize - oldsize; |
|
602 } else if (size == 0) { |
|
603 // We asked for a 0-sized (re)allocation of some existing pointer |
|
604 // and received NULL in return. 0-sized allocations are permitted |
|
605 // to either return NULL or to allocate a unique object per call (!). |
|
606 // For a malloc implementation that chooses the second strategy, |
|
607 // that allocation may fail (unlikely, but possible). |
|
608 // |
|
609 // Given a NULL return value and an allocation size of 0, then, we |
|
610 // don't know if that means the original pointer was freed or if |
|
611 // the allocation of the unique object failed. If the original |
|
612 // pointer was freed, then we have nothing to do here. If the |
|
613 // allocation of the unique object failed, the original pointer is |
|
614 // still valid and we ought to undo the decrement from above. |
|
615 // However, we have no way of knowing how the underlying realloc |
|
616 // implementation is behaving. Assuming that the original pointer |
|
617 // was freed is the safest course of action. We do, however, need |
|
618 // to note that we freed memory. |
|
619 sAmount -= oldsize; |
|
620 } else { |
|
621 // realloc failed. The amount allocated hasn't changed. |
|
622 } |
|
623 return pnew; |
|
624 } |
|
625 |
|
626 static void |
|
627 CountingFree(void* p) |
|
628 { |
|
629 sAmount -= MallocSizeOfOnFree(p); |
|
630 free(p); |
|
631 } |
|
632 |
|
633 private: |
|
634 // |sAmount| can be (implicitly) accessed by multiple threads, so it |
|
635 // must be thread-safe. |
|
636 static Atomic<size_t> sAmount; |
|
637 |
|
638 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc) |
|
639 MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree) |
|
640 }; |
|
641 |
|
642 } |
|
643 |
|
644 // This macro assumes the presence of appropriate |aHandleReport| and |aData| |
|
645 // variables. |
|
646 #define MOZ_COLLECT_REPORT(path, kind, units, amount, description) \ |
|
647 aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(path), \ |
|
648 kind, units, amount, \ |
|
649 NS_LITERAL_CSTRING(description), aData) |
|
650 |
|
651 %} |