author | Kannan Vijayan <kvijayan@mozilla.com> |
Mon, 03 Mar 2014 14:36:08 -0500 (2014-03-03) | |
changeset 171550 | b37ed02f9f4b1da4fb0fcd183f4982045a5d7a44 |
parent 171549 | 06eb9d02fd2a9a7eb8fbeb875bc4298d38504b76 |
child 171551 | dd4e1e3a72a5dcc42118356d0e676ea06842be33 |
push id | 40499 |
push user | kvijayan@mozilla.com |
push date | Mon, 03 Mar 2014 19:36:41 +0000 (2014-03-03) |
treeherder | mozilla-inbound@b37ed02f9f4b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 976260 |
milestone | 30.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/public/ProfilingStack.h +++ b/js/public/ProfilingStack.h @@ -86,14 +86,17 @@ class ProfileEntry JS_FRIEND_API(void) SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max); JS_FRIEND_API(void) EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled); +JS_FRIEND_API(void) +RegisterRuntimeProfilingEventMarker(JSRuntime *rt, void (*fn)(const char *)); + JS_FRIEND_API(jsbytecode*) ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip); } // namespace js #endif /* js_ProfilingStack_h */
--- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1,14 +1,15 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "jsprf.h" #include "jit/arm/Simulator-arm.h" #include "jit/BaselineIC.h" #include "jit/BaselineJIT.h" #include "jit/CompileInfo.h" #include "jit/IonSpewer.h" #include "vm/ArgumentsObject.h" #include "jsscriptinlines.h" @@ -970,24 +971,44 @@ InitFromBailout(JSContext *cx, HandleScr } } else { opReturnAddr = nativeCodeForPC; } builder.setResumeAddr(opReturnAddr); IonSpew(IonSpew_BaselineBailouts, " Set resumeAddr=%p", opReturnAddr); } - if (cx->runtime()->spsProfiler.enabled() && blFrame->hasPushedSPSFrame()) { - // Set PC index to 0 for the innermost frame to match what the - // interpreter and Baseline do: they update the SPS pc for - // JSOP_CALL ops but set it to 0 when running other ops. Ion code - // can set the pc to NullPCIndex and this will confuse SPS when - // Baseline calls into the VM at non-CALL ops and re-enters JS. - IonSpew(IonSpew_BaselineBailouts, " Setting PCidx for last frame to 0"); - cx->runtime()->spsProfiler.updatePC(script, script->code()); + if (cx->runtime()->spsProfiler.enabled()) { + if (blFrame->hasPushedSPSFrame()) { + // Set PC index to 0 for the innermost frame to match what the + // interpreter and Baseline do: they update the SPS pc for + // JSOP_CALL ops but set it to 0 when running other ops. Ion code + // can set the pc to NullPCIndex and this will confuse SPS when + // Baseline calls into the VM at non-CALL ops and re-enters JS. + IonSpew(IonSpew_BaselineBailouts, " Setting PCidx for last frame to 0"); + cx->runtime()->spsProfiler.updatePC(script, script->code()); + } + + // Register bailout with profiler. + const char *filename = script->filename(); + if (filename == nullptr) + filename = "<unknown>"; + unsigned len = strlen(filename) + 200; + char *buf = js_pod_malloc<char>(len); + if (buf == nullptr) + return false; + JS_snprintf(buf, len, "%s %s %s on line %d of %s:%d", + BailoutKindString(bailoutKind), + resumeAfter ? "after" : "at", + js_CodeName[op], + int(PCToLineNumber(script, pc)), + filename, + int(script->lineno())); + cx->runtime()->spsProfiler.markEvent(buf); + js_free(buf); } return true; } *callPC = pc; // Write out descriptor of BaselineJS frame.
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8,16 +8,17 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "jslibmath.h" #include "jsmath.h" #include "jsnum.h" +#include "jsprf.h" #include "builtin/Eval.h" #include "builtin/TypedObject.h" #ifdef JSGC_GENERATIONAL # include "gc/Nursery.h" #endif #include "jit/ExecutionModeInlines.h" #include "jit/IonCaches.h" @@ -6221,16 +6222,29 @@ CodeGenerator::link(JSContext *cx, types ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset()); // If SPS is enabled, mark IonScript as having been instrumented with SPS if (sps_.enabled()) ionScript->setHasSPSInstrumentation(); SetIonScript(script, executionMode, ionScript); + if (cx->runtime()->spsProfiler.enabled()) { + const char *filename = script->filename(); + if (filename == nullptr) + filename = "<unknown>"; + unsigned len = strlen(filename) + 50; + char *buf = js_pod_malloc<char>(len); + if (!buf) + return false; + JS_snprintf(buf, len, "Ion compiled %s:%d", filename, (int) script->lineno()); + cx->runtime()->spsProfiler.markEvent(buf); + js_free(buf); + } + // In parallel execution mode, when we first compile a script, we // don't know that its potential callees are compiled, so set a // flag warning that the callees may not be fully compiled. if (!callTargets.empty()) ionScript->setHasUncompiledCallTarget(); invalidateEpilogueData_.fixup(&masm); Assembler::patchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -10,16 +10,17 @@ #include "mozilla/ThreadLocal.h" #include "jscompartment.h" #include "jsworkers.h" #if JS_TRACE_LOGGING #include "TraceLogging.h" #endif +#include "jsprf.h" #include "gc/Marking.h" #include "jit/AliasAnalysis.h" #include "jit/AsmJSModule.h" #include "jit/BacktrackingAllocator.h" #include "jit/BaselineFrame.h" #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/CodeGenerator.h" @@ -2616,16 +2617,37 @@ jit::Invalidate(JSContext *cx, const Vec } bool jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses, bool cancelOffThread) { JS_ASSERT(script->hasIonScript()); + if (cx->runtime()->spsProfiler.enabled()) { + // Register invalidation with profiler. + // Format of event payload string: + // "<filename>:<lineno>" + + // Get the script filename, if any, and its length. + const char *filename = script->filename(); + if (filename == nullptr) + filename = "<unknown>"; + + size_t len = strlen(filename) + 20; + char *buf = js_pod_malloc<char>(len); + if (!buf) + return false; + + // Construct the descriptive string. + JS_snprintf(buf, len, "Invalidate %s:%llu", filename, script->lineno()); + cx->runtime()->spsProfiler.markEvent(buf); + js_free(buf); + } + Vector<types::RecompileInfo> scripts(cx); switch (mode) { case SequentialExecution: JS_ASSERT(script->hasIonScript()); if (!scripts.append(script->ionScript()->recompileInfo())) return false; break;
--- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -47,17 +47,16 @@ enum BailoutKind // A bailout caused by invalid assumptions based on Baseline code. Bailout_BaselineInfo }; static const uint32_t BAILOUT_KIND_BITS = 3; static const uint32_t BAILOUT_RESUME_BITS = 1; -#ifdef DEBUG inline const char * BailoutKindString(BailoutKind kind) { switch (kind) { case Bailout_Normal: return "Bailout_Normal"; case Bailout_ArgumentCheck: return "Bailout_ArgumentCheck"; @@ -66,17 +65,16 @@ BailoutKindString(BailoutKind kind) case Bailout_ShapeGuard: return "Bailout_ShapeGuard"; case Bailout_BaselineInfo: return "Bailout_BaselineInfo"; default: MOZ_ASSUME_UNREACHABLE("Invalid BailoutKind"); } } -#endif static const uint32_t ELEMENT_TYPE_BITS = 4; static const uint32_t ELEMENT_TYPE_SHIFT = 0; static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1; static const uint32_t VECTOR_SCALE_BITS = 2; static const uint32_t VECTOR_SCALE_SHIFT = ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT; static const uint32_t VECTOR_SCALE_MASK = (1 << VECTOR_SCALE_BITS) - 1;
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4276,16 +4276,32 @@ static bool SetCachingEnabled(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); jsCachingEnabled = ToBoolean(args.get(0)); args.rval().setUndefined(); return true; } +static void +PrintProfilerEvents_Callback(const char *msg) +{ + fprintf(stderr, "PROFILER EVENT: %s\n", msg); +} + +static bool +PrintProfilerEvents(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (cx->runtime()->spsProfiler.enabled()) + js::RegisterRuntimeProfilingEventMarker(cx->runtime(), &PrintProfilerEvents_Callback); + args.rval().setUndefined(); + return true; +} + static const JSFunctionSpecWithHelp shell_functions[] = { JS_FN_HELP("version", Version, 0, 0, "version([number])", " Get or force a script compilation version number."), JS_FN_HELP("options", Options, 0, 0, "options([option ...])", " Get or toggle JavaScript options."), @@ -4616,16 +4632,21 @@ static const JSFunctionSpecWithHelp shel JS_FN_HELP("cacheEntry", CacheEntry, 1, 0, "cacheEntry(code)", " Return a new opaque object which emulates a cache entry of a script. This\n" " object encapsulates the code and its cached content. The cache entry is filled\n" " and read by the \"evaluate\" function by using it in place of the source, and\n" " by setting \"saveBytecode\" and \"loadBytecode\" options."), + JS_FN_HELP("printProfilerEvents", PrintProfilerEvents, 0, 0, +"printProfilerEvents()", +" Register a callback with the profiler that prints javascript profiler events\n" +" to stderr. Callback is only registered if profiling is enabled."), + JS_FS_HELP_END }; static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { JS_FN_HELP("clone", Clone, 1, 0, "clone(fun[, scope])", " Clone function object."),
--- a/js/src/vm/SPSProfiler.cpp +++ b/js/src/vm/SPSProfiler.cpp @@ -21,17 +21,18 @@ using mozilla::DebugOnly; SPSProfiler::SPSProfiler(JSRuntime *rt) : rt(rt), stack_(nullptr), size_(nullptr), max_(0), slowAssertions(false), enabled_(false), - lock_(nullptr) + lock_(nullptr), + eventMarker_(nullptr) { JS_ASSERT(rt != nullptr); } bool SPSProfiler::init() { #ifdef JS_THREADSAFE @@ -62,16 +63,22 @@ SPSProfiler::setProfilingStack(ProfileEn if (!strings.initialized()) strings.init(); stack_ = stack; size_ = size; max_ = max; } void +SPSProfiler::setEventMarker(void (*fn)(const char *)) +{ + eventMarker_ = fn; +} + +void SPSProfiler::enable(bool enabled) { JS_ASSERT(installed()); if (enabled_ == enabled) return; /* @@ -126,16 +133,26 @@ SPSProfiler::onScriptFinalized(JSScript return; if (ProfileStringMap::Ptr entry = strings.lookup(script)) { const char *tofree = entry->value(); strings.remove(entry); js_free(const_cast<char *>(tofree)); } } +void +SPSProfiler::markEvent(const char *event) +{ + JS_ASSERT(enabled()); + if (eventMarker_) { + JS::AutoAssertNoGC nogc; + eventMarker_(event); + } +} + bool SPSProfiler::enter(JSScript *script, JSFunction *maybeFun) { const char *str = profileString(script, maybeFun); if (str == nullptr) return false; #ifdef DEBUG @@ -326,13 +343,20 @@ js::SetRuntimeProfilingStack(JSRuntime * } JS_FRIEND_API(void) js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled) { rt->spsProfiler.enable(enabled); } +JS_FRIEND_API(void) +js::RegisterRuntimeProfilingEventMarker(JSRuntime *rt, void (*fn)(const char *)) +{ + JS_ASSERT(rt->spsProfiler.enabled()); + rt->spsProfiler.setEventMarker(fn); +} + JS_FRIEND_API(jsbytecode*) js::ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip) { return rt->spsProfiler.ipToPC(script, size_t(ip)); }
--- a/js/src/vm/SPSProfiler.h +++ b/js/src/vm/SPSProfiler.h @@ -120,16 +120,17 @@ class SPSProfiler JSRuntime *rt; ProfileStringMap strings; ProfileEntry *stack_; uint32_t *size_; uint32_t max_; bool slowAssertions; uint32_t enabled_; PRLock *lock_; + void (*eventMarker_)(const char *); const char *allocProfileString(JSScript *script, JSFunction *function); void push(const char *string, void *sp, JSScript *script, jsbytecode *pc); void pushNoCopy(const char *string, void *sp, JSScript *script, jsbytecode *pc) { push(string, reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(sp) | ProfileEntry::NoCopyBit), script, pc); @@ -186,19 +187,22 @@ class SPSProfiler /* Enter a C++ function. */ void enterNative(const char *string, void *sp); void exitNative() { pop(); } jsbytecode *ipToPC(JSScript *script, size_t ip) { return nullptr; } void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max); + void setEventMarker(void (*fn)(const char *)); const char *profileString(JSScript *script, JSFunction *maybeFun); void onScriptFinalized(JSScript *script); + void markEvent(const char *event); + /* meant to be used for testing, not recommended to call in normal code */ size_t stringsCount(); void stringsReset(); uint32_t *addressOfEnabled() { return &enabled_; } };
--- a/tools/profiler/ProfilerMarkers.cpp +++ b/tools/profiler/ProfilerMarkers.cpp @@ -138,8 +138,13 @@ IOMarkerPayload::preparePayloadImp(Build return data; } template JSCustomObjectBuilder::Object IOMarkerPayload::preparePayloadImp<JSCustomObjectBuilder>(JSCustomObjectBuilder& b); template JSObjectBuilder::Object IOMarkerPayload::preparePayloadImp<JSObjectBuilder>(JSObjectBuilder& b); +void +ProfilerJSEventMarker(const char *event) +{ + PROFILER_MARKER(event); +}
--- a/tools/profiler/PseudoStack.h +++ b/tools/profiler/PseudoStack.h @@ -287,16 +287,19 @@ public: return &mPendingUWTBuffers; } private: UWTBufferLinkedList mPendingUWTBuffers; volatile bool mSignalLock; }; +// Stub eventMarker function for js-engine event generation. +void ProfilerJSEventMarker(const char *event); + // the PseudoStack members are read by signal // handlers, so the mutation of them needs to be signal-safe. struct PseudoStack { public: PseudoStack() : mStackPointer(0) , mRuntime(nullptr) @@ -393,16 +396,17 @@ public: (uint32_t*) &mStackPointer, uint32_t(mozilla::ArrayLength(mStack))); if (mStartJSSampling) enableJSSampling(); } void enableJSSampling() { if (mRuntime) { js::EnableRuntimeProfilingStack(mRuntime, true); + js::RegisterRuntimeProfilingEventMarker(mRuntime, &ProfilerJSEventMarker); mStartJSSampling = false; } else { mStartJSSampling = true; } } void jsOperationCallback() { if (mStartJSSampling) enableJSSampling();