Commit 707fdd4c authored by yurys@chromium.org's avatar yurys@chromium.org

Support idle time in CPU profiler

This change provides an API for the embedder to tell CPU profiler if it is idle or busy with some task. This way we can discriminate between idle time and some native code execution.

BUG=268947
R=alph@chromium.org, yangguo@chromium.org

Review URL: https://codereview.chromium.org/22412003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16109 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ca4457e8
......@@ -192,6 +192,11 @@ class V8_EXPORT CpuProfiler {
*/
void DeleteAllCpuProfiles();
/**
* Tells the profiler whether the embedder is idle.
*/
void SetIdle(bool is_idle);
private:
CpuProfiler();
~CpuProfiler();
......
......@@ -7646,6 +7646,19 @@ void CpuProfiler::DeleteAllCpuProfiles() {
}
void CpuProfiler::SetIdle(bool is_idle) {
i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate();
i::StateTag state = isolate->current_vm_state();
ASSERT(state == i::EXTERNAL || state == i::IDLE);
if (isolate->js_entry_sp() != NULL) return;
if (is_idle) {
isolate->set_current_vm_state(i::IDLE);
} else if (state == i::IDLE) {
isolate->set_current_vm_state(i::EXTERNAL);
}
}
static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) {
return const_cast<i::HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphEdge*>(edge));
......
......@@ -106,7 +106,7 @@ bool ProfilerEventsProcessor::ProcessCodeEvent() {
bool ProfilerEventsProcessor::ProcessTicks() {
while (true) {
if (!ticks_from_vm_buffer_.IsEmpty()
while (!ticks_from_vm_buffer_.IsEmpty()
&& ticks_from_vm_buffer_.Peek()->order ==
last_processed_code_event_id_) {
TickSampleEventRecord record;
......
......@@ -241,6 +241,7 @@ class CpuProfiler : public CodeEventListener {
ProfileGenerator* generator() const { return generator_; }
ProfilerEventsProcessor* processor() const { return processor_; }
Isolate* isolate() const { return isolate_; }
private:
void StartProcessorIfNotStarted();
......@@ -258,7 +259,6 @@ class CpuProfiler : public CodeEventListener {
bool need_to_stop_sampler_;
bool is_profiling_;
private:
DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
};
......
......@@ -661,9 +661,9 @@ class Isolate {
}
inline Address* handler_address() { return &thread_local_top_.handler_; }
// Bottom JS entry (see StackTracer::Trace in sampler.cc).
static Address js_entry_sp(ThreadLocalTop* thread) {
return thread->js_entry_sp_;
// Bottom JS entry.
Address js_entry_sp() {
return thread_local_top_.js_entry_sp_;
}
inline Address* js_entry_sp_address() {
return &thread_local_top_.js_entry_sp_;
......
......@@ -92,6 +92,8 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
case OTHER:
case EXTERNAL:
return program_entry_;
case IDLE:
return idle_entry_;
default: return NULL;
}
}
......
......@@ -614,6 +614,8 @@ const char* const ProfileGenerator::kAnonymousFunctionName =
"(anonymous function)";
const char* const ProfileGenerator::kProgramEntryName =
"(program)";
const char* const ProfileGenerator::kIdleEntryName =
"(idle)";
const char* const ProfileGenerator::kGarbageCollectorEntryName =
"(garbage collector)";
const char* const ProfileGenerator::kUnresolvedFunctionName =
......@@ -624,6 +626,8 @@ ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
: profiles_(profiles),
program_entry_(
profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)),
idle_entry_(
profiles->NewCodeEntry(Logger::FUNCTION_TAG, kIdleEntryName)),
gc_entry_(
profiles->NewCodeEntry(Logger::BUILTIN_TAG,
kGarbageCollectorEntryName)),
......
......@@ -342,6 +342,7 @@ class ProfileGenerator {
static const char* const kAnonymousFunctionName;
static const char* const kProgramEntryName;
static const char* const kIdleEntryName;
static const char* const kGarbageCollectorEntryName;
// Used to represent frames for which we have no reliable way to
// detect function.
......@@ -353,6 +354,7 @@ class ProfileGenerator {
CpuProfilesCollection* profiles_;
CodeMap code_map_;
CodeEntry* program_entry_;
CodeEntry* idle_entry_;
CodeEntry* gc_entry_;
CodeEntry* unresolved_entry_;
......
......@@ -615,8 +615,7 @@ DISABLE_ASAN void TickSample::Init(Isolate* isolate,
// Avoid collecting traces while doing GC.
if (state == GC) return;
const Address js_entry_sp =
Isolate::js_entry_sp(isolate->thread_local_top());
Address js_entry_sp = isolate->js_entry_sp();
if (js_entry_sp == 0) {
// Not executing JS now.
return;
......
......@@ -363,7 +363,8 @@ enum StateTag {
GC,
COMPILER,
OTHER,
EXTERNAL
EXTERNAL,
IDLE
};
......
......@@ -1324,3 +1324,56 @@ TEST(JsNative1JsNative2JsSample) {
v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
cpu_profiler->DeleteAllCpuProfiles();
}
// [Top down]:
// 6 0 (root) #0 1
// 3 3 (program) #0 2
// 3 3 (idle) #0 3
TEST(IdleTime) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
v8::Local<v8::String> profile_name = v8::String::New("my_profile");
cpu_profiler->StartCpuProfiling(profile_name);
i::Isolate* isolate = i::Isolate::Current();
i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
processor->AddCurrentStack(isolate);
cpu_profiler->SetIdle(true);
for (int i = 0; i < 3; i++) {
processor->AddCurrentStack(isolate);
}
cpu_profiler->SetIdle(false);
processor->AddCurrentStack(isolate);
const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
CHECK_NE(NULL, profile);
// Dump collected profile to have a better diagnostic in case of failure.
reinterpret_cast<i::CpuProfile*>(
const_cast<v8::CpuProfile*>(profile))->Print();
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
ScopedVector<v8::Handle<v8::String> > names(3);
names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
names[2] = v8::String::New(ProfileGenerator::kIdleEntryName);
CheckChildrenNames(root, names);
const v8::CpuProfileNode* programNode =
GetChild(root, ProfileGenerator::kProgramEntryName);
CHECK_EQ(0, programNode->GetChildrenCount());
CHECK_GE(programNode->GetSelfSamplesCount(), 3);
const v8::CpuProfileNode* idleNode =
GetChild(root, ProfileGenerator::kIdleEntryName);
CHECK_EQ(0, idleNode->GetChildrenCount());
CHECK_GE(idleNode->GetSelfSamplesCount(), 3);
cpu_profiler->DeleteAllCpuProfiles();
}
......@@ -157,7 +157,7 @@ void TraceExtension::JSTrace(const v8::FunctionCallbackInfo<v8::Value>& args) {
static Address GetJsEntrySp() {
CHECK_NE(NULL, i::Isolate::Current()->thread_local_top());
return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top());
return i::Isolate::Current()->js_entry_sp();
}
......
......@@ -249,7 +249,8 @@ TickProcessor.VmStates = {
GC: 1,
COMPILER: 2,
OTHER: 3,
EXTERNAL: 4
EXTERNAL: 4,
IDLE: 5
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment