Roll src/third_party/WebKit cc8fa7d:a2f2e15d (svn 202014:202015)
[chromium-blink-merge.git] / chrome / common / profiling.cc
blob06f1c7d223fda40ec2042a24f0937a26638d8e53
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/profiling.h"
7 #include "base/at_exit.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/debug/profiler.h"
11 #include "base/lazy_instance.h"
12 #include "base/location.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_util.h"
15 #include "base/threading/thread.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "gin/public/debug.h"
18 #include "v8/include/v8.h"
20 namespace {
22 base::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL;
23 base::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL;
25 void JitCodeEventHandler(const v8::JitCodeEvent* event) {
26 DCHECK_NE(static_cast<base::debug::AddDynamicSymbol>(NULL),
27 add_dynamic_symbol_func);
28 DCHECK_NE(static_cast<base::debug::MoveDynamicSymbol>(NULL),
29 move_dynamic_symbol_func);
31 switch (event->type) {
32 case v8::JitCodeEvent::CODE_ADDED:
33 add_dynamic_symbol_func(event->code_start, event->code_len,
34 event->name.str, event->name.len);
35 break;
37 case v8::JitCodeEvent::CODE_MOVED:
38 move_dynamic_symbol_func(event->code_start, event->new_code_start);
39 break;
41 default:
42 break;
46 std::string GetProfileName() {
47 static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
48 CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
50 if (profile_name.empty()) {
51 const base::CommandLine& command_line =
52 *base::CommandLine::ForCurrentProcess();
53 if (command_line.HasSwitch(switches::kProfilingFile))
54 profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
55 else
56 profile_name = std::string(kDefaultProfileName);
57 std::string process_type =
58 command_line.GetSwitchValueASCII(switches::kProcessType);
59 std::string type = process_type.empty() ?
60 std::string("browser") : std::string(process_type);
61 base::ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type);
63 return profile_name;
66 void FlushProfilingData(base::Thread* thread) {
67 static const int kProfilingFlushSeconds = 10;
69 if (!Profiling::BeingProfiled())
70 return;
72 base::debug::FlushProfiling();
73 static int flush_seconds;
74 if (!flush_seconds) {
75 const base::CommandLine& command_line =
76 *base::CommandLine::ForCurrentProcess();
77 std::string profiling_flush =
78 command_line.GetSwitchValueASCII(switches::kProfilingFlush);
79 if (!profiling_flush.empty()) {
80 flush_seconds = atoi(profiling_flush.c_str());
81 DCHECK(flush_seconds > 0);
82 } else {
83 flush_seconds = kProfilingFlushSeconds;
86 thread->task_runner()->PostDelayedTask(
87 FROM_HERE, base::Bind(&FlushProfilingData, thread),
88 base::TimeDelta::FromSeconds(flush_seconds));
91 class ProfilingThreadControl {
92 public:
93 ProfilingThreadControl() : thread_(NULL) {}
95 void Start() {
96 base::AutoLock locked(lock_);
98 if (thread_ && thread_->IsRunning())
99 return;
100 thread_ = new base::Thread("Profiling_Flush");
101 thread_->Start();
102 thread_->task_runner()->PostTask(FROM_HERE,
103 base::Bind(&FlushProfilingData, thread_));
106 void Stop() {
107 base::AutoLock locked(lock_);
109 if (!thread_ || !thread_->IsRunning())
110 return;
111 thread_->Stop();
112 delete thread_;
113 thread_ = NULL;
116 private:
117 base::Thread* thread_;
118 base::Lock lock_;
120 DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
123 base::LazyInstance<ProfilingThreadControl>::Leaky
124 g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
126 } // namespace
128 // static
129 void Profiling::ProcessStarted() {
130 const base::CommandLine& command_line =
131 *base::CommandLine::ForCurrentProcess();
132 std::string process_type =
133 command_line.GetSwitchValueASCII(switches::kProcessType);
135 // Establish the V8 profiling hooks if we're an instrumented binary.
136 if (base::debug::IsBinaryInstrumented()) {
137 base::debug::ReturnAddressLocationResolver resolve_func =
138 base::debug::GetProfilerReturnAddrResolutionFunc();
140 if (resolve_func != NULL) {
141 v8::V8::SetReturnAddressLocationResolver(resolve_func);
144 // Set up the JIT code entry handler and the symbol callbacks if the
145 // profiler supplies them.
146 // TODO(siggi): Maybe add a switch or an environment variable to turn off
147 // V8 profiling?
148 base::debug::DynamicFunctionEntryHook entry_hook_func =
149 base::debug::GetProfilerDynamicFunctionEntryHookFunc();
150 add_dynamic_symbol_func = base::debug::GetProfilerAddDynamicSymbolFunc();
151 move_dynamic_symbol_func = base::debug::GetProfilerMoveDynamicSymbolFunc();
153 if (entry_hook_func != NULL &&
154 add_dynamic_symbol_func != NULL &&
155 move_dynamic_symbol_func != NULL) {
156 gin::Debug::SetFunctionEntryHook(entry_hook_func);
157 gin::Debug::SetJitCodeEventHandler(&JitCodeEventHandler);
161 if (command_line.HasSwitch(switches::kProfilingAtStart)) {
162 std::string process_type_to_start =
163 command_line.GetSwitchValueASCII(switches::kProfilingAtStart);
164 if (process_type == process_type_to_start)
165 Start();
169 // static
170 void Profiling::Start() {
171 const base::CommandLine& command_line =
172 *base::CommandLine::ForCurrentProcess();
173 bool flush = command_line.HasSwitch(switches::kProfilingFlush);
174 base::debug::StartProfiling(GetProfileName());
176 // Schedule profile data flushing for single process because it doesn't
177 // get written out correctly on exit.
178 if (flush)
179 g_flush_thread_control.Get().Start();
182 // static
183 void Profiling::Stop() {
184 g_flush_thread_control.Get().Stop();
185 base::debug::StopProfiling();
188 // static
189 bool Profiling::BeingProfiled() {
190 return base::debug::BeingProfiled();
193 // static
194 void Profiling::Toggle() {
195 if (BeingProfiled())
196 Stop();
197 else
198 Start();