зеркало из https://github.com/mozilla/gecko-dev.git
Bug 976260 - Register javascript performance events with the profiler. r=jandem
This commit is contained in:
Родитель
546a09676a
Коммит
88eff64bd1
|
@ -91,6 +91,9 @@ SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
|
|||
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);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 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"
|
||||
|
@ -975,14 +976,34 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
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;
|
||||
|
|
|
@ -6226,6 +6226,19 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
|
||||
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.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "TraceLogging.h"
|
||||
#endif
|
||||
|
||||
#include "jsprf.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "jit/AliasAnalysis.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
|
@ -2621,6 +2622,27 @@ jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetU
|
|||
{
|
||||
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) {
|
||||
|
|
|
@ -52,7 +52,6 @@ enum BailoutKind
|
|||
static const uint32_t BAILOUT_KIND_BITS = 3;
|
||||
static const uint32_t BAILOUT_RESUME_BITS = 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
inline const char *
|
||||
BailoutKindString(BailoutKind kind)
|
||||
{
|
||||
|
@ -71,7 +70,6 @@ BailoutKindString(BailoutKind kind)
|
|||
MOZ_ASSUME_UNREACHABLE("Invalid BailoutKind");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const uint32_t ELEMENT_TYPE_BITS = 4;
|
||||
static const uint32_t ELEMENT_TYPE_SHIFT = 0;
|
||||
|
|
|
@ -4275,6 +4275,22 @@ SetCachingEnabled(JSContext *cx, unsigned argc, Value *vp)
|
|||
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])",
|
||||
|
@ -4615,6 +4631,11 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
" 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
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ SPSProfiler::SPSProfiler(JSRuntime *rt)
|
|||
max_(0),
|
||||
slowAssertions(false),
|
||||
enabled_(false),
|
||||
lock_(nullptr)
|
||||
lock_(nullptr),
|
||||
eventMarker_(nullptr)
|
||||
{
|
||||
JS_ASSERT(rt != nullptr);
|
||||
}
|
||||
|
@ -66,6 +67,12 @@ SPSProfiler::setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max
|
|||
max_ = max;
|
||||
}
|
||||
|
||||
void
|
||||
SPSProfiler::setEventMarker(void (*fn)(const char *))
|
||||
{
|
||||
eventMarker_ = fn;
|
||||
}
|
||||
|
||||
void
|
||||
SPSProfiler::enable(bool enabled)
|
||||
{
|
||||
|
@ -331,6 +338,13 @@ 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)
|
||||
{
|
||||
|
|
|
@ -125,6 +125,7 @@ class SPSProfiler
|
|||
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);
|
||||
|
@ -191,9 +192,16 @@ class SPSProfiler
|
|||
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) {
|
||||
JS_ASSERT(enabled());
|
||||
if (eventMarker_)
|
||||
eventMarker_(event);
|
||||
}
|
||||
|
||||
/* meant to be used for testing, not recommended to call in normal code */
|
||||
size_t stringsCount();
|
||||
void stringsReset();
|
||||
|
|
|
@ -143,3 +143,8 @@ IOMarkerPayload::preparePayloadImp<JSCustomObjectBuilder>(JSCustomObjectBuilder&
|
|||
template JSObjectBuilder::Object
|
||||
IOMarkerPayload::preparePayloadImp<JSObjectBuilder>(JSObjectBuilder& b);
|
||||
|
||||
void
|
||||
ProfilerJSEventMarker(const char *event)
|
||||
{
|
||||
PROFILER_MARKER(event);
|
||||
}
|
||||
|
|
|
@ -292,6 +292,9 @@ private:
|
|||
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
|
||||
|
@ -398,6 +401,7 @@ public:
|
|||
void enableJSSampling() {
|
||||
if (mRuntime) {
|
||||
js::EnableRuntimeProfilingStack(mRuntime, true);
|
||||
js::RegisterRuntimeProfilingEventMarker(mRuntime, &ProfilerJSEventMarker);
|
||||
mStartJSSampling = false;
|
||||
} else {
|
||||
mStartJSSampling = true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче