From 57231d5286b036f3277e778eca5c4501c99b9ce0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 2 Oct 2013 06:37:44 +0200 Subject: [PATCH] src: notify V8 profiler when we're idle Inform V8's CPU profiler when we're idle. The profiler is sampling-based but not all samples are created equal; mark the wall clock time spent in epoll_wait() and friends so profiling tools can filter it out. The samples still end up in v8.log but with state=IDLE rather than state=EXTERNAL. --- src/env-inl.h | 17 +++++++++++++++++ src/env.h | 9 +++++++++ src/node.cc | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/src/env-inl.h b/src/env-inl.h index a53e662..6ab93c4 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -203,6 +203,23 @@ inline uv_idle_t* Environment::immediate_idle_handle() { return &immediate_idle_handle_; } +inline Environment* Environment::from_idle_prepare_handle( + uv_prepare_t* handle) { + return CONTAINER_OF(handle, Environment, idle_prepare_handle_); +} + +inline uv_prepare_t* Environment::idle_prepare_handle() { + return &idle_prepare_handle_; +} + +inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) { + return CONTAINER_OF(handle, Environment, idle_check_handle_); +} + +inline uv_check_t* Environment::idle_check_handle() { + return &idle_check_handle_; +} + inline uv_loop_t* Environment::event_loop() const { return isolate_data()->event_loop(); } diff --git a/src/env.h b/src/env.h index db8d660..082e3d6 100644 --- a/src/env.h +++ b/src/env.h @@ -232,6 +232,13 @@ class Environment { static inline Environment* from_immediate_check_handle(uv_check_t* handle); inline uv_check_t* immediate_check_handle(); inline uv_idle_t* immediate_idle_handle(); + + static inline Environment* from_idle_prepare_handle(uv_prepare_t* handle); + inline uv_prepare_t* idle_prepare_handle(); + + static inline Environment* from_idle_check_handle(uv_check_t* handle); + inline uv_check_t* idle_check_handle(); + inline DomainFlag* domain_flag(); inline TickInfo* tick_info(); @@ -274,6 +281,8 @@ class Environment { IsolateData* const isolate_data_; uv_check_t immediate_check_handle_; uv_idle_t immediate_idle_handle_; + uv_prepare_t idle_prepare_handle_; + uv_check_t idle_check_handle_; DomainFlag domain_flag_; TickInfo tick_info_; uv_timer_t cares_timer_handle_; diff --git a/src/node.cc b/src/node.cc index 9f724d4..6b957bd 100644 --- a/src/node.cc +++ b/src/node.cc @@ -51,6 +51,7 @@ #include "string_bytes.h" #include "uv.h" #include "v8-debug.h" +#include "v8-profiler.h" #include "zlib.h" #include @@ -3205,6 +3206,18 @@ void EmitExit(Environment* env) { } +void SetIdle(uv_prepare_t* handle, int) { + Environment* env = Environment::from_idle_prepare_handle(handle); + env->isolate()->GetCpuProfiler()->SetIdle(true); +} + + +void ClearIdle(uv_check_t* handle, int) { + Environment* env = Environment::from_idle_check_handle(handle); + env->isolate()->GetCpuProfiler()->SetIdle(false); +} + + Environment* CreateEnvironment(Isolate* isolate, int argc, const char* const* argv, @@ -3230,6 +3243,25 @@ Environment* CreateEnvironment(Isolate* isolate, SetupProcessObject(env, argc, argv, exec_argc, exec_argv); Load(env); + // Inform V8's CPU profiler when we're idle. The profiler is sampling-based + // but not all samples are created equal; mark the wall clock time spent in + // epoll_wait() and friends so profiling tools can filter it out. The samples + // still end up in v8.log but with state=IDLE rather than state=EXTERNAL. + // TODO(bnoordhuis): Only start when profiling. OTOH, the performance impact + // is probably negligible. + // TODO(bnoordhuis) Depends on a libuv implementation detail that we should + // probably fortify in the API contract, namely that the last started prepare + // or check watcher runs first. It's not 100% foolproof; if an add-on starts + // a prepare or check watcher after us, any samples attributed to its callback + // will be recorded with state=IDLE. + uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); + uv_prepare_start(env->idle_prepare_handle(), SetIdle); + uv_unref(reinterpret_cast(env->idle_prepare_handle())); + + uv_check_init(env->event_loop(), env->idle_check_handle()); + uv_check_start(env->idle_check_handle(), ClearIdle); + uv_unref(reinterpret_cast(env->idle_check_handle())); + return env; } -- 2.7.4