*/
void DeleteAllCpuProfiles();
+ /**
+ * Tells the profiler whether the embedder is idle.
+ */
+ void SetIdle(bool is_idle);
+
private:
CpuProfiler();
~CpuProfiler();
}
+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));
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;
ProfileGenerator* generator() const { return generator_; }
ProfilerEventsProcessor* processor() const { return processor_; }
+ Isolate* isolate() const { return isolate_; }
private:
void StartProcessorIfNotStarted();
bool need_to_stop_sampler_;
bool is_profiling_;
- private:
DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
};
}
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_;
case OTHER:
case EXTERNAL:
return program_entry_;
+ case IDLE:
+ return idle_entry_;
default: return NULL;
}
}
"(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 =
: 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)),
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.
CpuProfilesCollection* profiles_;
CodeMap code_map_;
CodeEntry* program_entry_;
+ CodeEntry* idle_entry_;
CodeEntry* gc_entry_;
CodeEntry* unresolved_entry_;
// 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;
GC,
COMPILER,
OTHER,
- EXTERNAL
+ EXTERNAL,
+ IDLE
};
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();
+}
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();
}
GC: 1,
COMPILER: 2,
OTHER: 3,
- EXTERNAL: 4
+ EXTERNAL: 4,
+ IDLE: 5
};