LCOV - app.info - js/src/gc/Statistics.cpp

LCOV - code coverage report
| Current view: | directory - js/src/gc - Statistics.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 359 | 68 | 18.9 %
| Date: | 2012-04-07 | Functions: | 39 | 8 | 20.5 %

           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 <stdarg.h>
          42                 :
          43                 : #include "jscntxt.h"
          44                 : #include "jscompartment.h"
          45                 : #include "jscrashformat.h"
          46                 : #include "jscrashreport.h"
          47                 : #include "jsprf.h"
          48                 : #include "jsprobes.h"
          49                 : #include "jsutil.h"
          50                 : #include "prmjtime.h"
          51                 :
          52                 : #include "gc/Statistics.h"
          53                 :
          54                 : #include "gc/Barrier-inl.h"
          55                 :
          56                 : namespace js {
          57                 : namespace gcstats {
          58                 :
          59                 : /* Except for the first and last, slices of less than 12ms are not reported. */
          60                 : static const int64_t SLICE_MIN_REPORT_TIME = 12 * PRMJ_USEC_PER_MSEC;
          61                 :
          62                 : class StatisticsSerializer
          63               0 : {
          64                 :     typedef Vector<char, 128, SystemAllocPolicy> CharBuffer;
          65                 :     CharBuffer buf_;
          66                 :     bool asJSON_;
          67                 :     bool needComma_;
          68                 :     bool oom_;
          69                 :
          70                 :     const static int MaxFieldValueLength = 128;
          71                 :
          72                 :   public:
          73                 :     enum Mode {
          74                 :         AsJSON = true,
          75                 :         AsText = false
          76                 :     };
          77                 :
          78               0 :     StatisticsSerializer(Mode asJSON)
          79               0 :       : buf_(), asJSON_(asJSON), needComma_(false), oom_(false)
          80               0 :     {}
          81                 :
          82               0 :     bool isJSON() { return asJSON_; }
          83                 :
          84               0 :     bool isOOM() { return oom_; }
          85                 :
          86               0 :     void endLine() {
          87               0 :         if (!asJSON_) {
          88               0 :             p("\n");
          89               0 :             needComma_ = false;
          90                 :         }
          91               0 :     }
          92                 :
          93               0 :     void extra(const char *str) {
          94               0 :         if (!asJSON_) {
          95               0 :             needComma_ = false;
          96               0 :             p(str);
          97                 :         }
          98               0 :     }
          99                 :
         100               0 :     void appendString(const char *name, const char *value) {
         101               0 :         put(name, value, "", true);
         102               0 :     }
         103                 :
         104               0 :     void appendNumber(const char *name, const char *vfmt, const char *units, ...) {
         105                 :         va_list va;
         106               0 :         va_start(va, units);
         107               0 :         append(name, vfmt, va, units);
         108               0 :         va_end(va);
         109               0 :     }
         110                 :
         111               0 :     void appendIfNonzeroMS(const char *name, double v) {
         112               0 :         if (asJSON_ || v >= 0.1)
         113               0 :             appendNumber(name, "%.1f", "ms", v);
         114               0 :     }
         115                 :
         116               0 :     void beginObject(const char *name) {
         117               0 :         if (needComma_)
         118               0 :             pJSON(", ");
         119               0 :         if (asJSON_ && name) {
         120               0 :             putQuoted(name);
         121               0 :             pJSON(": ");
         122                 :         }
         123               0 :         pJSON("{");
         124               0 :         needComma_ = false;
         125               0 :     }
         126                 :
         127               0 :     void endObject() {
         128               0 :         needComma_ = false;
         129               0 :         pJSON("}");
         130               0 :         needComma_ = true;
         131               0 :     }
         132                 :
         133               0 :     void beginArray(const char *name) {
         134               0 :         if (needComma_)
         135               0 :             pJSON(", ");
         136               0 :         if (asJSON_)
         137               0 :             putQuoted(name);
         138               0 :         pJSON(": [");
         139               0 :         needComma_ = false;
         140               0 :     }
         141                 :
         142               0 :     void endArray() {
         143               0 :         needComma_ = false;
         144               0 :         pJSON("]");
         145               0 :         needComma_ = true;
         146               0 :     }
         147                 :
         148               0 :     jschar *finishJSString() {
         149               0 :         char *buf = finishCString();
         150               0 :         if (!buf)
         151               0 :             return NULL;
         152                 :
         153               0 :         size_t nchars = strlen(buf);
         154               0 :         jschar *out = (jschar *)js_malloc(sizeof(jschar) * (nchars + 1));
         155               0 :         if (!out) {
         156               0 :             oom_ = true;
         157               0 :             js_free(buf);
         158               0 :             return NULL;
         159                 :         }
         160                 :
         161               0 :         size_t outlen = nchars;
         162               0 :         bool ok = InflateStringToBuffer(NULL, buf, nchars, out, &outlen);
         163               0 :         js_free(buf);
         164               0 :         if (!ok) {
         165               0 :             oom_ = true;
         166               0 :             js_free(out);
         167               0 :             return NULL;
         168                 :         }
         169               0 :         out[nchars] = 0;
         170                 :
         171               0 :         return out;
         172                 :     }
         173                 :
         174               0 :     char *finishCString() {
         175               0 :         if (oom_)
         176               0 :             return NULL;
         177                 :
         178               0 :         buf_.append('\0');
         179                 :
         180               0 :         char *buf = buf_.extractRawBuffer();
         181               0 :         if (!buf)
         182               0 :             oom_ = true;
         183                 :
         184               0 :         return buf;
         185                 :     }
         186                 :
         187                 :   private:
         188               0 :     void append(const char *name, const char *vfmt,
         189                 :                 va_list va, const char *units)
         190                 :     {
         191                 :         char val[MaxFieldValueLength];
         192               0 :         JS_vsnprintf(val, MaxFieldValueLength, vfmt, va);
         193               0 :         put(name, val, units, false);
         194               0 :     }
         195                 :
         196               0 :     void p(const char *cstr) {
         197               0 :         if (oom_)
         198               0 :             return;
         199                 :
         200               0 :         if (!buf_.append(cstr, strlen(cstr)))
         201               0 :             oom_ = true;
         202                 :     }
         203                 :
         204               0 :     void p(const char c) {
         205               0 :         if (oom_)
         206               0 :             return;
         207                 :
         208               0 :         if (!buf_.append(c))
         209               0 :             oom_ = true;
         210                 :     }
         211                 :
         212               0 :     void pJSON(const char *str) {
         213               0 :         if (asJSON_)
         214               0 :             p(str);
         215               0 :     }
         216                 :
         217               0 :     void put(const char *name, const char *val, const char *units, bool valueIsQuoted) {
         218               0 :         if (needComma_)
         219               0 :             p(", ");
         220               0 :         needComma_ = true;
         221                 :
         222               0 :         putKey(name);
         223               0 :         p(": ");
         224               0 :         if (valueIsQuoted)
         225               0 :             putQuoted(val);
         226                 :         else
         227               0 :             p(val);
         228               0 :         if (!asJSON_)
         229               0 :             p(units);
         230               0 :     }
         231                 :
         232               0 :     void putQuoted(const char *str) {
         233               0 :         pJSON("\"");
         234               0 :         p(str);
         235               0 :         pJSON("\"");
         236               0 :     }
         237                 :
         238               0 :     void putKey(const char *str) {
         239               0 :         if (!asJSON_) {
         240               0 :             p(str);
         241               0 :             return;
         242                 :         }
         243                 :
         244               0 :         p("\"");
         245               0 :         const char *c = str;
         246               0 :         while (*c) {
         247               0 :             if (*c == ' ' || *c == '\t')
         248               0 :                 p('_');
         249               0 :             else if (isupper(*c))
         250               0 :                 p(tolower(*c));
         251               0 :             else if (*c == '+')
         252               0 :                 p("added_");
         253               0 :             else if (*c == '-')
         254               0 :                 p("removed_");
         255               0 :             else if (*c != '(' && *c != ')')
         256               0 :                 p(*c);
         257               0 :             c++;
         258                 :         }
         259               0 :         p("\"");
         260                 :     }
         261                 : };
         262                 :
         263                 : static const char *
         264               0 : ExplainReason(gcreason::Reason reason)
         265                 : {
         266               0 :     switch (reason) {
         267                 : #define SWITCH_REASON(name)                     \
         268                 :         case gcreason::name:                    \
         269                 :           return #name;
         270               0 :         GCREASONS(SWITCH_REASON)
         271                 :
         272                 :         default:
         273               0 :           JS_NOT_REACHED("bad GC reason");
         274                 :           return "?";
         275                 : #undef SWITCH_REASON
         276                 :     }
         277                 : }
         278                 :
         279                 : static double
         280               0 : t(int64_t t)
         281                 : {
         282               0 :     return double(t) / PRMJ_USEC_PER_MSEC;
         283                 : }
         284                 :
         285                 : static void
         286               0 : formatPhases(StatisticsSerializer &ss, const char *name, int64_t *times)
         287                 : {
         288               0 :     ss.beginObject(name);
         289               0 :     ss.appendIfNonzeroMS("Begin Callback", t(times[PHASE_GC_BEGIN]));
         290               0 :     ss.appendIfNonzeroMS("Wait Background Thread", t(times[PHASE_WAIT_BACKGROUND_THREAD]));
         291               0 :     ss.appendIfNonzeroMS("Purge", t(times[PHASE_PURGE]));
         292               0 :     ss.appendIfNonzeroMS("Mark", t(times[PHASE_MARK]));
         293               0 :     ss.appendIfNonzeroMS("Mark Roots", t(times[PHASE_MARK_ROOTS]));
         294               0 :     ss.appendIfNonzeroMS("Mark Delayed", t(times[PHASE_MARK_DELAYED]));
         295               0 :     ss.appendIfNonzeroMS("Mark Other", t(times[PHASE_MARK_OTHER]));
         296               0 :     ss.appendIfNonzeroMS("Finalize Start Callback", t(times[PHASE_FINALIZE_START]));
         297               0 :     ss.appendIfNonzeroMS("Sweep", t(times[PHASE_SWEEP]));
         298               0 :     ss.appendIfNonzeroMS("Sweep Compartments", t(times[PHASE_SWEEP_COMPARTMENTS]));
         299               0 :     ss.appendIfNonzeroMS("Sweep Object", t(times[PHASE_SWEEP_OBJECT]));
         300               0 :     ss.appendIfNonzeroMS("Sweep String", t(times[PHASE_SWEEP_STRING]));
         301               0 :     ss.appendIfNonzeroMS("Sweep Script", t(times[PHASE_SWEEP_SCRIPT]));
         302               0 :     ss.appendIfNonzeroMS("Sweep Shape", t(times[PHASE_SWEEP_SHAPE]));
         303               0 :     ss.appendIfNonzeroMS("Discard Code", t(times[PHASE_DISCARD_CODE]));
         304               0 :     ss.appendIfNonzeroMS("Discard Analysis", t(times[PHASE_DISCARD_ANALYSIS]));
         305               0 :     ss.appendIfNonzeroMS("Discard TI", t(times[PHASE_DISCARD_TI]));
         306               0 :     ss.appendIfNonzeroMS("Sweep Types", t(times[PHASE_SWEEP_TYPES]));
         307               0 :     ss.appendIfNonzeroMS("Clear Script Analysis", t(times[PHASE_CLEAR_SCRIPT_ANALYSIS]));
         308               0 :     ss.appendIfNonzeroMS("Finalize End Callback", t(times[PHASE_FINALIZE_END]));
         309               0 :     ss.appendIfNonzeroMS("Deallocate", t(times[PHASE_DESTROY]));
         310               0 :     ss.appendIfNonzeroMS("End Callback", t(times[PHASE_GC_END]));
         311               0 :     ss.endObject();
         312               0 : }
         313                 :
         314                 : bool
         315               0 : Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
         316                 : {
         317               0 :     int64_t total = 0, longest = 0;
         318               0 :     for (SliceData *slice = slices.begin(); slice != slices.end(); slice++) {
         319               0 :         total += slice->duration();
         320               0 :         if (slice->duration() > longest)
         321               0 :             longest = slice->duration();
         322                 :     }
         323                 :
         324               0 :     double mmu20 = computeMMU(20 * PRMJ_USEC_PER_MSEC);
         325               0 :     double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
         326                 :
         327               0 :     ss.beginObject(NULL);
         328               0 :     if (ss.isJSON())
         329               0 :         ss.appendNumber("Timestamp", "%llu", "", (unsigned long long)timestamp);
         330               0 :     ss.appendNumber("Total Time", "%.1f", "ms", t(total));
         331               0 :     ss.appendNumber("Compartments Collected", "%d", "", collectedCount);
         332               0 :     ss.appendNumber("Total Compartments", "%d", "", compartmentCount);
         333               0 :     ss.appendNumber("MMU (20ms)", "%d", "%", int(mmu20 * 100));
         334               0 :     ss.appendNumber("MMU (50ms)", "%d", "%", int(mmu50 * 100));
         335               0 :     if (slices.length() > 1 || ss.isJSON())
         336               0 :         ss.appendNumber("Max Pause", "%.1f", "ms", t(longest));
         337                 :     else
         338               0 :         ss.appendString("Reason", ExplainReason(slices[0].reason));
         339               0 :     if (nonincrementalReason || ss.isJSON()) {
         340                 :         ss.appendString("Nonincremental Reason",
         341               0 :                         nonincrementalReason ? nonincrementalReason : "none");
         342                 :     }
         343               0 :     ss.appendNumber("Allocated", "%u", "MB", unsigned(preBytes / 1024 / 1024));
         344               0 :     ss.appendNumber("+Chunks", "%d", "", counts[STAT_NEW_CHUNK]);
         345               0 :     ss.appendNumber("-Chunks", "%d", "", counts[STAT_DESTROY_CHUNK]);
         346               0 :     ss.endLine();
         347                 :
         348               0 :     if (slices.length() > 1 || ss.isJSON()) {
         349               0 :         ss.beginArray("Slices");
         350               0 :         for (size_t i = 0; i < slices.length(); i++) {
         351               0 :             int64_t width = slices[i].duration();
         352               0 :             if (i != 0 && i != slices.length() - 1 && width < SLICE_MIN_REPORT_TIME &&
         353               0 :                 !slices[i].resetReason && !ss.isJSON())
         354                 :             {
         355               0 :                 continue;
         356                 :             }
         357                 :
         358               0 :             ss.beginObject(NULL);
         359               0 :             ss.extra("    ");
         360               0 :             ss.appendNumber("Slice", "%d", "", i);
         361               0 :             ss.appendNumber("Time", "%.1f", "ms", t(slices[i].end - slices[0].start));
         362               0 :             ss.extra(" (");
         363               0 :             ss.appendNumber("Pause", "%.1f", "", t(width));
         364               0 :             ss.appendString("Reason", ExplainReason(slices[i].reason));
         365               0 :             if (slices[i].resetReason)
         366               0 :                 ss.appendString("Reset", slices[i].resetReason);
         367               0 :             ss.extra("): ");
         368               0 :             formatPhases(ss, "times", slices[i].phaseTimes);
         369               0 :             ss.endLine();
         370               0 :             ss.endObject();
         371                 :         }
         372               0 :         ss.endArray();
         373                 :     }
         374               0 :     ss.extra("    Totals: ");
         375               0 :     formatPhases(ss, "totals", phaseTimes);
         376               0 :     ss.endObject();
         377                 :
         378               0 :     return !ss.isOOM();
         379                 : }
         380                 :
         381                 : jschar *
         382               0 : Statistics::formatMessage()
         383                 : {
         384               0 :     StatisticsSerializer ss(StatisticsSerializer::AsText);
         385               0 :     formatData(ss, 0);
         386               0 :     return ss.finishJSString();
         387                 : }
         388                 :
         389                 : jschar *
         390               0 : Statistics::formatJSON(uint64_t timestamp)
         391                 : {
         392               0 :     StatisticsSerializer ss(StatisticsSerializer::AsJSON);
         393               0 :     formatData(ss, timestamp);
         394               0 :     return ss.finishJSString();
         395                 : }
         396                 :
         397           18761 : Statistics::Statistics(JSRuntime *rt)
         398                 :   : runtime(rt),
         399           18761 :     startupTime(PRMJ_Now()),
         400                 :     fp(NULL),
         401                 :     fullFormat(false),
         402                 :     collectedCount(0),
         403                 :     compartmentCount(0),
         404           37522 :     nonincrementalReason(NULL)
         405                 : {
         406           18761 :     PodArrayZero(phaseTotals);
         407           18761 :     PodArrayZero(counts);
         408                 :
         409           18761 :     char *env = getenv("MOZ_GCTIMER");
         410           18761 :     if (!env || strcmp(env, "none") == 0) {
         411           18761 :         fp = NULL;
         412           18761 :         return;
         413                 :     }
         414                 :
         415               0 :     if (strcmp(env, "stdout") == 0) {
         416               0 :         fullFormat = false;
         417               0 :         fp = stdout;
         418               0 :     } else if (strcmp(env, "stderr") == 0) {
         419               0 :         fullFormat = false;
         420               0 :         fp = stderr;
         421                 :     } else {
         422               0 :         fullFormat = true;
         423                 :
         424               0 :         fp = fopen(env, "a");
         425               0 :         JS_ASSERT(fp);
         426                 :     }
         427                 : }
         428                 :
         429           37522 : Statistics::~Statistics()
         430                 : {
         431           18761 :     if (fp) {
         432               0 :         if (fullFormat) {
         433               0 :             StatisticsSerializer ss(StatisticsSerializer::AsText);
         434               0 :             formatPhases(ss, "", phaseTotals);
         435               0 :             char *msg = ss.finishCString();
         436               0 :             if (msg) {
         437               0 :                 fprintf(fp, "TOTALS\n%s\n\n-------\n", msg);
         438               0 :                 js_free(msg);
         439                 :             }
         440                 :         }
         441                 :
         442               0 :         if (fp != stdout && fp != stderr)
         443               0 :             fclose(fp);
         444                 :     }
         445           18761 : }
         446                 :
         447                 : int64_t
         448               0 : Statistics::gcDuration()
         449                 : {
         450               0 :     return slices.back().end - slices[0].start;
         451                 : }
         452                 :
         453                 : void
         454               0 : Statistics::printStats()
         455                 : {
         456               0 :     if (fullFormat) {
         457               0 :         StatisticsSerializer ss(StatisticsSerializer::AsText);
         458               0 :         formatData(ss, 0);
         459               0 :         char *msg = ss.finishCString();
         460               0 :         if (msg) {
         461               0 :             fprintf(fp, "GC(T+%.3fs) %s\n", t(slices[0].start - startupTime) / 1000.0, msg);
         462               0 :             js_free(msg);
         463                 :         }
         464                 :     } else {
         465                 :         fprintf(fp, "%f %f %f\n",
         466                 :                 t(gcDuration()),
         467                 :                 t(phaseTimes[PHASE_MARK]),
         468               0 :                 t(phaseTimes[PHASE_SWEEP]));
         469                 :     }
         470               0 :     fflush(fp);
         471               0 : }
         472                 :
         473                 : void
         474           38427 : Statistics::beginGC()
         475                 : {
         476           38427 :     PodArrayZero(phaseStarts);
         477           38427 :     PodArrayZero(phaseTimes);
         478                 :
         479           38427 :     slices.clearAndFree();
         480           38427 :     nonincrementalReason = NULL;
         481                 :
         482           38427 :     preBytes = runtime->gcBytes;
         483                 :
         484           38427 :     Probes::GCStart();
         485           38427 : }
         486                 :
         487                 : void
         488           38427 : Statistics::endGC()
         489                 : {
         490           38427 :     Probes::GCEnd();
         491           38427 :     crash::SnapshotGCStack();
         492                 :
         493          883821 :     for (int i = 0; i < PHASE_LIMIT; i++)
         494          845394 :         phaseTotals[i] += phaseTimes[i];
         495                 :
         496           38427 :     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
         497               0 :         (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, collectedCount == compartmentCount ? 0 : 1);
         498               0 :         (*cb)(JS_TELEMETRY_GC_MS, t(gcDuration()));
         499               0 :         (*cb)(JS_TELEMETRY_GC_MARK_MS, t(phaseTimes[PHASE_MARK]));
         500               0 :         (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_SWEEP]));
         501               0 :         (*cb)(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason);
         502               0 :         (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gcIncrementalEnabled);
         503                 :
         504               0 :         double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
         505               0 :         (*cb)(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
         506                 :     }
         507                 :
         508           38427 :     if (fp)
         509               0 :         printStats();
         510           38427 : }
         511                 :
         512                 : void
         513           38481 : Statistics::beginSlice(int collectedCount, int compartmentCount, gcreason::Reason reason)
         514                 : {
         515           38481 :     this->collectedCount = collectedCount;
         516           38481 :     this->compartmentCount = compartmentCount;
         517                 :
         518           38481 :     bool first = runtime->gcIncrementalState == gc::NO_INCREMENTAL;
         519           38481 :     if (first)
         520           38427 :         beginGC();
         521                 :
         522           38481 :     SliceData data(reason, PRMJ_Now());
         523           38481 :     (void) slices.append(data); /* Ignore any OOMs here. */
         524                 :
         525           38481 :     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
         526               0 :         (*cb)(JS_TELEMETRY_GC_REASON, reason);
         527                 :
         528           38481 :     bool wasFullGC = collectedCount == compartmentCount;
         529           38481 :     if (GCSliceCallback cb = runtime->gcSliceCallback)
         530               0 :         (*cb)(runtime, first ? GC_CYCLE_BEGIN : GC_SLICE_BEGIN, GCDescription(!wasFullGC));
         531           38481 : }
         532                 :
         533                 : void
         534           38481 : Statistics::endSlice()
         535                 : {
         536           38481 :     slices.back().end = PRMJ_Now();
         537                 :
         538           38481 :     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
         539               0 :         (*cb)(JS_TELEMETRY_GC_SLICE_MS, t(slices.back().end - slices.back().start));
         540               0 :         (*cb)(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason);
         541                 :     }
         542                 :
         543           38481 :     bool last = runtime->gcIncrementalState == gc::NO_INCREMENTAL;
         544           38481 :     if (last)
         545           38427 :         endGC();
         546                 :
         547           38481 :     bool wasFullGC = collectedCount == compartmentCount;
         548           38481 :     if (GCSliceCallback cb = runtime->gcSliceCallback) {
         549               0 :         if (last)
         550               0 :             (*cb)(runtime, GC_CYCLE_END, GCDescription(!wasFullGC));
         551                 :         else
         552               0 :             (*cb)(runtime, GC_SLICE_END, GCDescription(!wasFullGC));
         553                 :     }
         554                 :
         555                 :     /* Do this after the slice callback since it uses these values. */
         556           38481 :     if (last)
         557           38427 :         PodArrayZero(counts);
         558           38481 : }
         559                 :
         560                 : void
         561         1051317 : Statistics::beginPhase(Phase phase)
         562                 : {
         563         1051317 :     phaseStarts[phase] = PRMJ_Now();
         564                 :
         565         1051317 :     if (phase == gcstats::PHASE_MARK)
         566          115362 :         Probes::GCStartMarkPhase();
         567          935955 :     else if (phase == gcstats::PHASE_SWEEP)
         568           38427 :         Probes::GCStartSweepPhase();
         569         1051317 : }
         570                 :
         571                 : void
         572         1051317 : Statistics::endPhase(Phase phase)
         573                 : {
         574         1051317 :     int64_t now = PRMJ_Now();
         575         1051317 :     int64_t t = now - phaseStarts[phase];
         576         1051317 :     slices.back().phaseTimes[phase] += t;
         577         1051317 :     phaseTimes[phase] += t;
         578                 :
         579         1051317 :     if (phase == gcstats::PHASE_MARK)
         580          115362 :         Probes::GCEndMarkPhase();
         581          935955 :     else if (phase == gcstats::PHASE_SWEEP)
         582           38427 :         Probes::GCEndSweepPhase();
         583         1051317 : }
         584                 :
         585                 : /*
         586                 :  * MMU (minimum mutator utilization) is a measure of how much garbage collection
         587                 :  * is affecting the responsiveness of the system. MMU measurements are given
         588                 :  * with respect to a certain window size. If we report MMU(50ms) = 80%, then
         589                 :  * that means that, for any 50ms window of time, at least 80% of the window is
         590                 :  * devoted to the mutator. In other words, the GC is running for at most 20% of
         591                 :  * the window, or 10ms. The GC can run multiple slices during the 50ms window
         592                 :  * as long as the total time it spends is at most 10ms.
         593                 :  */
         594                 : double
         595               0 : Statistics::computeMMU(int64_t window)
         596                 : {
         597               0 :     JS_ASSERT(!slices.empty());
         598                 :
         599               0 :     int64_t gc = slices[0].end - slices[0].start;
         600               0 :     int64_t gcMax = gc;
         601                 :
         602               0 :     if (gc >= window)
         603               0 :         return 0.0;
         604                 :
         605               0 :     int startIndex = 0;
         606               0 :     for (size_t endIndex = 1; endIndex < slices.length(); endIndex++) {
         607               0 :         gc += slices[endIndex].end - slices[endIndex].start;
         608                 :
         609               0 :         while (slices[endIndex].end - slices[startIndex].end >= window) {
         610               0 :             gc -= slices[startIndex].end - slices[startIndex].start;
         611               0 :             startIndex++;
         612                 :         }
         613                 :
         614               0 :         int64_t cur = gc;
         615               0 :         if (slices[endIndex].end - slices[startIndex].start > window)
         616               0 :             cur -= (slices[endIndex].end - slices[startIndex].start - window);
         617               0 :         if (cur > gcMax)
         618               0 :             gcMax = cur;
         619                 :     }
         620                 :
         621               0 :     return double(window - gcMax) / window;
         622                 : }
         623                 :
         624                 : } /* namespace gcstats */
         625                 : } /* namespace js */

Generated by: LCOV version 1.7