profiling.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/profiling.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/profiler.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "v8/include/v8.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetProfileName() {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_name.empty()) {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (command_line.HasSwitch(switches::kProfilingFile))
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_name = std::string(kDefaultProfileName);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string process_type =
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProcessType);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string type = process_type.empty() ?
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string("browser") : std::string(process_type);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str());
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_name;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FlushProfilingData(base::Thread* thread) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kProfilingFlushSeconds = 10;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Profiling::BeingProfiled())
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::FlushProfiling();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int flush_seconds;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!flush_seconds) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string profiling_flush =
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProfilingFlush);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!profiling_flush.empty()) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_seconds = atoi(profiling_flush.c_str());
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(flush_seconds > 0);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_seconds = kProfilingFlushSeconds;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread->message_loop()->PostDelayedTask(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&FlushProfilingData, thread),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(flush_seconds));
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProfilingThreadControl {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfilingThreadControl() : thread_(NULL) {}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(lock_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (thread_ && thread_->IsRunning())
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_ = new base::Thread("Profiling_Flush");
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->Start();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->message_loop()->PostTask(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&FlushProfilingData, thread_));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(lock_);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thread_ || !thread_->IsRunning())
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->Stop();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete thread_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_ = NULL;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Thread* thread_;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<ProfilingThreadControl>::Leaky
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::ProcessStarted() {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string process_type =
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kProcessType);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Establish the V8 return address resolution hook if we're
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an instrumented binary.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::debug::IsBinaryInstrumented()) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::debug::ReturnAddressLocationResolver resolve_func =
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::debug::GetProfilerReturnAddrResolutionFunc();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (resolve_func != NULL) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      v8::V8::SetReturnAddressLocationResolver(resolve_func);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line.HasSwitch(switches::kProfilingAtStart)) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string process_type_to_start =
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProfilingAtStart);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (process_type == process_type_to_start)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Start();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Start() {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool flush = command_line.HasSwitch(switches::kProfilingFlush);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::StartProfiling(GetProfileName());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule profile data flushing for single process because it doesn't
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // get written out correctly on exit.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flush)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_flush_thread_control.Get().Start();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Stop() {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_flush_thread_control.Get().Stop();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::StopProfiling();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Profiling::BeingProfiled() {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::debug::BeingProfiled();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Toggle() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (BeingProfiled())
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Start();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
155