Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / common / profiling.cc
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.
4
5 #include "chrome/common/profiling.h"
6
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"
18
19 namespace {
20
21 base::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL;
22 base::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL;
23
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);
29
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;
35
36     case v8::JitCodeEvent::CODE_MOVED:
37       move_dynamic_symbol_func(event->code_start, event->new_code_start);
38       break;
39
40     default:
41       break;
42   }
43 }
44
45 std::string GetProfileName() {
46   static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
47   CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
48
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());
60   }
61   return profile_name;
62 }
63
64 void FlushProfilingData(base::Thread* thread) {
65   static const int kProfilingFlushSeconds = 10;
66
67   if (!Profiling::BeingProfiled())
68     return;
69
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;
81     }
82   }
83   thread->message_loop()->PostDelayedTask(
84       FROM_HERE,
85       base::Bind(&FlushProfilingData, thread),
86       base::TimeDelta::FromSeconds(flush_seconds));
87 }
88
89 class ProfilingThreadControl {
90  public:
91   ProfilingThreadControl() : thread_(NULL) {}
92
93   void Start() {
94     base::AutoLock locked(lock_);
95
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_));
102   }
103
104   void Stop() {
105     base::AutoLock locked(lock_);
106
107     if (!thread_ || !thread_->IsRunning())
108       return;
109     thread_->Stop();
110     delete thread_;
111     thread_ = NULL;
112   }
113
114  private:
115   base::Thread* thread_;
116   base::Lock lock_;
117
118   DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
119 };
120
121 base::LazyInstance<ProfilingThreadControl>::Leaky
122     g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
123
124 } // namespace
125
126 // static
127 void Profiling::ProcessStarted() {
128   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
129   std::string process_type =
130       command_line.GetSwitchValueASCII(switches::kProcessType);
131
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();
136
137     if (resolve_func != NULL) {
138       v8::V8::SetReturnAddressLocationResolver(resolve_func);
139     }
140
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();
149
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);
155     }
156   }
157
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();
163   }
164 }
165
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());
171
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();
176 }
177
178 // static
179 void Profiling::Stop() {
180   g_flush_thread_control.Get().Stop();
181   base::debug::StopProfiling();
182 }
183
184 // static
185 bool Profiling::BeingProfiled() {
186   return base::debug::BeingProfiled();
187 }
188
189 // static
190 void Profiling::Toggle() {
191   if (BeingProfiled())
192     Stop();
193   else
194     Start();
195 }