Introduce a separate event for CodeDeopt
The reuse of CodeCreateEvent for deopt events caused a CodeCreateEvent fired twice for a code object. When the event was processed for the first time it seized the no-fp-ranges from code object, so the second event had no ranges info leaving code entry without them. As a result when a cpu profile sample falls into the region it missed the 2nd stack frame. LOG=N BUG= R=bmeurer@chromium.org, loislo@chromium.org Review URL: https://codereview.chromium.org/290093005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21418 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6683b4b9dd
commit
a7e816db28
@ -28,6 +28,14 @@ void CodeMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
||||
}
|
||||
|
||||
|
||||
void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
||||
CodeEntry* entry = code_map->FindEntry(start);
|
||||
if (entry != NULL) {
|
||||
entry->set_bailout_reason(bailout_reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
||||
code_map->MoveCode(from, to);
|
||||
}
|
||||
|
@ -304,6 +304,15 @@ void CpuProfiler::CodeMoveEvent(Address from, Address to) {
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) {
|
||||
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
|
||||
CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
|
||||
rec->start = code->address();
|
||||
rec->bailout_reason = GetBailoutReason(shared->DisableOptimizationReason());
|
||||
processor_->Enqueue(evt_rec);
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::CodeDeleteEvent(Address from) {
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ class ProfileGenerator;
|
||||
#define CODE_EVENTS_TYPE_LIST(V) \
|
||||
V(CODE_CREATION, CodeCreateEventRecord) \
|
||||
V(CODE_MOVE, CodeMoveEventRecord) \
|
||||
V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
|
||||
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord) \
|
||||
V(REPORT_BUILTIN, ReportBuiltinEventRecord)
|
||||
|
||||
@ -65,6 +66,15 @@ class CodeMoveEventRecord : public CodeEventRecord {
|
||||
};
|
||||
|
||||
|
||||
class CodeDisableOptEventRecord : public CodeEventRecord {
|
||||
public:
|
||||
Address start;
|
||||
const char* bailout_reason;
|
||||
|
||||
INLINE(void UpdateCodeMap(CodeMap* code_map));
|
||||
};
|
||||
|
||||
|
||||
class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
|
||||
public:
|
||||
Address from;
|
||||
@ -225,6 +235,7 @@ class CpuProfiler : public CodeEventListener {
|
||||
Code* code, int args_count);
|
||||
virtual void CodeMovingGCEvent() {}
|
||||
virtual void CodeMoveEvent(Address from, Address to);
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
|
||||
virtual void CodeDeleteEvent(Address from);
|
||||
virtual void GetterCallbackEvent(Name* name, Address entry_point);
|
||||
virtual void RegExpCodeCreateEvent(Code* code, String* source);
|
||||
|
22
src/log.cc
22
src/log.cc
@ -230,6 +230,7 @@ class PerfBasicLogger : public CodeEventLogger {
|
||||
virtual ~PerfBasicLogger();
|
||||
|
||||
virtual void CodeMoveEvent(Address from, Address to) { }
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
||||
virtual void CodeDeleteEvent(Address from) { }
|
||||
|
||||
private:
|
||||
@ -295,6 +296,7 @@ class PerfJitLogger : public CodeEventLogger {
|
||||
virtual ~PerfJitLogger();
|
||||
|
||||
virtual void CodeMoveEvent(Address from, Address to) { }
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
||||
virtual void CodeDeleteEvent(Address from) { }
|
||||
|
||||
private:
|
||||
@ -457,6 +459,7 @@ class LowLevelLogger : public CodeEventLogger {
|
||||
virtual ~LowLevelLogger();
|
||||
|
||||
virtual void CodeMoveEvent(Address from, Address to);
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
||||
virtual void CodeDeleteEvent(Address from);
|
||||
virtual void SnapshotPositionEvent(Address addr, int pos);
|
||||
virtual void CodeMovingGCEvent();
|
||||
@ -623,6 +626,7 @@ class JitLogger : public CodeEventLogger {
|
||||
explicit JitLogger(JitCodeEventHandler code_event_handler);
|
||||
|
||||
virtual void CodeMoveEvent(Address from, Address to);
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
||||
virtual void CodeDeleteEvent(Address from);
|
||||
virtual void AddCodeLinePosInfoEvent(
|
||||
void* jit_handler_data,
|
||||
@ -1446,6 +1450,24 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
}
|
||||
|
||||
|
||||
void Logger::CodeDisableOptEvent(Code* code,
|
||||
SharedFunctionInfo* shared) {
|
||||
PROFILER_LOG(CodeDisableOptEvent(code, shared));
|
||||
|
||||
if (!is_logging_code_events()) return;
|
||||
CALL_LISTENERS(CodeDisableOptEvent(code, shared));
|
||||
|
||||
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
||||
Log::MessageBuilder msg(log_);
|
||||
msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]);
|
||||
SmartArrayPointer<char> name =
|
||||
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append("\"%s\",", name.get());
|
||||
msg.Append("\"%s\"\n", GetBailoutReason(shared->DisableOptimizationReason()));
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
|
||||
|
||||
void Logger::CodeMovingGCEvent() {
|
||||
PROFILER_LOG(CodeMovingGCEvent());
|
||||
|
||||
|
@ -79,6 +79,7 @@ struct TickSample;
|
||||
|
||||
#define LOG_EVENTS_AND_TAGS_LIST(V) \
|
||||
V(CODE_CREATION_EVENT, "code-creation") \
|
||||
V(CODE_DISABLE_OPT_EVENT, "code-disable-optimization") \
|
||||
V(CODE_MOVE_EVENT, "code-move") \
|
||||
V(CODE_DELETE_EVENT, "code-delete") \
|
||||
V(CODE_MOVING_GC, "code-moving-gc") \
|
||||
@ -237,6 +238,8 @@ class Logger {
|
||||
CompilationInfo* info,
|
||||
Name* source, int line, int column);
|
||||
void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
|
||||
// Emits a code deoptimization event.
|
||||
void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
|
||||
void CodeMovingGCEvent();
|
||||
// Emits a code create event for a RegExp.
|
||||
void RegExpCodeCreateEvent(Code* code, String* source);
|
||||
@ -470,6 +473,7 @@ class CodeEventListener {
|
||||
virtual void CodeDeleteEvent(Address from) = 0;
|
||||
virtual void SharedFunctionInfoMoveEvent(Address from, Address to) = 0;
|
||||
virtual void CodeMovingGCEvent() = 0;
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -10706,9 +10706,7 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
|
||||
if (code()->kind() == Code::FUNCTION) {
|
||||
code()->set_optimizable(false);
|
||||
}
|
||||
PROFILE(GetIsolate(),
|
||||
LogExistingFunction(Handle<SharedFunctionInfo>(this),
|
||||
Handle<Code>(code())));
|
||||
PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[disabled optimization for ");
|
||||
ShortPrint();
|
||||
|
@ -630,6 +630,9 @@ class CodeAddressMap: public CodeEventLogger {
|
||||
address_to_name_map_.Move(from, to);
|
||||
}
|
||||
|
||||
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) {
|
||||
}
|
||||
|
||||
virtual void CodeDeleteEvent(Address from) {
|
||||
address_to_name_map_.Remove(from);
|
||||
}
|
||||
|
@ -587,6 +587,72 @@ TEST(CollectCpuProfile) {
|
||||
}
|
||||
|
||||
|
||||
static const char* hot_deopt_no_frame_entry_test_source =
|
||||
"function foo(a, b) {\n"
|
||||
" try {\n"
|
||||
" return a + b;\n"
|
||||
" } catch (e) { }\n"
|
||||
"}\n"
|
||||
"function start(timeout) {\n"
|
||||
" var start = Date.now();\n"
|
||||
" do {\n"
|
||||
" for (var i = 1; i < 1000; ++i) foo(1, i);\n"
|
||||
" var duration = Date.now() - start;\n"
|
||||
" } while (duration < timeout);\n"
|
||||
" return duration;\n"
|
||||
"}\n";
|
||||
|
||||
// Check that the profile tree for the script above will look like the
|
||||
// following:
|
||||
//
|
||||
// [Top down]:
|
||||
// 1062 0 (root) [-1]
|
||||
// 1054 0 start [-1]
|
||||
// 1054 1 foo [-1]
|
||||
// 2 2 (program) [-1]
|
||||
// 6 6 (garbage collector) [-1]
|
||||
//
|
||||
// The test checks no FP ranges are present in a deoptimized funcion.
|
||||
// If 'foo' has no ranges the samples falling into the prologue will miss the
|
||||
// 'start' function on the stack, so 'foo' will be attached to the (root).
|
||||
TEST(HotDeoptNoFrameEntry) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
|
||||
v8::Script::Compile(v8::String::NewFromUtf8(
|
||||
env->GetIsolate(),
|
||||
hot_deopt_no_frame_entry_test_source))->Run();
|
||||
v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
|
||||
env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
|
||||
|
||||
int32_t profiling_interval_ms = 200;
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
|
||||
};
|
||||
v8::CpuProfile* profile =
|
||||
RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
|
||||
function->Call(env->Global(), ARRAY_SIZE(args), args);
|
||||
|
||||
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
|
||||
|
||||
ScopedVector<v8::Handle<v8::String> > names(3);
|
||||
names[0] = v8::String::NewFromUtf8(
|
||||
env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
|
||||
names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
|
||||
ProfileGenerator::kProgramEntryName);
|
||||
names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
|
||||
CheckChildrenNames(root, names);
|
||||
|
||||
const v8::CpuProfileNode* startNode =
|
||||
GetChild(env->GetIsolate(), root, "start");
|
||||
CHECK_EQ(1, startNode->GetChildrenCount());
|
||||
|
||||
GetChild(env->GetIsolate(), startNode, "foo");
|
||||
|
||||
profile->Delete();
|
||||
}
|
||||
|
||||
|
||||
TEST(CollectCpuProfileSamples) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
|
Loading…
Reference in New Issue
Block a user