profiling.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.h" 13#include "base/string_util.h" 14#include "base/threading/thread.h" 15#include "chrome/common/chrome_switches.h" 16#include "v8/include/v8.h" 17 18namespace { 19std::string GetProfileName() { 20 static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}"; 21 CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ()); 22 23 if (profile_name.empty()) { 24 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 25 if (command_line.HasSwitch(switches::kProfilingFile)) 26 profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile); 27 else 28 profile_name = std::string(kDefaultProfileName); 29 std::string process_type = 30 command_line.GetSwitchValueASCII(switches::kProcessType); 31 std::string type = process_type.empty() ? 32 std::string("browser") : std::string(process_type); 33 ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str()); 34 } 35 return profile_name; 36} 37 38void FlushProfilingData(base::Thread* thread) { 39 static const int kProfilingFlushSeconds = 10; 40 41 if (!Profiling::BeingProfiled()) 42 return; 43 44 base::debug::FlushProfiling(); 45 static int flush_seconds; 46 if (!flush_seconds) { 47 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 48 std::string profiling_flush = 49 command_line.GetSwitchValueASCII(switches::kProfilingFlush); 50 if (!profiling_flush.empty()) { 51 flush_seconds = atoi(profiling_flush.c_str()); 52 DCHECK(flush_seconds > 0); 53 } else { 54 flush_seconds = kProfilingFlushSeconds; 55 } 56 } 57 thread->message_loop()->PostDelayedTask( 58 FROM_HERE, 59 base::Bind(&FlushProfilingData, thread), 60 base::TimeDelta::FromSeconds(flush_seconds)); 61} 62 63class ProfilingThreadControl { 64 public: 65 ProfilingThreadControl() : thread_(NULL) {} 66 67 void Start() { 68 base::AutoLock locked(lock_); 69 70 if (thread_ && thread_->IsRunning()) 71 return; 72 thread_ = new base::Thread("Profiling_Flush"); 73 thread_->Start(); 74 thread_->message_loop()->PostTask( 75 FROM_HERE, base::Bind(&FlushProfilingData, thread_)); 76 } 77 78 void Stop() { 79 base::AutoLock locked(lock_); 80 81 if (!thread_ || !thread_->IsRunning()) 82 return; 83 thread_->Stop(); 84 delete thread_; 85 thread_ = NULL; 86 } 87 88 private: 89 base::Thread* thread_; 90 base::Lock lock_; 91 92 DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl); 93}; 94 95base::LazyInstance<ProfilingThreadControl>::Leaky 96 g_flush_thread_control = LAZY_INSTANCE_INITIALIZER; 97 98} // namespace 99 100// static 101void Profiling::ProcessStarted() { 102 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 103 std::string process_type = 104 command_line.GetSwitchValueASCII(switches::kProcessType); 105 106 // Establish the V8 return address resolution hook if we're 107 // an instrumented binary. 108 if (base::debug::IsBinaryInstrumented()) { 109 base::debug::ReturnAddressLocationResolver resolve_func = 110 base::debug::GetProfilerReturnAddrResolutionFunc(); 111 112 if (resolve_func != NULL) { 113 v8::V8::SetReturnAddressLocationResolver(resolve_func); 114 } 115 } 116 117 if (command_line.HasSwitch(switches::kProfilingAtStart)) { 118 std::string process_type_to_start = 119 command_line.GetSwitchValueASCII(switches::kProfilingAtStart); 120 if (process_type == process_type_to_start) 121 Start(); 122 } 123} 124 125// static 126void Profiling::Start() { 127 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 128 bool flush = command_line.HasSwitch(switches::kProfilingFlush); 129 base::debug::StartProfiling(GetProfileName()); 130 131 // Schedule profile data flushing for single process because it doesn't 132 // get written out correctly on exit. 133 if (flush) 134 g_flush_thread_control.Get().Start(); 135} 136 137// static 138void Profiling::Stop() { 139 g_flush_thread_control.Get().Stop(); 140 base::debug::StopProfiling(); 141} 142 143// static 144bool Profiling::BeingProfiled() { 145 return base::debug::BeingProfiled(); 146} 147 148// static 149void Profiling::Toggle() { 150 if (BeingProfiled()) 151 Stop(); 152 else 153 Start(); 154} 155