Test for golden version-7 safe-browsing file.
[chromium-blink-merge.git] / chrome / common / profiling.cc
blob46e7bfc74684141793ea58658cd73cbfce0a6fdd
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 "v8/include/v8.h"
18 namespace {
20 base::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL;
21 base::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL;
23 void JitCodeEventHandler(const v8::JitCodeEvent* event) {
24 DCHECK_NE(static_cast<base::debug::AddDynamicSymbol>(NULL),
25 add_dynamic_symbol_func);
26 DCHECK_NE(static_cast<base::debug::MoveDynamicSymbol>(NULL),
27 move_dynamic_symbol_func);
29 switch (event->type) {
30 case v8::JitCodeEvent::CODE_ADDED:
31 add_dynamic_symbol_func(event->code_start, event->code_len,
32 event->name.str, event->name.len);
33 break;
35 case v8::JitCodeEvent::CODE_MOVED:
36 move_dynamic_symbol_func(event->code_start, event->new_code_start);
37 break;
39 default:
40 break;
44 std::string GetProfileName() {
45 static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
46 CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
48 if (profile_name.empty()) {
49 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
50 if (command_line.HasSwitch(switches::kProfilingFile))
51 profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
52 else
53 profile_name = std::string(kDefaultProfileName);
54 std::string process_type =
55 command_line.GetSwitchValueASCII(switches::kProcessType);
56 std::string type = process_type.empty() ?
57 std::string("browser") : std::string(process_type);
58 ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str());
60 return profile_name;
63 void FlushProfilingData(base::Thread* thread) {
64 static const int kProfilingFlushSeconds = 10;
66 if (!Profiling::BeingProfiled())
67 return;
69 base::debug::FlushProfiling();
70 static int flush_seconds;
71 if (!flush_seconds) {
72 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
73 std::string profiling_flush =
74 command_line.GetSwitchValueASCII(switches::kProfilingFlush);
75 if (!profiling_flush.empty()) {
76 flush_seconds = atoi(profiling_flush.c_str());
77 DCHECK(flush_seconds > 0);
78 } else {
79 flush_seconds = kProfilingFlushSeconds;
82 thread->message_loop()->PostDelayedTask(
83 FROM_HERE,
84 base::Bind(&FlushProfilingData, thread),
85 base::TimeDelta::FromSeconds(flush_seconds));
88 class ProfilingThreadControl {
89 public:
90 ProfilingThreadControl() : thread_(NULL) {}
92 void Start() {
93 base::AutoLock locked(lock_);
95 if (thread_ && thread_->IsRunning())
96 return;
97 thread_ = new base::Thread("Profiling_Flush");
98 thread_->Start();
99 thread_->message_loop()->PostTask(
100 FROM_HERE, base::Bind(&FlushProfilingData, thread_));
103 void Stop() {
104 base::AutoLock locked(lock_);
106 if (!thread_ || !thread_->IsRunning())
107 return;
108 thread_->Stop();
109 delete thread_;
110 thread_ = NULL;
113 private:
114 base::Thread* thread_;
115 base::Lock lock_;
117 DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
120 base::LazyInstance<ProfilingThreadControl>::Leaky
121 g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
123 } // namespace
125 // static
126 void Profiling::ProcessStarted() {
127 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
128 std::string process_type =
129 command_line.GetSwitchValueASCII(switches::kProcessType);
131 // Establish the V8 profiling hooks if we're an instrumented binary.
132 if (base::debug::IsBinaryInstrumented()) {
133 base::debug::ReturnAddressLocationResolver resolve_func =
134 base::debug::GetProfilerReturnAddrResolutionFunc();
136 if (resolve_func != NULL) {
137 v8::V8::SetReturnAddressLocationResolver(resolve_func);
140 // Set up the JIT code entry handler and the symbol callbacks if the
141 // profiler supplies them.
142 // TODO(siggi): Maybe add a switch or an environment variable to turn off
143 // V8 profiling?
144 base::debug::DynamicFunctionEntryHook entry_hook_func =
145 base::debug::GetProfilerDynamicFunctionEntryHookFunc();
146 add_dynamic_symbol_func = base::debug::GetProfilerAddDynamicSymbolFunc();
147 move_dynamic_symbol_func = base::debug::GetProfilerMoveDynamicSymbolFunc();
149 v8::Isolate* isolate = v8::Isolate::GetCurrent();
150 if (isolate != NULL &&
151 entry_hook_func != NULL &&
152 add_dynamic_symbol_func != NULL &&
153 move_dynamic_symbol_func != NULL) {
154 v8::V8::SetFunctionEntryHook(isolate, entry_hook_func);
155 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
156 &JitCodeEventHandler);
160 if (command_line.HasSwitch(switches::kProfilingAtStart)) {
161 std::string process_type_to_start =
162 command_line.GetSwitchValueASCII(switches::kProfilingAtStart);
163 if (process_type == process_type_to_start)
164 Start();
168 // static
169 void Profiling::Start() {
170 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
171 bool flush = command_line.HasSwitch(switches::kProfilingFlush);
172 base::debug::StartProfiling(GetProfileName());
174 // Schedule profile data flushing for single process because it doesn't
175 // get written out correctly on exit.
176 if (flush)
177 g_flush_thread_control.Get().Start();
180 // static
181 void Profiling::Stop() {
182 g_flush_thread_control.Get().Stop();
183 base::debug::StopProfiling();
186 // static
187 bool Profiling::BeingProfiled() {
188 return base::debug::BeingProfiled();
191 // static
192 void Profiling::Toggle() {
193 if (BeingProfiled())
194 Stop();
195 else
196 Start();