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