Index: chrome/common/profiling.cc |
diff --git a/chrome/common/profiling.cc b/chrome/common/profiling.cc |
index 1acb43fea13a9d4e0e4bb58ffa0d61710f461cba..dc8c79b3429ecbbb610b9d0287683384aeaa0f10 100644 |
--- a/chrome/common/profiling.cc |
+++ b/chrome/common/profiling.cc |
@@ -1,154 +1,194 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/common/profiling.h" |
- |
-#include "base/at_exit.h" |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/debug/profiler.h" |
-#include "base/lazy_instance.h" |
-#include "base/message_loop.h" |
-#include "base/strings/string_util.h" |
-#include "base/threading/thread.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "v8/include/v8.h" |
- |
-namespace { |
-std::string GetProfileName() { |
- static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}"; |
- CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ()); |
- |
- if (profile_name.empty()) { |
- const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- if (command_line.HasSwitch(switches::kProfilingFile)) |
- profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile); |
- else |
- profile_name = std::string(kDefaultProfileName); |
- std::string process_type = |
- command_line.GetSwitchValueASCII(switches::kProcessType); |
- std::string type = process_type.empty() ? |
- std::string("browser") : std::string(process_type); |
- ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str()); |
- } |
- return profile_name; |
-} |
- |
-void FlushProfilingData(base::Thread* thread) { |
- static const int kProfilingFlushSeconds = 10; |
- |
- if (!Profiling::BeingProfiled()) |
- return; |
- |
- base::debug::FlushProfiling(); |
- static int flush_seconds; |
- if (!flush_seconds) { |
- const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- std::string profiling_flush = |
- command_line.GetSwitchValueASCII(switches::kProfilingFlush); |
- if (!profiling_flush.empty()) { |
- flush_seconds = atoi(profiling_flush.c_str()); |
- DCHECK(flush_seconds > 0); |
- } else { |
- flush_seconds = kProfilingFlushSeconds; |
- } |
- } |
- thread->message_loop()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&FlushProfilingData, thread), |
- base::TimeDelta::FromSeconds(flush_seconds)); |
-} |
- |
-class ProfilingThreadControl { |
- public: |
- ProfilingThreadControl() : thread_(NULL) {} |
- |
- void Start() { |
- base::AutoLock locked(lock_); |
- |
- if (thread_ && thread_->IsRunning()) |
- return; |
- thread_ = new base::Thread("Profiling_Flush"); |
- thread_->Start(); |
- thread_->message_loop()->PostTask( |
- FROM_HERE, base::Bind(&FlushProfilingData, thread_)); |
- } |
- |
- void Stop() { |
- base::AutoLock locked(lock_); |
- |
- if (!thread_ || !thread_->IsRunning()) |
- return; |
- thread_->Stop(); |
- delete thread_; |
- thread_ = NULL; |
- } |
- |
- private: |
- base::Thread* thread_; |
- base::Lock lock_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl); |
-}; |
- |
-base::LazyInstance<ProfilingThreadControl>::Leaky |
- g_flush_thread_control = LAZY_INSTANCE_INITIALIZER; |
- |
-} // namespace |
- |
-// static |
-void Profiling::ProcessStarted() { |
- const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- std::string process_type = |
- command_line.GetSwitchValueASCII(switches::kProcessType); |
- |
- // Establish the V8 return address resolution hook if we're |
- // an instrumented binary. |
- if (base::debug::IsBinaryInstrumented()) { |
- base::debug::ReturnAddressLocationResolver resolve_func = |
- base::debug::GetProfilerReturnAddrResolutionFunc(); |
- |
- if (resolve_func != NULL) { |
- v8::V8::SetReturnAddressLocationResolver(resolve_func); |
- } |
- } |
- |
- if (command_line.HasSwitch(switches::kProfilingAtStart)) { |
- std::string process_type_to_start = |
- command_line.GetSwitchValueASCII(switches::kProfilingAtStart); |
- if (process_type == process_type_to_start) |
- Start(); |
- } |
-} |
- |
-// static |
-void Profiling::Start() { |
- const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- bool flush = command_line.HasSwitch(switches::kProfilingFlush); |
- base::debug::StartProfiling(GetProfileName()); |
- |
- // Schedule profile data flushing for single process because it doesn't |
- // get written out correctly on exit. |
- if (flush) |
- g_flush_thread_control.Get().Start(); |
-} |
- |
-// static |
-void Profiling::Stop() { |
- g_flush_thread_control.Get().Stop(); |
- base::debug::StopProfiling(); |
-} |
- |
-// static |
-bool Profiling::BeingProfiled() { |
- return base::debug::BeingProfiled(); |
-} |
- |
-// static |
-void Profiling::Toggle() { |
- if (BeingProfiled()) |
- Stop(); |
- else |
- Start(); |
-} |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/common/profiling.h" |
+ |
+#include "base/at_exit.h" |
+#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/debug/profiler.h" |
+#include "base/lazy_instance.h" |
+#include "base/message_loop.h" |
+#include "base/strings/string_util.h" |
+#include "base/threading/thread.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "v8/include/v8.h" |
+ |
+namespace { |
+ |
+base::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL; |
+base::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL; |
+ |
+void JitCodeEventHandler(const v8::JitCodeEvent* event) { |
+ DCHECK_NE(static_cast<base::debug::AddDynamicSymbol>(NULL), |
+ add_dynamic_symbol_func); |
+ DCHECK_NE(static_cast<base::debug::MoveDynamicSymbol>(NULL), |
+ move_dynamic_symbol_func); |
+ |
+ switch (event->type) { |
+ case v8::JitCodeEvent::CODE_ADDED: |
+ add_dynamic_symbol_func(event->code_start, event->code_len, |
+ event->name.str, event->name.len); |
+ break; |
+ |
+ case v8::JitCodeEvent::CODE_MOVED: |
+ move_dynamic_symbol_func(event->code_start, event->new_code_start); |
+ break; |
+ } |
+} |
+ |
+std::string GetProfileName() { |
+ static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}"; |
+ CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ()); |
+ |
+ if (profile_name.empty()) { |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ if (command_line.HasSwitch(switches::kProfilingFile)) |
+ profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile); |
+ else |
+ profile_name = std::string(kDefaultProfileName); |
+ std::string process_type = |
+ command_line.GetSwitchValueASCII(switches::kProcessType); |
+ std::string type = process_type.empty() ? |
+ std::string("browser") : std::string(process_type); |
+ ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str()); |
+ } |
+ return profile_name; |
+} |
+ |
+void FlushProfilingData(base::Thread* thread) { |
+ static const int kProfilingFlushSeconds = 10; |
+ |
+ if (!Profiling::BeingProfiled()) |
+ return; |
+ |
+ base::debug::FlushProfiling(); |
+ static int flush_seconds; |
+ if (!flush_seconds) { |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ std::string profiling_flush = |
+ command_line.GetSwitchValueASCII(switches::kProfilingFlush); |
+ if (!profiling_flush.empty()) { |
+ flush_seconds = atoi(profiling_flush.c_str()); |
+ DCHECK(flush_seconds > 0); |
+ } else { |
+ flush_seconds = kProfilingFlushSeconds; |
+ } |
+ } |
+ thread->message_loop()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&FlushProfilingData, thread), |
+ base::TimeDelta::FromSeconds(flush_seconds)); |
+} |
+ |
+class ProfilingThreadControl { |
+ public: |
+ ProfilingThreadControl() : thread_(NULL) {} |
+ |
+ void Start() { |
+ base::AutoLock locked(lock_); |
+ |
+ if (thread_ && thread_->IsRunning()) |
+ return; |
+ thread_ = new base::Thread("Profiling_Flush"); |
+ thread_->Start(); |
+ thread_->message_loop()->PostTask( |
+ FROM_HERE, base::Bind(&FlushProfilingData, thread_)); |
+ } |
+ |
+ void Stop() { |
+ base::AutoLock locked(lock_); |
+ |
+ if (!thread_ || !thread_->IsRunning()) |
+ return; |
+ thread_->Stop(); |
+ delete thread_; |
+ thread_ = NULL; |
+ } |
+ |
+ private: |
+ base::Thread* thread_; |
+ base::Lock lock_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl); |
+}; |
+ |
+base::LazyInstance<ProfilingThreadControl>::Leaky |
+ g_flush_thread_control = LAZY_INSTANCE_INITIALIZER; |
+ |
+} // namespace |
+ |
+// static |
+void Profiling::ProcessStarted() { |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ std::string process_type = |
+ command_line.GetSwitchValueASCII(switches::kProcessType); |
+ |
+ // Establish the V8 profiling hooks if we're an instrumented binary. |
+ if (base::debug::IsBinaryInstrumented()) { |
+ base::debug::ReturnAddressLocationResolver resolve_func = |
+ base::debug::GetProfilerReturnAddrResolutionFunc(); |
+ |
+ if (resolve_func != NULL) { |
+ v8::V8::SetReturnAddressLocationResolver(resolve_func); |
+ } |
+ |
+ // Set up the JIT code entry handler and the symbol callbacks if the |
+ // profiler supplies them. |
+ // TODO(siggi): Maybe add a switch or an environment variable to turn off |
+ // V8 profiling? |
+ base::debug::DynamicFunctionEntryHook entry_hook_func = |
+ base::debug::GetProfilerDynamicFunctionEntryHookFunc(); |
+ add_dynamic_symbol_func = base::debug::GetProfilerAddDynamicSymbolFunc(); |
+ move_dynamic_symbol_func = base::debug::GetProfilerMoveDynamicSymbolFunc(); |
Nico
2013/07/03 19:26:38
nit: can't you just call this in JitCodeEventHandl
Sigurður Ásgeirsson
2013/07/03 19:35:58
Retrieving these functions is relatively expensive
|
+ |
+ v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
+ if (isolate != NULL && |
+ entry_hook_func != NULL && |
+ add_dynamic_symbol_func != NULL && |
+ move_dynamic_symbol_func != NULL) { |
+ v8::V8::SetFunctionEntryHook(isolate, entry_hook_func); |
+ v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, |
+ &JitCodeEventHandler); |
+ } |
+ } |
+ |
+ if (command_line.HasSwitch(switches::kProfilingAtStart)) { |
+ std::string process_type_to_start = |
+ command_line.GetSwitchValueASCII(switches::kProfilingAtStart); |
+ if (process_type == process_type_to_start) |
+ Start(); |
+ } |
+} |
+ |
+// static |
+void Profiling::Start() { |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ bool flush = command_line.HasSwitch(switches::kProfilingFlush); |
+ base::debug::StartProfiling(GetProfileName()); |
+ |
+ // Schedule profile data flushing for single process because it doesn't |
+ // get written out correctly on exit. |
+ if (flush) |
+ g_flush_thread_control.Get().Start(); |
+} |
+ |
+// static |
+void Profiling::Stop() { |
+ g_flush_thread_control.Get().Stop(); |
+ base::debug::StopProfiling(); |
+} |
+ |
+// static |
+bool Profiling::BeingProfiled() { |
+ return base::debug::BeingProfiled(); |
+} |
+ |
+// static |
+void Profiling::Toggle() { |
+ if (BeingProfiled()) |
+ Stop(); |
+ else |
+ Start(); |
+} |