Bug 1045063 - TraceLogging: Don't keep track of stack while disabled, r=bbouvier

This commit is contained in:
Hannes Verschore 2014-08-01 20:16:27 +02:00
parent 3c8c24351c
commit d86704b06c
4 changed files with 132 additions and 113 deletions

View File

@ -1616,7 +1616,7 @@ EnableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
args.rval().setBoolean(TraceLoggerEnable(logger));
args.rval().setBoolean(TraceLoggerEnable(logger, cx));
return true;
}

View File

@ -1005,17 +1005,23 @@ CodeGeneratorShared::computeDivisionConstants(int d) {
bool
CodeGeneratorShared::emitTracelogScript(bool isStart)
{
Label done;
RegisterSet regs = RegisterSet::Volatile();
Register logger = regs.takeGeneral();
Register script = regs.takeGeneral();
masm.Push(logger);
masm.Push(script);
CodeOffsetLabel patchLogger = masm.movWithPatch(ImmPtr(nullptr), logger);
if (!patchableTraceLoggers_.append(patchLogger))
return false;
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
masm.Push(script);
CodeOffsetLabel patchScript = masm.movWithPatch(ImmWord(0), script);
if (!patchableTLScripts_.append(patchScript))
return false;
@ -1026,6 +1032,9 @@ CodeGeneratorShared::emitTracelogScript(bool isStart)
masm.tracelogStop(logger, script);
masm.Pop(script);
masm.bind(&done);
masm.Pop(logger);
return true;
}
@ -1036,6 +1045,7 @@ CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
if (!TraceLogTextIdEnabled(textId))
return true;
Label done;
RegisterSet regs = RegisterSet::Volatile();
Register logger = regs.takeGeneral();
@ -1045,6 +1055,9 @@ CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
if (!patchableTraceLoggers_.append(patchLocation))
return false;
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
if (isStart) {
masm.tracelogStart(logger, textId);
} else {
@ -1055,6 +1068,8 @@ CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
#endif
}
masm.bind(&done);
masm.Pop(logger);
return true;
}

View File

