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"
48 #if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
51 ConservativeGCStats::dump(FILE *fp
)
54 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(counter
); ++i
)
57 #define ULSTAT(x) ((unsigned long)(x))
58 fprintf(fp
, "CONSERVATIVE STACK SCANNING:\n");
59 fprintf(fp
, " number of stack words: %lu\n", ULSTAT(words
));
60 fprintf(fp
, " excluded, low bit set: %lu\n", ULSTAT(counter
[CGCT_LOWBITSET
]));
61 fprintf(fp
, " not withing a chunk: %lu\n", ULSTAT(counter
[CGCT_NOTCHUNK
]));
62 fprintf(fp
, " not within arena range: %lu\n", ULSTAT(counter
[CGCT_NOTARENA
]));
63 fprintf(fp
, " points to free arena: %lu\n", ULSTAT(counter
[CGCT_FREEARENA
]));
64 fprintf(fp
, " excluded, wrong tag: %lu\n", ULSTAT(counter
[CGCT_WRONGTAG
]));
65 fprintf(fp
, " excluded, not live: %lu\n", ULSTAT(counter
[CGCT_NOTLIVE
]));
66 fprintf(fp
, " valid GC things: %lu\n", ULSTAT(counter
[CGCT_VALID
]));
71 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
73 GCMarker::dumpConservativeRoots()
75 if (!conservativeDumpFileName
)
79 if (!strcmp(conservativeDumpFileName
, "stdout")) {
81 } else if (!strcmp(conservativeDumpFileName
, "stderr")) {
83 } else if (!(fp
= fopen(conservativeDumpFileName
, "aw"))) {
85 "Warning: cannot open %s to dump the conservative roots\n",
86 conservativeDumpFileName
);
90 conservativeStats
.dump(fp
);
92 for (ConservativeRoot
*i
= conservativeRoots
.begin();
93 i
!= conservativeRoots
.end();
95 fprintf(fp
, " %p: ", i
->thing
);
96 switch (i
->traceKind
) {
98 JS_NOT_REACHED("Unknown trace kind");
100 case JSTRACE_OBJECT
: {
101 JSObject
*obj
= (JSObject
*) i
->thing
;
102 fprintf(fp
, "object %s", obj
->getClass()->name
);
105 case JSTRACE_STRING
: {
106 JSString
*str
= (JSString
*) i
->thing
;
108 js_PutEscapedString(buf
, sizeof buf
, str
, '"');
109 fprintf(fp
, "string %s", buf
);
112 # if JS_HAS_XML_SUPPORT
114 JSXML
*xml
= (JSXML
*) i
->thing
;
115 fprintf(fp
, "xml %u", (unsigned)xml
->xml_class
);
124 if (fp
!= stdout
&& fp
!= stderr
)
127 #endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */
132 UpdateArenaStats(JSGCArenaStats
*st
, uint32 nlivearenas
, uint32 nkilledArenas
,
137 narenas
= nlivearenas
+ nkilledArenas
;
138 JS_ASSERT(narenas
>= st
->livearenas
);
140 st
->newarenas
= narenas
- st
->livearenas
;
141 st
->narenas
= narenas
;
142 st
->livearenas
= nlivearenas
;
143 if (st
->maxarenas
< narenas
)
144 st
->maxarenas
= narenas
;
145 st
->totalarenas
+= narenas
;
147 st
->nthings
= nthings
;
148 if (st
->maxthings
< nthings
)
149 st
->maxthings
= nthings
;
150 st
->totalthings
+= nthings
;
154 js_DumpGCStats(JSRuntime
*rt
, FILE *fp
)
156 static const char *const GC_ARENA_NAMES
[] = {
159 #if JS_HAS_XML_SUPPORT
174 fprintf(fp
, "\nGC allocation statistics:\n\n");
176 #define UL(x) ((unsigned long)(x))
177 #define ULSTAT(x) UL(rt->gcStats.x)
178 #define PERCENT(x,y) (100.0 * (double) (x) / (double) (y))
180 size_t sumArenas
= 0;
181 size_t sumTotalArenas
= 0;
182 size_t sumThings
= 0;
183 size_t sumMaxThings
= 0;
184 size_t sumThingSize
= 0;
185 size_t sumTotalThingSize
= 0;
186 size_t sumArenaCapacity
= 0;
187 size_t sumTotalArenaCapacity
= 0;
189 size_t sumLocalAlloc
= 0;
192 for (int i
= 0; i
< (int) FINALIZE_LIMIT
; i
++) {
193 size_t thingSize
, thingsPerArena
;
195 thingSize
= rt
->gcArenaList
[i
].thingSize
;
196 thingsPerArena
= ThingsPerArena(thingSize
);
197 st
= &rt
->gcArenaStats
[i
];
198 if (st
->maxarenas
== 0)
201 "%s arenas (thing size %lu, %lu things per arena):",
202 GC_ARENA_NAMES
[i
], UL(thingSize
), UL(thingsPerArena
));
204 fprintf(fp
, " arenas before GC: %lu\n", UL(st
->narenas
));
205 fprintf(fp
, " new arenas before GC: %lu (%.1f%%)\n",
206 UL(st
->newarenas
), PERCENT(st
->newarenas
, st
->narenas
));
207 fprintf(fp
, " arenas after GC: %lu (%.1f%%)\n",
208 UL(st
->livearenas
), PERCENT(st
->livearenas
, st
->narenas
));
209 fprintf(fp
, " max arenas: %lu\n", UL(st
->maxarenas
));
210 fprintf(fp
, " things: %lu\n", UL(st
->nthings
));
211 fprintf(fp
, " GC cell utilization: %.1f%%\n",
212 PERCENT(st
->nthings
, thingsPerArena
* st
->narenas
));
213 fprintf(fp
, " average cell utilization: %.1f%%\n",
214 PERCENT(st
->totalthings
, thingsPerArena
* st
->totalarenas
));
215 fprintf(fp
, " max things: %lu\n", UL(st
->maxthings
));
216 fprintf(fp
, " alloc attempts: %lu\n", UL(st
->alloc
));
217 fprintf(fp
, " alloc without locks: %lu (%.1f%%)\n",
218 UL(st
->localalloc
), PERCENT(st
->localalloc
, st
->alloc
));
219 sumArenas
+= st
->narenas
;
220 sumTotalArenas
+= st
->totalarenas
;
221 sumThings
+= st
->nthings
;
222 sumMaxThings
+= st
->maxthings
;
223 sumThingSize
+= thingSize
* st
->nthings
;
224 sumTotalThingSize
+= size_t(thingSize
* st
->totalthings
);
225 sumArenaCapacity
+= thingSize
* thingsPerArena
* st
->narenas
;
226 sumTotalArenaCapacity
+= thingSize
* thingsPerArena
* st
->totalarenas
;
227 sumAlloc
+= st
->alloc
;
228 sumLocalAlloc
+= st
->localalloc
;
230 sumRetry
+= st
->retry
;
234 fputs("Never used arenas:\n", fp
);
235 for (int i
= 0; i
< (int) FINALIZE_LIMIT
; i
++) {
236 size_t thingSize
, thingsPerArena
;
238 thingSize
= rt
->gcArenaList
[i
].thingSize
;
239 thingsPerArena
= ThingsPerArena(thingSize
);
240 st
= &rt
->gcArenaStats
[i
];
241 if (st
->maxarenas
!= 0)
244 "%s (thing size %lu, %lu things per arena)\n",
245 GC_ARENA_NAMES
[i
], UL(thingSize
), UL(thingsPerArena
));
247 fprintf(fp
, "\nTOTAL STATS:\n");
248 fprintf(fp
, " bytes allocated: %lu\n", UL(rt
->gcBytes
));
249 fprintf(fp
, " total GC arenas: %lu\n", UL(sumArenas
));
250 fprintf(fp
, " max allocated arenas: %lu\n", ULSTAT(maxnallarenas
));
251 fprintf(fp
, " max allocated chunks: %lu\n", ULSTAT(maxnchunks
));
252 fprintf(fp
, " total GC things: %lu\n", UL(sumThings
));
253 fprintf(fp
, " max total GC things: %lu\n", UL(sumMaxThings
));
254 fprintf(fp
, " GC cell utilization: %.1f%%\n",
255 PERCENT(sumThingSize
, sumArenaCapacity
));
256 fprintf(fp
, " average cell utilization: %.1f%%\n",
257 PERCENT(sumTotalThingSize
, sumTotalArenaCapacity
));
258 fprintf(fp
, "allocation retries after GC: %lu\n", UL(sumRetry
));
259 fprintf(fp
, " alloc attempts: %lu\n", UL(sumAlloc
));
260 fprintf(fp
, " alloc without locks: %lu (%.1f%%)\n",
261 UL(sumLocalAlloc
), PERCENT(sumLocalAlloc
, sumAlloc
));
262 fprintf(fp
, " allocation failures: %lu\n", UL(sumFail
));
263 fprintf(fp
, " valid lock calls: %lu\n", ULSTAT(lock
));
264 fprintf(fp
, " valid unlock calls: %lu\n", ULSTAT(unlock
));
265 fprintf(fp
, " delayed tracing calls: %lu\n", ULSTAT(unmarked
));
267 fprintf(fp
, " max trace later count: %lu\n", ULSTAT(maxunmarked
));
269 fprintf(fp
, "potentially useful GC calls: %lu\n", ULSTAT(poke
));
270 fprintf(fp
, " thing arenas freed so far: %lu\n", ULSTAT(afree
));
271 rt
->gcStats
.conservative
.dump(fp
);
283 jsrefcount newChunkCount
= 0;
284 jsrefcount destroyChunkCount
= 0;
288 memset(this, 0, sizeof(GCTimer
));
293 GCTimer::getFirstEnter() {
294 static uint64 firstEnter
= rdtsc();
299 GCTimer::finish(bool lastGC
) {
303 if (JS_WANT_GC_SUITE_PRINT
) {
304 fprintf(stderr
, "%f %f %f\n",
305 (double)(end
- enter
) / 1e6
,
306 (double)(startSweep
- startMark
) / 1e6
,
307 (double)(sweepDestroyEnd
- startSweep
) / 1e6
);
312 gcFile
= fopen("gcTimer.dat", "w");
314 fprintf(gcFile
, " AppTime, Total, Mark, Sweep, FinObj,");
315 fprintf(gcFile
, " FinStr, Destroy, newChunks, destoyChunks\n");
318 fprintf(gcFile
, "%12.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %7.1f, ",
319 (double)(enter
- getFirstEnter()) / 1e6
,
320 (double)(end
- enter
) / 1e6
,
321 (double)(startSweep
- startMark
) / 1e6
,
322 (double)(sweepDestroyEnd
- startSweep
) / 1e6
,
323 (double)(sweepObjectEnd
- startSweep
) / 1e6
,
324 (double)(sweepStringEnd
- sweepObjectEnd
) / 1e6
,
325 (double)(sweepDestroyEnd
- sweepStringEnd
) / 1e6
);
326 fprintf(gcFile
, "%10d, %10d \n", newChunkCount
,
337 destroyChunkCount
= 0;
340 #ifdef JS_SCOPE_DEPTH_METER
342 DumpScopeDepthMeter(JSRuntime
*rt
)
346 fp
= fopen("/tmp/scopedepth.stats", "w");
349 JS_DumpBasicStats(&rt
->protoLookupDepthStats
, "proto-lookup depth", fp
);
350 JS_DumpBasicStats(&rt
->scopeSearchDepthStats
, "scope-search depth", fp
);
351 JS_DumpBasicStats(&rt
->hostenvScopeDepthStats
, "hostenv scope depth", fp
);
352 JS_DumpBasicStats(&rt
->lexicalScopeDepthStats
, "lexical scope depth", fp
);
360 #ifdef JS_DUMP_LOOP_STATS
362 DumpLoopStats(JSRuntime
*rt
)
366 lsfp
= fopen("/tmp/loopstats", "w");
368 JS_DumpBasicStats(&rt
->loopStats
, "loops", lsfp
);