1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99 ft=cpp:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 #include "jsgcstats.h"
44 #include "jsbuiltins.h"
45 #include "jscompartment.h"
48 using namespace js::gc
;
50 #define UL(x) ((unsigned long)(x))
51 #define PERCENT(x,y) (100.0 * (double) (x) / (double) (y))
56 #if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
59 ConservativeGCStats::dump(FILE *fp
)
62 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(counter
); ++i
)
65 #define ULSTAT(x) ((unsigned long)(x))
66 fprintf(fp
, "CONSERVATIVE STACK SCANNING:\n");
67 fprintf(fp
, " number of stack words: %lu\n", ULSTAT(words
));
68 fprintf(fp
, " excluded, low bit set: %lu\n", ULSTAT(counter
[CGCT_LOWBITSET
]));
69 fprintf(fp
, " not withing a chunk: %lu\n", ULSTAT(counter
[CGCT_NOTCHUNK
]));
70 fprintf(fp
, " not within arena range: %lu\n", ULSTAT(counter
[CGCT_NOTARENA
]));
71 fprintf(fp
, " points to free arena: %lu\n", ULSTAT(counter
[CGCT_FREEARENA
]));
72 fprintf(fp
, " excluded, wrong tag: %lu\n", ULSTAT(counter
[CGCT_WRONGTAG
]));
73 fprintf(fp
, " excluded, not live: %lu\n", ULSTAT(counter
[CGCT_NOTLIVE
]));
74 fprintf(fp
, " valid GC things: %lu\n", ULSTAT(counter
[CGCT_VALID
]));
75 fprintf(fp
, " valid but not aligned: %lu\n", ULSTAT(counter
[CGCT_VALIDWITHOFFSET
]));
82 UpdateCompartmentStats(JSCompartment
*comp
, unsigned thingKind
, uint32 nlivearenas
,
83 uint32 nkilledArenas
, uint32 nthings
)
86 JSGCArenaStats
*compSt
= &comp
->compartmentStats
[thingKind
];
87 JSGCArenaStats
*globSt
= &comp
->rt
->globalArenaStats
[thingKind
];
88 narenas
= nlivearenas
+ nkilledArenas
;
89 JS_ASSERT(narenas
>= compSt
->livearenas
);
91 compSt
->newarenas
= narenas
- compSt
->livearenas
;
92 compSt
->narenas
= narenas
;
93 compSt
->livearenas
= nlivearenas
;
94 if (compSt
->maxarenas
< narenas
)
95 compSt
->maxarenas
= narenas
;
96 compSt
->totalarenas
+= narenas
;
98 compSt
->nthings
= nthings
;
99 if (compSt
->maxthings
< nthings
)
100 compSt
->maxthings
= nthings
;
101 compSt
->totalthings
+= nthings
;
102 globSt
->newarenas
+= compSt
->newarenas
;
103 globSt
->narenas
+= narenas
;
104 globSt
->livearenas
+= compSt
->livearenas
;
105 globSt
->totalarenas
+= compSt
->totalarenas
;
106 globSt
->nthings
+= compSt
->nthings
;
107 globSt
->totalthings
+= compSt
->totalthings
;
108 if (globSt
->maxarenas
< compSt
->maxarenas
)
109 globSt
->maxarenas
= compSt
->maxarenas
;
110 if (globSt
->maxthings
< compSt
->maxthings
)
111 globSt
->maxthings
= compSt
->maxthings
;
114 static const char *const GC_ARENA_NAMES
[] = {
122 #if JS_HAS_XML_SUPPORT
129 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES
) == FINALIZE_LIMIT
);
131 template <typename T
>
133 GetSizeAndThings(size_t &thingSize
, size_t &thingsPerArena
)
135 thingSize
= sizeof(T
);
136 thingsPerArena
= Arena
<T
>::ThingsPerArena
;
139 #if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
141 GetAlignedThing(void *thing
, int thingKind
)
143 Cell
*cell
= (Cell
*)thing
;
145 case FINALIZE_OBJECT0
:
146 return (void *)GetArena
<JSObject
>(cell
)->getAlignedThing(thing
);
147 case FINALIZE_OBJECT2
:
148 return (void *)GetArena
<JSObject_Slots2
>(cell
)->getAlignedThing(thing
);
149 case FINALIZE_OBJECT4
:
150 return (void *)GetArena
<JSObject_Slots4
>(cell
)->getAlignedThing(thing
);
151 case FINALIZE_OBJECT8
:
152 return (void *)GetArena
<JSObject_Slots8
>(cell
)->getAlignedThing(thing
);
153 case FINALIZE_OBJECT12
:
154 return (void *)GetArena
<JSObject_Slots12
>(cell
)->getAlignedThing(thing
);
155 case FINALIZE_OBJECT16
:
156 return (void *)GetArena
<JSObject_Slots16
>(cell
)->getAlignedThing(thing
);
157 case FINALIZE_STRING
:
158 return (void *)GetArena
<JSString
>(cell
)->getAlignedThing(thing
);
159 case FINALIZE_EXTERNAL_STRING
:
160 return (void *)GetArena
<JSExternalString
>(cell
)->getAlignedThing(thing
);
161 case FINALIZE_SHORT_STRING
:
162 return (void *)GetArena
<JSShortString
>(cell
)->getAlignedThing(thing
);
163 case FINALIZE_FUNCTION
:
164 return (void *)GetArena
<JSFunction
>(cell
)->getAlignedThing(thing
);
165 #if JS_HAS_XML_SUPPORT
167 return (void *)GetArena
<JSXML
>(cell
)->getAlignedThing(thing
);
176 void GetSizeAndThingsPerArena(int thingKind
, size_t &thingSize
, size_t &thingsPerArena
)
179 case FINALIZE_OBJECT0
:
180 GetSizeAndThings
<JSObject
>(thingSize
, thingsPerArena
);
182 case FINALIZE_OBJECT2
:
183 GetSizeAndThings
<JSObject_Slots2
>(thingSize
, thingsPerArena
);
185 case FINALIZE_OBJECT4
:
186 GetSizeAndThings
<JSObject_Slots4
>(thingSize
, thingsPerArena
);
188 case FINALIZE_OBJECT8
:
189 GetSizeAndThings
<JSObject_Slots8
>(thingSize
, thingsPerArena
);
191 case FINALIZE_OBJECT12
:
192 GetSizeAndThings
<JSObject_Slots12
>(thingSize
, thingsPerArena
);
194 case FINALIZE_OBJECT16
:
195 GetSizeAndThings
<JSObject_Slots16
>(thingSize
, thingsPerArena
);
197 case FINALIZE_EXTERNAL_STRING
:
198 case FINALIZE_STRING
:
199 GetSizeAndThings
<JSString
>(thingSize
, thingsPerArena
);
201 case FINALIZE_SHORT_STRING
:
202 GetSizeAndThings
<JSShortString
>(thingSize
, thingsPerArena
);
204 case FINALIZE_FUNCTION
:
205 GetSizeAndThings
<JSFunction
>(thingSize
, thingsPerArena
);
207 #if JS_HAS_XML_SUPPORT
209 GetSizeAndThings
<JSXML
>(thingSize
, thingsPerArena
);
218 DumpArenaStats(JSGCArenaStats
*stp
, FILE *fp
)
220 size_t sumArenas
= 0, sumTotalArenas
= 0, sumThings
=0, sumMaxThings
= 0;
221 size_t sumThingSize
= 0, sumTotalThingSize
= 0, sumArenaCapacity
= 0;
222 size_t sumTotalArenaCapacity
= 0, sumAlloc
= 0, sumLocalAlloc
= 0;
224 for (int i
= 0; i
< (int) FINALIZE_LIMIT
; i
++) {
225 JSGCArenaStats
*st
= &stp
[i
];
226 if (st
->maxarenas
== 0)
228 size_t thingSize
= 0, thingsPerArena
= 0;
229 GetSizeAndThingsPerArena(i
, thingSize
, thingsPerArena
);
231 fprintf(fp
, "%s arenas (thing size %lu, %lu things per arena):\n",
232 GC_ARENA_NAMES
[i
], UL(thingSize
), UL(thingsPerArena
));
233 fprintf(fp
, " arenas before GC: %lu\n", UL(st
->narenas
));
234 fprintf(fp
, " arenas after GC: %lu (%.1f%%)\n",
235 UL(st
->livearenas
), PERCENT(st
->livearenas
, st
->narenas
));
236 fprintf(fp
, " max arenas: %lu\n", UL(st
->maxarenas
));
237 fprintf(fp
, " things: %lu\n", UL(st
->nthings
));
238 fprintf(fp
, " GC cell utilization: %.1f%%\n",
239 PERCENT(st
->nthings
, thingsPerArena
* st
->narenas
));
240 fprintf(fp
, " average cell utilization: %.1f%%\n",
241 PERCENT(st
->totalthings
, thingsPerArena
* st
->totalarenas
));
242 fprintf(fp
, " max things: %lu\n", UL(st
->maxthings
));
243 fprintf(fp
, " alloc attempts: %lu\n", UL(st
->alloc
));
244 fprintf(fp
, " alloc without locks: %lu (%.1f%%)\n",
245 UL(st
->localalloc
), PERCENT(st
->localalloc
, st
->alloc
));
246 sumArenas
+= st
->narenas
;
247 sumTotalArenas
+= st
->totalarenas
;
248 sumThings
+= st
->nthings
;
249 sumMaxThings
+= st
->maxthings
;
250 sumThingSize
+= thingSize
* st
->nthings
;
251 sumTotalThingSize
+= size_t(thingSize
* st
->totalthings
);
252 sumArenaCapacity
+= thingSize
* thingsPerArena
* st
->narenas
;
253 sumTotalArenaCapacity
+= thingSize
* thingsPerArena
* st
->totalarenas
;
254 sumAlloc
+= st
->alloc
;
255 sumLocalAlloc
+= st
->localalloc
;
259 fputs("Never used arenas:\n", fp
);
260 for (int i
= 0; i
< (int) FINALIZE_LIMIT
; i
++) {
261 JSGCArenaStats
*st
= &stp
[i
];
262 if (st
->maxarenas
!= 0)
264 fprintf(fp
, "%s\n", GC_ARENA_NAMES
[i
]);
266 fprintf(fp
, "\nTOTAL STATS:\n");
267 fprintf(fp
, " total GC arenas: %lu\n", UL(sumArenas
));
268 fprintf(fp
, " total GC things: %lu\n", UL(sumThings
));
269 fprintf(fp
, " max total GC things: %lu\n", UL(sumMaxThings
));
270 fprintf(fp
, " GC cell utilization: %.1f%%\n",
271 PERCENT(sumThingSize
, sumArenaCapacity
));
272 fprintf(fp
, " average cell utilization: %.1f%%\n",
273 PERCENT(sumTotalThingSize
, sumTotalArenaCapacity
));
274 fprintf(fp
, " alloc attempts: %lu\n", UL(sumAlloc
));
275 fprintf(fp
, " alloc without locks: %lu (%.1f%%)\n",
276 UL(sumLocalAlloc
), PERCENT(sumLocalAlloc
, sumAlloc
));
280 DumpCompartmentStats(JSCompartment
*comp
, FILE *fp
)
282 if (comp
->rt
->atomsCompartment
== comp
)
283 fprintf(fp
, "\n**** AtomsCompartment Allocation Statistics: %p ****\n\n", (void *) comp
);
285 fprintf(fp
, "\n**** Compartment Allocation Statistics: %p ****\n\n", (void *) comp
);
287 DumpArenaStats(&comp
->compartmentStats
[0], fp
);
298 js_DumpGCStats(JSRuntime
*rt
, FILE *fp
)
300 #define ULSTAT(x) UL(rt->gcStats.x)
301 if (JS_WANT_GC_METER_PRINT
) {
302 fprintf(fp
, "\n**** Global Arena Allocation Statistics: ****\n");
303 DumpArenaStats(&rt
->globalArenaStats
[0], fp
);
304 fprintf(fp
, " bytes allocated: %lu\n", UL(rt
->gcBytes
));
305 fprintf(fp
, " allocation failures: %lu\n", ULSTAT(fail
));
306 fprintf(fp
, " last ditch GC runs: %lu\n", ULSTAT(lastditch
));
307 fprintf(fp
, " valid lock calls: %lu\n", ULSTAT(lock
));
308 fprintf(fp
, " valid unlock calls: %lu\n", ULSTAT(unlock
));
309 fprintf(fp
, " delayed tracing calls: %lu\n", ULSTAT(unmarked
));
311 fprintf(fp
, " max trace later count: %lu\n", ULSTAT(maxunmarked
));
313 fprintf(fp
, "potentially useful GC calls: %lu\n", ULSTAT(poke
));
314 fprintf(fp
, " thing arenas freed so far: %lu\n\n", ULSTAT(afree
));
317 if (JS_WANT_GC_PER_COMPARTMENT_PRINT
)
318 for (JSCompartment
**c
= rt
->compartments
.begin(); c
!= rt
->compartments
.end(); ++c
)
319 DumpCompartmentStats(*c
, fp
);
320 PodZero(&rt
->globalArenaStats
);
321 if (JS_WANT_CONSERVATIVE_GC_PRINT
)
322 rt
->gcStats
.conservative
.dump(fp
);
329 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
331 GCMarker::dumpConservativeRoots()
333 if (!conservativeDumpFileName
)
337 if (!strcmp(conservativeDumpFileName
, "stdout")) {
339 } else if (!strcmp(conservativeDumpFileName
, "stderr")) {
341 } else if (!(fp
= fopen(conservativeDumpFileName
, "aw"))) {
343 "Warning: cannot open %s to dump the conservative roots\n",
344 conservativeDumpFileName
);
348 conservativeStats
.dump(fp
);
350 for (ConservativeRoot
*i
= conservativeRoots
.begin();
351 i
!= conservativeRoots
.end();
353 fprintf(fp
, " %p: ", i
->thing
);
354 switch (GetFinalizableTraceKind(i
->thingKind
)) {
356 JS_NOT_REACHED("Unknown trace kind");
358 case JSTRACE_OBJECT
: {
359 JSObject
*obj
= (JSObject
*) i
->thing
;
360 fprintf(fp
, "object %s", obj
->getClass()->name
);
363 case JSTRACE_STRING
: {
364 JSString
*str
= (JSString
*) i
->thing
;
365 if (str
->isLinear()) {
367 PutEscapedString(buf
, sizeof buf
, str
->assertIsLinear(), '"');
368 fprintf(fp
, "string %s", buf
);
370 fprintf(fp
, "rope: length %d", (int)str
->length());
374 # if JS_HAS_XML_SUPPORT
376 JSXML
*xml
= (JSXML
*) i
->thing
;
377 fprintf(fp
, "xml %u", (unsigned)xml
->xml_class
);
386 if (fp
!= stdout
&& fp
!= stderr
)
389 #endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */
393 jsrefcount newChunkCount
= 0;
394 jsrefcount destroyChunkCount
= 0;
398 memset(this, 0, sizeof(GCTimer
));
403 GCTimer::getFirstEnter() {
404 static uint64 firstEnter
= rdtsc();
409 GCTimer::finish(bool lastGC
) {
413 if (JS_WANT_GC_SUITE_PRINT
) {
414 fprintf(stderr
, "%f %f %f\n",
415 (double)(end
- enter
) / 1e6
,
416 (double)(startSweep
- startMark
) / 1e6
,
417 (double)(sweepDestroyEnd
- startSweep
) / 1e6
);
422 gcFile
= fopen("gcTimer.dat", "a");
424 fprintf(gcFile
, " AppTime, Total, Mark, Sweep, FinObj,");
425 fprintf(gcFile
, " FinStr, Destroy, newChunks, destroyChunks\n");
428 fprintf(gcFile
, "%12.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %7.1f, ",
429 (double)(enter
- getFirstEnter()) / 1e6
,
430 (double)(end
- enter
) / 1e6
,
431 (double)(startSweep
- startMark
) / 1e6
,
432 (double)(sweepDestroyEnd
- startSweep
) / 1e6
,
433 (double)(sweepObjectEnd
- startSweep
) / 1e6
,
434 (double)(sweepStringEnd
- sweepObjectEnd
) / 1e6
,
435 (double)(sweepDestroyEnd
- sweepStringEnd
) / 1e6
);
436 fprintf(gcFile
, "%10d, %10d \n", newChunkCount
,
447 destroyChunkCount
= 0;