author | Wes Kocher <wkocher@mozilla.com> |
Tue, 04 Nov 2014 16:39:12 -0800 | |
changeset 214024 | d95e85773aa64e8efec26b623cbaf34e48d2aa8f |
parent 214023 | 4be4cf0afc2950232fd5d84e4edcf8a0a429c8dc |
child 214025 | 5e6d8b6023e32f464ac8595969531f40b5113c05 |
push id | 27771 |
push user | ryanvm@gmail.com |
push date | Wed, 05 Nov 2014 19:04:24 +0000 |
treeherder | mozilla-central@305b4fecce99 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1088831 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -22,17 +22,16 @@ #include "vm/HelperThreads.h" #include "vm/Runtime.h" using namespace js; using namespace js::gc; using namespace js::gcstats; using mozilla::PodArrayZero; -using mozilla::PodZero; /* Except for the first and last, slices of less than 10ms are not reported. */ static const int64_t SLICE_MIN_REPORT_TIME = 10 * PRMJ_USEC_PER_MSEC; class gcstats::StatisticsSerializer { typedef Vector<char, 128, SystemAllocPolicy> CharBuffer; CharBuffer buf_; @@ -279,17 +278,16 @@ struct PhaseInfo Phase index; const char *name; Phase parent; }; static const Phase PHASE_NO_PARENT = PHASE_LIMIT; static const PhaseInfo phases[] = { - { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT }, { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT }, { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT }, { PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT }, { PHASE_PURGE, "Purge", PHASE_NO_PARENT }, { PHASE_MARK, "Mark", PHASE_NO_PARENT }, { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MARK }, { PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK }, { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT }, @@ -323,19 +321,16 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP }, { PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP }, { PHASE_DESTROY, "Deallocate", PHASE_SWEEP }, { PHASE_COMPACT, "Compact", PHASE_NO_PARENT }, { PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT }, { PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT, }, { PHASE_COMPACT_UPDATE_GRAY, "Compact Update Gray", PHASE_COMPACT_UPDATE, }, { PHASE_GC_END, "End Callback", PHASE_NO_PARENT }, - { PHASE_MINOR_GC, "Minor GC", PHASE_NO_PARENT }, - { PHASE_COMPACT_STOREBUFFER_IN_MINOR_GC, "Compact Store Buffers", PHASE_MINOR_GC }, - { PHASE_COMPACT_STOREBUFFER_NO_PARENT, "Compact Store Buffers (toplevel)", PHASE_NO_PARENT }, { PHASE_LIMIT, nullptr, PHASE_NO_PARENT } }; static void FormatPhaseTimes(StatisticsSerializer &ss, const char *name, int64_t *times) { ss.beginObject(name); for (unsigned i = 0; phases[i].name; i++) @@ -385,18 +380,16 @@ Statistics::formatData(StatisticsSeriali ss.appendDecimal("Max Pause", "ms", t(longest)); else ss.appendString("Reason", ExplainReason(slices[0].reason)); ss.appendDecimal("Total Time", "ms", t(total)); ss.appendNumber("Zones Collected", "%d", "", zoneStats.collectedZoneCount); ss.appendNumber("Total Zones", "%d", "", zoneStats.zoneCount); ss.appendNumber("Total Compartments", "%d", "", zoneStats.compartmentCount); ss.appendNumber("Minor GCs", "%d", "", counts[STAT_MINOR_GC]); - ss.appendNumber("Store Buffer Compactions", "%d", "", counts[STAT_COMPACT_STOREBUFFER]); - ss.appendNumber("Store Buffer Overflows", "%d", "", counts[STAT_STOREBUFFER_OVERFLOW]); ss.appendNumber("MMU (20ms)", "%d", "%", int(mmu20 * 100)); ss.appendNumber("MMU (50ms)", "%d", "%", int(mmu50 * 100)); ss.appendDecimal("SCC Sweep Total", "ms", t(sccTotal)); ss.appendDecimal("SCC Sweep Max Pause", "ms", t(sccLongest)); if (nonincrementalReason || ss.isJSON()) { ss.appendString("Nonincremental Reason", nonincrementalReason ? nonincrementalReason : "none"); } @@ -478,35 +471,31 @@ Statistics::formatDescription() const char *format = "=================================================================\n\ Invocation Kind: %s\n\ Reason: %s\n\ Incremental: %s%s\n\ Zones Collected: %d of %d\n\ Compartments Collected: %d of %d\n\ MinorGCs since last GC: %d\n\ - Store Buffer Compactions: %d\n\ - Store Buffer Overflows: %d\n\ MMU 20ms:%.1f%%; 50ms:%.1f%%\n\ SCC Sweep Total (MaxPause): %.3fms (%.3fms)\n\ HeapSize: %.3f MiB\n\ Chunk Delta (magnitude): %+d (%d)\n\ "; char buffer[1024]; memset(buffer, 0, sizeof(buffer)); JS_snprintf(buffer, sizeof(buffer), format, ExplainInvocationKind(gckind), ExplainReason(slices[0].reason), nonincrementalReason ? "no - " : "yes", nonincrementalReason ? nonincrementalReason : "", zoneStats.collectedZoneCount, zoneStats.zoneCount, zoneStats.collectedCompartmentCount, zoneStats.compartmentCount, counts[STAT_MINOR_GC], - counts[STAT_COMPACT_STOREBUFFER], - counts[STAT_STOREBUFFER_OVERFLOW], mmu20 * 100., mmu50 * 100., t(sccTotal), t(sccLongest), double(preBytes) / 1024. / 1024., counts[STAT_NEW_CHUNK] - counts[STAT_DESTROY_CHUNK], counts[STAT_NEW_CHUNK] + counts[STAT_DESTROY_CHUNK]); return make_string_copy(buffer); } @@ -639,27 +628,23 @@ Statistics::formatJSON(uint64_t timestam Statistics::Statistics(JSRuntime *rt) : runtime(rt), startupTime(PRMJ_Now()), fp(nullptr), fullFormat(false), gcDepth(0), nonincrementalReason(nullptr), - timingMutator(false), - timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), sliceCallback(nullptr) { PodArrayZero(phaseTotals); PodArrayZero(counts); - PodArrayZero(phaseStartTimes); - PodArrayZero(phaseTimes); char *env = getenv("MOZ_GCTIMER"); if (!env || strcmp(env, "none") == 0) { fp = nullptr; return; } if (strcmp(env, "stdout") == 0) { @@ -733,16 +718,19 @@ Statistics::printStats() t(phaseTimes[PHASE_SWEEP])); } fflush(fp); } void Statistics::beginGC(JSGCInvocationKind kind) { + PodArrayZero(phaseStartTimes); + PodArrayZero(phaseTimes); + slices.clearAndFree(); sccTimes.clearAndFree(); gckind = kind; nonincrementalReason = nullptr; preBytes = runtime->gc.usage.gcBytes(); } @@ -774,21 +762,16 @@ Statistics::endGC() (*cb)(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); (*cb)(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); } if (fp) printStats(); - - // Clear the timers at the end of a GC because we accumulate time for some - // phases (eg storebuffer compaction) during the mutator's run. - PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); - PodZero(&phaseTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); } void Statistics::beginSlice(const ZoneGCStats &zoneStats, JSGCInvocationKind gckind, JS::gcreason::Reason reason) { this->zoneStats = zoneStats; @@ -836,92 +819,42 @@ Statistics::endSlice() } /* Do this after the slice callback since it uses these values. */ if (last) PodArrayZero(counts); } void -Statistics::startTimingMutator() -{ - MOZ_ASSERT(!timingMutator); - - // Should only be called from outside of GC - MOZ_ASSERT(phaseNestingDepth == 0); - - timingMutator = true; - timedGCTime = 0; - phaseStartTimes[PHASE_MUTATOR] = 0; - phaseTimes[PHASE_MUTATOR] = 0; - timedGCStart = 0; - - beginPhase(PHASE_MUTATOR); -} - -void -Statistics::stopTimingMutator(double &mutator_ms, double &gc_ms) -{ - MOZ_ASSERT(timingMutator); - - // Should only be called from outside of GC - MOZ_ASSERT(phaseNestingDepth == 1 && phaseNesting[0] == PHASE_MUTATOR); - - endPhase(PHASE_MUTATOR); - mutator_ms = t(phaseTimes[PHASE_MUTATOR]); - gc_ms = t(timedGCTime); - timingMutator = false; -} - -void Statistics::beginPhase(Phase phase) { /* Guard against re-entry */ MOZ_ASSERT(!phaseStartTimes[phase]); - if (timingMutator) { - if (phaseNestingDepth == 1 && phaseNesting[0] == PHASE_MUTATOR) { - endPhase(PHASE_MUTATOR); - timedGCStart = PRMJ_Now(); - } - } - #ifdef DEBUG MOZ_ASSERT(phases[phase].index == phase); Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT; MOZ_ASSERT(phaseNestingDepth < MAX_NESTING); MOZ_ASSERT_IF(gcDepth == 1, phases[phase].parent == parent); - MOZ_ASSERT_IF(phase == PHASE_COMPACT_STOREBUFFER_IN_MINOR_GC, parent == PHASE_MINOR_GC); - MOZ_ASSERT_IF(phase == PHASE_COMPACT_STOREBUFFER_NO_PARENT, parent == PHASE_NO_PARENT); - phaseNesting[phaseNestingDepth] = phase; phaseNestingDepth++; #endif phaseStartTimes[phase] = PRMJ_Now(); } void Statistics::endPhase(Phase phase) { phaseNestingDepth--; - int64_t now = PRMJ_Now(); - int64_t t = now - phaseStartTimes[phase]; - if (!slices.empty()) - slices.back().phaseTimes[phase] += t; + int64_t t = PRMJ_Now() - phaseStartTimes[phase]; + slices.back().phaseTimes[phase] += t; phaseTimes[phase] += t; phaseStartTimes[phase] = 0; - - if (timingMutator) { - if (phaseNestingDepth == 0 && phase != PHASE_MUTATOR) { - timedGCTime += now - timedGCStart; - beginPhase(PHASE_MUTATOR); - } - } } void Statistics::endParallelPhase(Phase phase, const GCParallelTask *task) { phaseNestingDepth--; slices.back().phaseTimes[phase] += task->duration();
--- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -22,17 +22,16 @@ struct JSCompartment; namespace js { class GCParallelTask; namespace gcstats { enum Phase { - PHASE_MUTATOR, PHASE_GC_BEGIN, PHASE_WAIT_BACKGROUND_THREAD, PHASE_MARK_DISCARD_CODE, PHASE_PURGE, PHASE_MARK, PHASE_MARK_ROOTS, PHASE_MARK_DELAYED, PHASE_SWEEP, @@ -66,35 +65,25 @@ enum Phase { PHASE_SWEEP_JITCODE, PHASE_FINALIZE_END, PHASE_DESTROY, PHASE_COMPACT, PHASE_COMPACT_MOVE, PHASE_COMPACT_UPDATE, PHASE_COMPACT_UPDATE_GRAY, PHASE_GC_END, - PHASE_MINOR_GC, - PHASE_COMPACT_STOREBUFFER_IN_MINOR_GC, - PHASE_COMPACT_STOREBUFFER_NO_PARENT, PHASE_LIMIT }; enum Stat { STAT_NEW_CHUNK, STAT_DESTROY_CHUNK, STAT_MINOR_GC, - // Number of times the storebuffers were compacted - STAT_COMPACT_STOREBUFFER, - - // Number of times a 'put' into a storebuffer overflowed, triggering a - // compaction - STAT_STOREBUFFER_OVERFLOW, - STAT_LIMIT }; class StatisticsSerializer; struct ZoneGCStats { /* Number of zones collected in this GC. */ @@ -124,19 +113,16 @@ struct Statistics void beginPhase(Phase phase); void endPhase(Phase phase); void endParallelPhase(Phase phase, const GCParallelTask *task); void beginSlice(const ZoneGCStats &zoneStats, JSGCInvocationKind gckind, JS::gcreason::Reason reason); void endSlice(); - void startTimingMutator(); - void stopTimingMutator(double &mutator_ms, double &gc_ms); - void reset(const char *reason) { slices.back().resetReason = reason; } void nonincremental(const char *reason) { nonincrementalReason = reason; } void count(Stat s) { MOZ_ASSERT(s < STAT_LIMIT); counts[s]++; } @@ -188,42 +174,37 @@ struct Statistics int64_t duration() const { return end - start; } }; Vector<SliceData, 8, SystemAllocPolicy> slices; /* Most recent time when the given phase started. */ int64_t phaseStartTimes[PHASE_LIMIT]; - /* Are we currently timing mutator vs GC time? */ - bool timingMutator; - - /* Bookkeeping for GC timings when timingMutator is true */ - int64_t timedGCStart; - int64_t timedGCTime; - /* Total time in a given phase for this GC. */ int64_t phaseTimes[PHASE_LIMIT]; /* Total time in a given phase over all GCs. */ int64_t phaseTotals[PHASE_LIMIT]; /* Number of events of this type for this GC. */ unsigned int counts[STAT_LIMIT]; /* Allocated space before the GC started. */ size_t preBytes; /* Records the maximum GC pause in an API-controlled interval (in us). */ int64_t maxPauseInInterval; +#ifdef DEBUG /* Phases that are currently on stack. */ static const size_t MAX_NESTING = 8; Phase phaseNesting[MAX_NESTING]; - size_t phaseNestingDepth; +#endif + mozilla::DebugOnly<size_t> phaseNestingDepth; /* Sweep times for SCCs of compartments. */ Vector<int64_t, 0, SystemAllocPolicy> sccTimes; JS::GCSliceCallback sliceCallback; void beginGC(JSGCInvocationKind kind); void endGC();
--- a/js/src/gc/StoreBuffer.cpp +++ b/js/src/gc/StoreBuffer.cpp @@ -5,32 +5,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef JSGC_GENERATIONAL #include "gc/StoreBuffer.h" #include "mozilla/Assertions.h" -#include "gc/Statistics.h" #include "vm/ArgumentsObject.h" #include "vm/ForkJoin.h" #include "jsgcinlines.h" using namespace js; using namespace js::gc; using mozilla::ReentrancyGuard; -gcstats::Statistics& -StoreBuffer::stats() -{ - return runtime_->gc.stats; -} - /*** Edges ***/ void StoreBuffer::SlotsEdge::mark(JSTracer *trc) { NativeObject *obj = object(); // Beware JSObject::swap exchanging a native object for a non-native one. @@ -95,30 +88,26 @@ template <typename T> void StoreBuffer::MonoTypeBuffer<T>::handleOverflow(StoreBuffer *owner) { if (!owner->isAboutToOverflow()) { /* * Compact the buffer now, and if that fails to free enough space then * trigger a minor collection. */ - gcstats::AutoPhase ap(owner->stats(), gcstats::PHASE_COMPACT_STOREBUFFER_NO_PARENT); - owner->stats().count(gcstats::STAT_STOREBUFFER_OVERFLOW); compact(owner); if (isLowOnSpace()) owner->setAboutToOverflow(); } else { /* * A minor GC has already been triggered, so there's no point * compacting unless the buffer is totally full. */ - if (storage_->availableInCurrentChunk() < sizeof(T)) { - owner->stats().count(gcstats::STAT_STOREBUFFER_OVERFLOW); - maybeCompact(owner, gcstats::PHASE_COMPACT_STOREBUFFER_NO_PARENT); - } + if (storage_->availableInCurrentChunk() < sizeof(T)) + maybeCompact(owner); } } template <typename T> void StoreBuffer::MonoTypeBuffer<T>::compactRemoveDuplicates(StoreBuffer *owner) { typedef HashSet<T, typename T::Hasher, SystemAllocPolicy> DedupSet; @@ -136,50 +125,46 @@ StoreBuffer::MonoTypeBuffer<T>::compactR /* Failure to insert will leave the set with duplicates. Oh well. */ duplicates.put(*edge); } } storage_->release(insert.mark()); duplicates.clear(); - owner->stats().count(gcstats::STAT_COMPACT_STOREBUFFER); } template <typename T> void StoreBuffer::MonoTypeBuffer<T>::compact(StoreBuffer *owner) { MOZ_ASSERT(storage_); compactRemoveDuplicates(owner); usedAtLastCompact_ = storage_->used(); } template <typename T> void -StoreBuffer::MonoTypeBuffer<T>::maybeCompact(StoreBuffer *owner, int phase) +StoreBuffer::MonoTypeBuffer<T>::maybeCompact(StoreBuffer *owner) { MOZ_ASSERT(storage_); - if (storage_->used() != usedAtLastCompact_) { - gcstats::AutoPhase ap(owner->stats(), static_cast<gcstats::Phase>(phase)); + if (storage_->used() != usedAtLastCompact_) compact(owner); - } } template <typename T> void StoreBuffer::MonoTypeBuffer<T>::mark(StoreBuffer *owner, JSTracer *trc) { MOZ_ASSERT(owner->isEnabled()); ReentrancyGuard g(*owner); if (!storage_) return; - maybeCompact(owner, gcstats::PHASE_COMPACT_STOREBUFFER_IN_MINOR_GC); - + maybeCompact(owner); for (LifoAlloc::Enum e(*storage_); !e.empty(); e.popFront<T>()) { T *edge = e.get<T>(); edge->mark(trc); } } /*** RelocatableMonoTypeBuffer ***/
--- a/js/src/gc/StoreBuffer.h +++ b/js/src/gc/StoreBuffer.h @@ -17,20 +17,16 @@ #include "ds/LifoAlloc.h" #include "gc/Nursery.h" #include "gc/Tracer.h" #include "js/MemoryMetrics.h" namespace js { -namespace gcstats { -struct Statistics; -} - MOZ_NORETURN void CrashAtUnhandlableOOM(const char *reason); namespace gc { /* * BufferableRef represents an abstract reference for use in the generational * GC's remembered set. Entries in the store buffer that cannot be represented @@ -139,17 +135,17 @@ class StoreBuffer /* * Attempts to reduce the usage of the buffer by removing unnecessary * entries. */ virtual void compact(StoreBuffer *owner); /* Compacts if any entries have been added since the last compaction. */ - void maybeCompact(StoreBuffer *owner, int phase); + void maybeCompact(StoreBuffer *owner); /* Add one item to the buffer. */ void put(StoreBuffer *owner, const T &t) { MOZ_ASSERT(storage_); T *tp = storage_->new_<T>(t); if (!tp) CrashAtUnhandlableOOM("Failed to allocate for MonoTypeBuffer::put."); @@ -488,18 +484,16 @@ class StoreBuffer void putGeneric(const T &t) { putFromAnyThread(bufferGeneric, t);} /* Insert or update a callback entry. */ template <typename Key> void putCallback(void (*callback)(JSTracer *trc, Key *key, void *data), Key *key, void *data) { putFromAnyThread(bufferGeneric, CallbackRef<Key>(callback, key, data)); } - gcstats::Statistics& stats(); - /* Methods to mark the source of all edges in the store buffer. */ void markAll(JSTracer *trc); void markValues(JSTracer *trc) { bufferVal.mark(this, trc); } void markCells(JSTracer *trc) { bufferCell.mark(this, trc); } void markSlots(JSTracer *trc) { bufferSlot.mark(this, trc); } void markWholeCells(JSTracer *trc) { bufferWholeCell.mark(this, trc); } void markRelocatableValues(JSTracer *trc) { bufferRelocVal.mark(this, trc); } void markRelocatableCells(JSTracer *trc) { bufferRelocCell.mark(this, trc); }
--- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -498,20 +498,17 @@ js::gc::GCRuntime::endVerifyPostBarriers VerifyPostTracer::EdgeSet edges; AutoPrepareForTracing prep(rt, SkipAtoms); /* Visit every entry in the store buffer and put the edges in a hash set. */ trc->setTraceCallback(PostVerifierCollectStoreBufferEdges); if (!edges.init()) goto oom; trc->edges = &edges; - { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC); - storeBuffer.markAll(trc); - } + storeBuffer.markAll(trc); /* Walk the heap to find any edges not the the |edges| set. */ trc->setTraceCallback(PostVerifierVisitEdge); for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) { for (ZoneCellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) { Cell *src = cells.getCell(); JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind)));
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6212,32 +6212,30 @@ GCRuntime::shrinkBuffers() else expireChunksAndArenas(true, lock); } void GCRuntime::minorGC(JS::gcreason::Reason reason) { #ifdef JSGC_GENERATIONAL - gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC); minorGCRequested = false; TraceLogger *logger = TraceLoggerForMainThread(rt); AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC); nursery.collect(rt, reason, nullptr); MOZ_ASSERT_IF(!rt->mainThread.suppressGC, nursery.isEmpty()); #endif } void GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason) { // Alternate to the runtime-taking form above which allows marking type // objects as needing pretenuring. #ifdef JSGC_GENERATIONAL - gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC); minorGCRequested = false; TraceLogger *logger = TraceLoggerForMainThread(rt); AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC); Nursery::TypeObjectList pretenureTypes; nursery.collect(rt, reason, &pretenureTypes); for (size_t i = 0; i < pretenureTypes.length(); i++) { if (pretenureTypes[i]->canPreTenure()) pretenureTypes[i]->setShouldPreTenure(cx);
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1655,53 +1655,16 @@ Quit(JSContext *cx, unsigned argc, jsval CallArgs args = CallArgsFromVp(argc, vp); JS_ConvertArguments(cx, args, "/ i", &gExitCode); gQuitting = true; return false; } -static bool -StartTimingMutator(JSContext *cx, unsigned argc, jsval *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() > 0) { - JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, - JSSMSG_TOO_MANY_ARGS, "startTimingMutator"); - return false; - } - - cx->runtime()->gc.stats.startTimingMutator(); - args.rval().setUndefined(); - return true; -} - -static bool -StopTimingMutator(JSContext *cx, unsigned argc, jsval *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() > 0) { - JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, - JSSMSG_TOO_MANY_ARGS, "stopTimingMutator"); - return false; - } - - double mutator_ms, gc_ms; - cx->runtime()->gc.stats.stopTimingMutator(mutator_ms, gc_ms); - double total_ms = mutator_ms + gc_ms; - if (total_ms > 0) { - fprintf(gOutFile, "Mutator: %.3fms (%.1f%%), GC: %.3fms (%.1f%%)\n", - mutator_ms, mutator_ms / total_ms * 100.0, gc_ms, gc_ms / total_ms * 100.0); - } - - args.rval().setUndefined(); - return true; -} - static const char * ToSource(JSContext *cx, MutableHandleValue vp, JSAutoByteString *bytes) { JSString *str = JS_ValueToSource(cx, vp); if (str) { vp.setString(str); if (bytes->encodeLatin1(cx, str)) return bytes->ptr(); @@ -4490,24 +4453,16 @@ static const JSFunctionSpecWithHelp shel "quit()", " Quit the shell."), JS_FN_HELP("assertEq", AssertEq, 2, 0, "assertEq(actual, expected[, msg])", " Throw if the first two arguments are not the same (both +0 or both -0,\n" " both NaN, or non-zero and ===)."), - JS_FN_HELP("startTimingMutator", StartTimingMutator, 0, 0, -"startTimingMutator()", -" Start accounting time to mutator vs GC."), - - JS_FN_HELP("stopTimingMutator", StopTimingMutator, 0, 0, -"stopTimingMutator()", -" Stop accounting time to mutator vs GC and dump the results."), - JS_FN_HELP("throwError", ThrowError, 0, 0, "throwError()", " Throw an error from JS_ReportError."), #ifdef DEBUG JS_FN_HELP("disassemble", DisassembleToString, 1, 0, "disassemble([fun])", " Return the disassembly for the given function."),