@ -17,7 +17,10 @@
#include "jit/CompileWrappers.h"
#include "vm/Runtime.h"
#include "jit/IonFrames-inl.h"
using namespace js;
using namespace js::jit;
using mozilla::NativeEndian;
#ifndef TRACE_LOG_DIR
@ -85,8 +88,7 @@ static const char* const text[] =
};
TraceLogger::TraceLogger()
: enabled(false),
enabledTimes(0),
: enabled(0),
failed(false),
nextTextId(0),
treeOffset(0),
@ -157,82 +159,89 @@ TraceLogger::init(uint32_t loggerId)
MOZ_ASSERT(textId == i);
}
enabled = true;
enabledTimes = 1;
enabled = 1;
return true;
}
bool
TraceLogger::enable()
{
if (enabled) {
enabledTimes++;
if (enabled > 0) {
enabled++;
return true;
}
if (failed)
return false;
if (!tree.ensureSpaceBeforeAdd(stack.size())) {
if (!flush()) {
fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
enabled = 1;
return true;
}
bool
TraceLogger::enable(JSContext *cx)
{
if (!enable())
return false;
if (enabled == 1) {
// Get the top Activation to log the top script/pc (No inlined frames).
Activation *act = cx->mainThread().activation();
while (act && (act->cx() != cx || (act->isJit() && !act->asJit()->isActive())))
act = act->prev();
if (!act) {
failed = true;
enabled = 0;
return false;
}
if (!tree.ensureSpaceBeforeAdd(stack.size())) {
fprintf(stderr, "TraceLogging: Couldn't reserve enough space.\n");
failed = true;
return false;
}
}
uint64_t start = rdtsc() - traceLoggers.startupTime;
StackEntry *parent = &stack[0];
for (uint32_t i = 1; i < stack.size(); i++) {
if (!traceLoggers.isTextIdEnabled(stack[i].textId()))
continue;
#ifdef DEBUG
TreeEntry entry;
if (!getTreeEntry(parent->treeId(), &entry))
return false;
#endif
JSScript *script = nullptr;
int32_t engine = 0;
if (parent->lastChildId() == 0) {
MOZ_ASSERT(!entry.hasChildren());
MOZ_ASSERT(parent->treeId() == tree.currentId() + treeOffset);
if (!updateHasChildren(parent->treeId())) {
fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
failed = true;
return false;
if (act->isJit()) {
JSRuntime *rt = cx->runtime();
JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution);
JS_ASSERT(it.type() == JitFrame_Exit);
++it;
if (it.type() == JitFrame_Rectifier ||
it.type() == JitFrame_Unwound_Rectifier)
{
++it;
JS_ASSERT(it.type() == JitFrame_BaselineStub ||
it.type() == JitFrame_BaselineJS ||
it.type() == JitFrame_IonJS);
}
if (it.type() == JitFrame_BaselineStub ||
it.type() == JitFrame_Unwound_BaselineStub)
{
++it;
JS_ASSERT(it.type() == JitFrame_BaselineJS);
}
script = it.script();
engine = it.isIonJS() ? IonMonkey : Baseline;
} else {
MOZ_ASSERT(entry.hasChildren() == 1);
if (!updateNextId(parent->lastChildId(), tree.nextId() + treeOffset)) {
fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
JS_ASSERT(act->isInterpreter());
InterpreterFrame *fp = act->asInterpreter()->current();
JS_ASSERT(!fp->runningInJit());
script = fp->script();
engine = Interpreter;
if (script->compartment() != cx->compartment()) {
failed = true;
enabled = 0;
return false;
}
}
TreeEntry &treeEntry = tree.pushUninitialized();
treeEntry.setStart(start);
treeEntry.setStop(0);
treeEntry.setTextId(stack[i].textId());
treeEntry.setHasChildren(false);
treeEntry.setNextId(0);
stack[i].setActive(true);
stack[i].setTreeId(tree.currentId() + treeOffset);
stack[i].setLastChildId(0);
parent->setLastChildId(tree.currentId() + treeOffset);
parent = &stack[i];
startEvent(createTextId(script));
startEvent(engine);
}
enabled = true;
enabledTimes = 1;
return true;
}
@ -242,32 +251,19 @@ TraceLogger::disable()
if (failed)
return false;
if (!enabled)
if (enabled == 0)
return true;
if (enabledTimes > 1) {
enabledTimes--;
if (enabled > 1) {
enabled--;
return true;
}
uint64_t stop = rdtsc() - traceLoggers.startupTime;
for (uint32_t i = 1; i < stack.size(); i++) {
if (!stack[i].active())
continue;
JS_ASSERT(enabled == 1);
while (stack.currentId() > 0)
stopEvent();
if (!updateStop(stack[i].treeId(), stop)) {
fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
failed = true;
enabled = false;
return false;
}
stack[i].setActive(false);
}
enabled = false;
enabledTimes = 0;
enabled = 0;
return true;
}
@ -326,15 +322,15 @@ TraceLogger::~TraceLogger()
// Make sure every start entry has a corresponding stop value.
// We temporary enable logging for this. Stop doesn't need any extra data,
// so is safe to do, even when we encountered OOM.
enabled = true;
enabled = 1;
while (stack.currentId() > 0)
stopEvent();
enabled = false;
enabled = 0;
}
if (!failed && !flush()) {
fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
enabled = false;
enabled = 0;
failed = true;
}
@ -439,12 +435,12 @@ TraceLogger::createTextId(const JS::ReadOnlyCompileOptions &compileOptions)
void
TraceLogger::logTimestamp(uint32_t id)
{
if (!enabled)
if (enabled == 0)
return;
if (!events.ensureSpaceBeforeAdd()) {
fprintf(stderr, "TraceLogging: Disabled a tracelogger due to OOM.\n");
enabled = false;
enabled = 0;
return;
}
@ -569,31 +565,15 @@ TraceLogger::updateStop(uint32_t treeId, uint64_t timestamp)
void
TraceLogger::startEvent(uint32_t id)
{
if (failed)
if (failed || enabled == 0)
return;
if (!stack.ensureSpaceBeforeAdd()) {
fprintf(stderr, "TraceLogging: Failed to allocate space to keep track of the stack.\n");
enabled = false;
failed = true;
return;
}
if (!enabled) {
StackEntry &stackEntry = stack.pushUninitialized();
stackEntry.setTreeId(tree.currentId() + treeOffset);
stackEntry.setLastChildId(0);
stackEntry.setTextId(id);
stackEntry.setActive(false);
return;
}
if (!tree.hasSpaceForAdd()){
uint64_t start = rdtsc() - traceLoggers.startupTime;
if (!tree.ensureSpaceBeforeAdd()) {
if (!flush()) {
fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
enabled = false;
enabled = 0;
failed = true;
return;
}
@ -603,7 +583,7 @@ TraceLogger::startEvent(uint32_t id)
// Tracelogger.
if (!startEvent(TraceLogger::TL, start)) {
fprintf(stderr, "TraceLogging: Failed to start an event.\n");
enabled = false;
enabled = 0;
failed = true;
return;
}
@ -613,7 +593,7 @@ TraceLogger::startEvent(uint32_t id)
uint64_t start = rdtsc() - traceLoggers.startupTime;
if (!startEvent(id, start)) {
fprintf(stderr, "TraceLogging: Failed to start an event.\n");
enabled = false;
enabled = 0;
failed = true;
return;
}
@ -631,6 +611,9 @@ TraceLogger::getActiveAncestor()
bool
TraceLogger::startEvent(uint32_t id, uint64_t timestamp)
{
if (!stack.ensureSpaceBeforeAdd())
return false;
// When a textId is disabled, a stack entry still needs to be pushed,
// together with an annotation that nothing needs to get done when receiving
// the stop event.
@ -688,9 +671,11 @@ void
TraceLogger::stopEvent(uint32_t id)
{
#ifdef DEBUG
TreeEntry entry;
MOZ_ASSERT_IF(stack.current().active(), getTreeEntry(stack.current().treeId(), &entry));
MOZ_ASSERT_IF(stack.current().active(), entry.textId() == id);
if (stack.currentId() > 0) {
TreeEntry entry;
MOZ_ASSERT_IF(stack.current().active(), getTreeEntry(stack.current().treeId(), &entry));
MOZ_ASSERT_IF(stack.current().active(), entry.textId() == id);
}
#endif
stopEvent();
}
@ -698,23 +683,31 @@ TraceLogger::stopEvent(uint32_t id)
void
TraceLogger::stopEvent()
{
if (enabled && stack.current().active()) {
if (enabled > 0 && stack.current().active()) {
uint64_t stop = rdtsc() - traceLoggers.startupTime;
if (!updateStop(stack.current().treeId(), stop)) {
fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
enabled = false;
enabled = 0;
failed = true;
return;
}
}
JS_ASSERT(stack.currentId() > 0);
if (stack.currentId() == 0) {
if (enabled == 0)
return;
// Forcefully disable logging. We have no stack information anymore.
enabled = 1;
disable();
return;
}
stack.pop();
}
TraceLogging::TraceLogging()
{
initialized = false;
enabled = false;
enabled = 0;
mainThreadEnabled = true;
offThreadEnabled = true;
loggerId = 0;
@ -749,7 +742,7 @@ TraceLogging::~TraceLogging()
lock = nullptr;
}
enabled = false;
enabled = 0;
}
static bool
@ -769,7 +762,7 @@ bool
TraceLogging::lazyInit()
{
if (initialized)
return enabled;
return enabled > 0;
initialized = true;
@ -877,18 +870,18 @@ TraceLogging::lazyInit()
}
startupTime = rdtsc();
enabled = true;
enabled = 1;
return true;
}
TraceLogger *
js::TraceLoggerForMainThread(jit::CompileRuntime *runtime)
js::TraceLoggerForMainThread(CompileRuntime *runtime)
{
return traceLoggers.forMainThread(runtime);
}
TraceLogger *
TraceLogging::forMainThread(jit::CompileRuntime *runtime)
TraceLogging::forMainThread(CompileRuntime *runtime)
{
return forMainThread(runtime->mainThread());
}

View File

@ -387,8 +387,7 @@ class TraceLogger
FILE *treeFile;
FILE *eventFile;
bool enabled;
uint32_t enabledTimes;
uint32_t enabled;
bool failed;
uint32_t nextTextId;
@ -436,6 +435,7 @@ class TraceLogger
bool init(uint32_t loggerId);
bool enable();
bool enable(JSContext *cx);
bool disable();
// The createTextId functions map a unique input to a logger ID.
@ -455,6 +455,10 @@ class TraceLogger
void stopEvent(uint32_t id);
void stopEvent();
static unsigned offsetOfEnabled() {
return offsetof(TraceLogger, enabled);
}
private:
void assertNoQuotes(const char *text) {
#ifdef DEBUG
@ -531,6 +535,13 @@ inline bool TraceLoggerEnable(TraceLogger *logger) {
#endif
return false;
}
inline bool TraceLoggerEnable(TraceLogger *logger, JSContext *cx) {
#ifdef JS_TRACE_LOGGING
if (logger)
return logger->enable(cx);
#endif
return false;
}
inline bool TraceLoggerDisable(TraceLogger *logger) {
#ifdef JS_TRACE_LOGGING
if (logger)