PageRenderTime 73ms CodeModel.GetById 27ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/js/src/gc/Statistics.cpp

http://github.com/zpao/v8monkey
C++ | 337 lines | 246 code | 53 blank | 38 comment | 41 complexity | 9d0e179c0da6612259375a4afc895c04 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 * vim: set ts=8 sw=4 et tw=78:
  3 *
  4 * ***** BEGIN LICENSE BLOCK *****
  5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6 *
  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/
 11 *
 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
 15 * License.
 16 *
 17 * The Original Code is SpiderMonkey JavaScript engine.
 18 *
 19 * The Initial Developer of the Original Code is
 20 * the Mozilla Foundation.
 21 * Portions created by the Initial Developer are Copyright (C) 2011
 22 * the Initial Developer. All Rights Reserved.
 23 *
 24 * Contributor(s):
 25 *
 26 * Alternatively, the contents of this file may be used under the terms of
 27 * either of the GNU General Public License Version 2 or later (the "GPL"),
 28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 29 * in which case the provisions of the GPL or the LGPL are applicable instead
 30 * of those above. If you wish to allow use of your version of this file only
 31 * under the terms of either the GPL or the LGPL, and not to allow others to
 32 * use your version of this file under the terms of the MPL, indicate your
 33 * decision by deleting the provisions above and replace them with the notice
 34 * and other provisions required by the GPL or the LGPL. If you do not delete
 35 * the provisions above, a recipient may use your version of this file under
 36 * the terms of any one of the MPL, the GPL or the LGPL.
 37 *
 38 * ***** END LICENSE BLOCK ***** */
 39
 40#include <stdio.h>
 41#include <ctype.h>
 42
 43#include "jscntxt.h"
 44#include "jscrashformat.h"
 45#include "jscrashreport.h"
 46#include "jsprf.h"
 47#include "jsprobes.h"
 48#include "jsutil.h"
 49#include "prmjtime.h"
 50
 51#include "gc/Statistics.h"
 52
 53namespace js {
 54namespace gcstats {
 55
 56static const char *
 57ExplainReason(gcreason::Reason reason)
 58{
 59    switch (reason) {
 60#define SWITCH_REASON(name)                     \
 61        case gcreason::name:                    \
 62          return #name;
 63        GCREASONS(SWITCH_REASON)
 64
 65        default:
 66          JS_NOT_REACHED("bad GC reason");
 67          return "?";
 68#undef SWITCH_REASON
 69    }
 70}
 71
 72Statistics::ColumnInfo::ColumnInfo(const char *title, double t, double total)
 73  : title(title)
 74{
 75    JS_snprintf(str, sizeof(str), "%.1f", t);
 76    JS_snprintf(totalStr, sizeof(totalStr), "%.1f", total);
 77    width = 6;
 78}
 79
 80Statistics::ColumnInfo::ColumnInfo(const char *title, double t)
 81  : title(title)
 82{
 83    JS_snprintf(str, sizeof(str), "%.1f", t);
 84    strcpy(totalStr, "n/a");
 85    width = 6;
 86}
 87
 88Statistics::ColumnInfo::ColumnInfo(const char *title, unsigned int data)
 89  : title(title)
 90{
 91    JS_snprintf(str, sizeof(str), "%d", data);
 92    strcpy(totalStr, "n/a");
 93    width = 4;
 94}
 95
 96Statistics::ColumnInfo::ColumnInfo(const char *title, const char *data)
 97  : title(title)
 98{
 99    JS_ASSERT(strlen(data) < sizeof(str));
100    strcpy(str, data);
101    strcpy(totalStr, "n/a ");
102    width = 0;
103}
104
105static const int NUM_COLUMNS = 17;
106
107void
108Statistics::makeTable(ColumnInfo *cols)
109{
110    int i = 0;
111
112    cols[i++] = ColumnInfo("Type", compartment ? "Comp" : "Glob");
113
114    cols[i++] = ColumnInfo("Total", t(PHASE_GC), total(PHASE_GC));
115    cols[i++] = ColumnInfo("Wait", beginDelay(PHASE_MARK, PHASE_GC));
116    cols[i++] = ColumnInfo("Mark", t(PHASE_MARK), total(PHASE_MARK));
117    cols[i++] = ColumnInfo("Sweep", t(PHASE_SWEEP), total(PHASE_SWEEP));
118    cols[i++] = ColumnInfo("FinObj", t(PHASE_SWEEP_OBJECT), total(PHASE_SWEEP_OBJECT));
119    cols[i++] = ColumnInfo("FinStr", t(PHASE_SWEEP_STRING), total(PHASE_SWEEP_STRING));
120    cols[i++] = ColumnInfo("FinScr", t(PHASE_SWEEP_SCRIPT), total(PHASE_SWEEP_SCRIPT));
121    cols[i++] = ColumnInfo("FinShp", t(PHASE_SWEEP_SHAPE), total(PHASE_SWEEP_SHAPE));
122    cols[i++] = ColumnInfo("DisCod", t(PHASE_DISCARD_CODE), total(PHASE_DISCARD_CODE));
123    cols[i++] = ColumnInfo("DisAnl", t(PHASE_DISCARD_ANALYSIS), total(PHASE_DISCARD_ANALYSIS));
124    cols[i++] = ColumnInfo("XPCnct", t(PHASE_XPCONNECT), total(PHASE_XPCONNECT));
125    cols[i++] = ColumnInfo("Destry", t(PHASE_DESTROY), total(PHASE_DESTROY));
126    cols[i++] = ColumnInfo("End", endDelay(PHASE_GC, PHASE_DESTROY));
127
128    cols[i++] = ColumnInfo("+Chu", counts[STAT_NEW_CHUNK]);
129    cols[i++] = ColumnInfo("-Chu", counts[STAT_DESTROY_CHUNK]);
130
131    cols[i++] = ColumnInfo("Reason", ExplainReason(triggerReason));
132
133    JS_ASSERT(i == NUM_COLUMNS);
134}
135
136Statistics::Statistics(JSRuntime *rt)
137  : runtime(rt),
138    triggerReason(gcreason::NO_REASON)
139{
140    PodArrayZero(counts);
141    PodArrayZero(totals);
142
143    startupTime = PRMJ_Now();
144
145    char *env = getenv("MOZ_GCTIMER");
146    if (!env || strcmp(env, "none") == 0) {
147        fp = NULL;
148        return;
149    }
150
151    if (strcmp(env, "stdout") == 0) {
152        fullFormat = false;
153        fp = stdout;
154    } else if (strcmp(env, "stderr") == 0) {
155        fullFormat = false;
156        fp = stderr;
157    } else {
158        fullFormat = true;
159
160        fp = fopen(env, "a");
161        JS_ASSERT(fp);
162
163        fprintf(fp, "     AppTime");
164
165        ColumnInfo cols[NUM_COLUMNS];
166        makeTable(cols);
167        for (int i = 0; i < NUM_COLUMNS; i++)
168            fprintf(fp, ", %*s", cols[i].width, cols[i].title);
169        fprintf(fp, "\n");
170    }
171}
172
173Statistics::~Statistics()
174{
175    if (fp) {
176        if (fullFormat) {
177            fprintf(fp, "------>TOTAL");
178
179            ColumnInfo cols[NUM_COLUMNS];
180            makeTable(cols);
181            for (int i = 0; i < NUM_COLUMNS && cols[i].totalStr[0]; i++)
182                fprintf(fp, ", %*s", cols[i].width, cols[i].totalStr);
183            fprintf(fp, "\n");
184        }
185
186        if (fp != stdout && fp != stderr)
187            fclose(fp);
188    }
189}
190
191struct GCCrashData
192{
193    int isRegen;
194    int isCompartment;
195};
196
197void
198Statistics::beginGC(JSCompartment *comp, gcreason::Reason reason)
199{
200    compartment = comp;
201
202    PodArrayZero(phaseStarts);
203    PodArrayZero(phaseEnds);
204    PodArrayZero(phaseTimes);
205
206    triggerReason = reason;
207
208    beginPhase(PHASE_GC);
209    Probes::GCStart();
210
211    GCCrashData crashData;
212    crashData.isCompartment = !!compartment;
213    crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
214}
215
216double
217Statistics::t(Phase phase)
218{
219    return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC;
220}
221
222double
223Statistics::total(Phase phase)
224{
225    return double(totals[phase]) / PRMJ_USEC_PER_MSEC;
226}
227
228double
229Statistics::beginDelay(Phase phase1, Phase phase2)
230{
231    return double(phaseStarts[phase1] - phaseStarts[phase2]) / PRMJ_USEC_PER_MSEC;
232}
233
234double
235Statistics::endDelay(Phase phase1, Phase phase2)
236{
237    return double(phaseEnds[phase1] - phaseEnds[phase2]) / PRMJ_USEC_PER_MSEC;
238}
239
240void
241Statistics::statsToString(char *buffer, size_t size)
242{
243    JS_ASSERT(size);
244    buffer[0] = 0x00;
245
246    ColumnInfo cols[NUM_COLUMNS];
247    makeTable(cols);
248
249    size_t pos = 0;
250    for (int i = 0; i < NUM_COLUMNS; i++) {
251        int len = strlen(cols[i].title) + 1 + strlen(cols[i].str);
252        if (i > 0)
253            len += 2;
254        if (pos + len >= size)
255            break;
256        if (i > 0)
257            strcat(buffer, ", ");
258        strcat(buffer, cols[i].title);
259        strcat(buffer, ":");
260        strcat(buffer, cols[i].str);
261        pos += len;
262    }
263}
264
265void
266Statistics::printStats()
267{
268    if (fullFormat) {
269        fprintf(fp, "%12.0f", double(phaseStarts[PHASE_GC] - startupTime) / PRMJ_USEC_PER_MSEC);
270
271        ColumnInfo cols[NUM_COLUMNS];
272        makeTable(cols);
273        for (int i = 0; i < NUM_COLUMNS; i++)
274            fprintf(fp, ", %*s", cols[i].width, cols[i].str);
275        fprintf(fp, "\n");
276    } else {
277        fprintf(fp, "%f %f %f\n",
278                t(PHASE_GC), t(PHASE_MARK), t(PHASE_SWEEP));
279    }
280    fflush(fp);
281}
282
283void
284Statistics::endGC()
285{
286    Probes::GCEnd();
287    endPhase(PHASE_GC);
288    crash::SnapshotGCStack();
289
290    for (int i = 0; i < PHASE_LIMIT; i++)
291        totals[i] += phaseTimes[i];
292
293    if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
294        (*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
295        (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
296        (*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
297        (*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
298        (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
299    }
300
301    if (JSGCFinishedCallback cb = runtime->gcFinishedCallback) {
302        char buffer[1024];
303        statsToString(buffer, sizeof(buffer));
304        (*cb)(runtime, compartment, buffer);
305    }
306
307    if (fp)
308        printStats();
309
310    PodArrayZero(counts);
311}
312
313void
314Statistics::beginPhase(Phase phase)
315{
316    phaseStarts[phase] = PRMJ_Now();
317
318    if (phase == gcstats::PHASE_MARK)
319        Probes::GCStartMarkPhase();
320    else if (phase == gcstats::PHASE_SWEEP)
321        Probes::GCStartSweepPhase();
322}
323
324void
325Statistics::endPhase(Phase phase)
326{
327    phaseEnds[phase] = PRMJ_Now();
328    phaseTimes[phase] += phaseEnds[phase] - phaseStarts[phase];
329
330    if (phase == gcstats::PHASE_MARK)
331        Probes::GCEndMarkPhase();
332    else if (phase == gcstats::PHASE_SWEEP)
333        Probes::GCEndSweepPhase();
334}
335
336} /* namespace gcstats */
337} /* namespace js */