Resurrect battery_status_dispatcher_unittest.
[chromium-blink-merge.git] / chrome / common / profiling.cc
blob07cc8def0c34a2a01a24a672d2f5c96fe160ed5d
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/message_loop/message_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/threading/thread.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "gin/public/debug.h"
17 #include "v8/include/v8.h"
19 namespace {
21 base::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL;
22 base::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL;
24 void JitCodeEventHandler(const v8::JitCodeEvent* event) {
25 DCHECK_NE(static_cast<base::debug::AddDynamicSymbol>(NULL),
26 add_dynamic_symbol_func);
27 DCHECK_NE(static_cast<base::debug::MoveDynamicSymbol>(NULL),
28 move_dynamic_symbol_func);
30 switch (event->type) {
31 case v8::JitCodeEvent::CODE_ADDED:
32 add_dynamic_symbol_func(event->code_start, event->code_len,
33 event->name.str, event->name.len);
34 break;
36 case v8::JitCodeEvent::CODE_MOVED:
37 move_dynamic_symbol_func(event->code_start, event->new_code_start);
38 break;
40 default:
41 break;
45 std::string GetProfileName() {
46 static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
47 CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
49 if (profile_name.empty()) {
50 const base::CommandLine& command_line =
51 *base::CommandLine::ForCurrentProcess();
52 if (command_line.HasSwitch(switches::kProfilingFile))
53 profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
54 else
55 profile_name = std::string(kDefaultProfileName);
56 std::string process_type =
57 command_line.GetSwitchValueASCII(switches::kProcessType);
58 std::string type = process_type.empty() ?
59 std::string("browser") : std::string(process_type);
60 ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str());
62 return profile_name;
65 void FlushProfilingData(base::Thread* thread) {
66 static const int kProfilingFlushSeconds = 10;
68 if (!Profiling::BeingProfiled())
69 return;
71 base::debug::FlushProfiling();
72 static int flush_seconds;
73 if (!flush_seconds) {
74 const base::CommandLine& command_line =
75 *base::CommandLine::ForCurrentProcess();
76 std::string profiling_flush =
77 command_line.GetSwitchValueASCII(switches::kProfilingFlush);
78 if (!profiling_flush.empty()) {
79 flush_seconds = atoi(profiling_flush.c_str());
80 DCHECK(flush_seconds > 0);
81 } else {
82 flush_seconds = kProfilingFlushSeconds;
85 thread->message_loop()->PostDelayedTask(
86 FROM_HERE,
87 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_->message_loop()->PostTask(
103 FROM_HERE, 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();