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