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:
alph@chromium.org 2014-05-22 05:36:27 +00:00
parent 6683b4b9dd
commit a7e816db28
8 changed files with 124 additions and 3 deletions

View File

@ -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);
}

View File

@ -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) {
}

View File

@ -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);

View File

@ -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());

View File

@ -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;
};

View File

@ -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();

View File

@ -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);
}

View File

@ -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());