Changes in whitespace in order to try submitting cl and commiting.
[chromium-blink-merge.git] / chrome / common / profiling.cc
blob19cbac7a1975de99a9065a27e253d17e94465f10
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 CommandLine& command_line = *CommandLine::ForCurrentProcess();
51 if (command_line.HasSwitch(switches::kProfilingFile))
52 profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
53 else
54 profile_name = std::string(kDefaultProfileName);
55 std::string process_type =
56 command_line.GetSwitchValueASCII(switches::kProcessType);
57 std::string type = process_type.empty() ?
58 std::string("browser") : std::string(process_type);
59 ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str());
61 return profile_name;
64 void FlushProfilingData(base::Thread* thread) {
65 static const int kProfilingFlushSeconds = 10;
67 if (!Profiling::BeingProfiled())
68 return;
70 base::debug::FlushProfiling();
71 static int flush_seconds;
72 if (!flush_seconds) {
73 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
74 std::string profiling_flush =
75 command_line.GetSwitchValueASCII(switches::kProfilingFlush);
76 if (!profiling_flush.empty()) {
77 flush_seconds = atoi(profiling_flush.c_str());
78 DCHECK(flush_seconds > 0);
79 } else {
80 flush_seconds = kProfilingFlushSeconds;
83 thread->message_loop()->PostDelayedTask(
84 FROM_HERE,
85 base::Bind(&FlushProfilingData, thread),
86 base::TimeDelta::FromSeconds(flush_seconds));
89 class ProfilingThreadControl {
90 public:
91 ProfilingThreadControl() : thread_(NULL) {}
93 void Start() {
94 base::AutoLock locked(lock_);
96 if (thread_ && thread_->IsRunning())
97 return;
98 thread_ = new base::Thread("Profiling_Flush");
99 thread_->Start();
100 thread_->message_loop()->PostTask(
101 FROM_HERE, base::Bind(&FlushProfilingData, thread_));
104 void Stop() {
105 base::AutoLock locked(lock_);
107 if (!thread_ || !thread_->IsRunning())
108 return;
109 thread_->Stop();
110 delete thread_;
111 thread_ = NULL;
114 private:
115 base::Thread* thread_;
116 base::Lock lock_;
118 DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
121 base::LazyInstance<ProfilingThreadControl>::Leaky
122 g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
124 } // namespace
126 // static
127 void Profiling::ProcessStarted() {
128 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
129 std::string process_type =
130 command_line.GetSwitchValueASCII(switches::kProcessType);
132 // Establish the V8 profiling hooks if we're an instrumented binary.
133 if (base::debug::IsBinaryInstrumented()) {
134 base::debug::ReturnAddressLocationResolver resolve_func =
135 base::debug::GetProfilerReturnAddrResolutionFunc();
137 if (resolve_func != NULL) {
138 v8::V8::SetReturnAddressLocationResolver(resolve_func);
141 // Set up the JIT code entry handler and the symbol callbacks if the
142 // profiler supplies them.
143 // TODO(siggi): Maybe add a switch or an environment variable to turn off
144 // V8 profiling?
145 base::debug::DynamicFunctionEntryHook entry_hook_func =
146 base::debug::GetProfilerDynamicFunctionEntryHookFunc();
147 add_dynamic_symbol_func = base::debug::GetProfilerAddDynamicSymbolFunc();
148 move_dynamic_symbol_func = base::debug::GetProfilerMoveDynamicSymbolFunc();
150 if (entry_hook_func != NULL &&
151 add_dynamic_symbol_func != NULL &&
152 move_dynamic_symbol_func != NULL) {
153 gin::Debug::SetFunctionEntryHook(entry_hook_func);
154 gin::Debug::SetJitCodeEventHandler(&JitCodeEventHandler);
158 if (command_line.HasSwitch(switches::kProfilingAtStart)) {
159 std::string process_type_to_start =
160 command_line.GetSwitchValueASCII(switches::kProfilingAtStart);
161 if (process_type == process_type_to_start)
162 Start();
166 // static
167 void Profiling::Start() {
168 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
169 bool flush = command_line.HasSwitch(switches::kProfilingFlush);
170 base::debug::StartProfiling(GetProfileName());
172 // Schedule profile data flushing for single process because it doesn't
173 // get written out correctly on exit.
174 if (flush)
175 g_flush_thread_control.Get().Start();
178 // static
179 void Profiling::Stop() {
180 g_flush_thread_control.Get().Stop();
181 base::debug::StopProfiling();
184 // static
185 bool Profiling::BeingProfiled() {
186 return base::debug::BeingProfiled();
189 // static
190 void Profiling::Toggle() {
191 if (BeingProfiled())
192 Stop();
193 else
194 Start();