profiling.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/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 {
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbase::debug::AddDynamicSymbol add_dynamic_symbol_func = NULL;
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbase::debug::MoveDynamicSymbol move_dynamic_symbol_func = NULL;
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid JitCodeEventHandler(const v8::JitCodeEvent* event) {
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_NE(static_cast<base::debug::AddDynamicSymbol>(NULL),
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            add_dynamic_symbol_func);
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_NE(static_cast<base::debug::MoveDynamicSymbol>(NULL),
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            move_dynamic_symbol_func);
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  switch (event->type) {
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case v8::JitCodeEvent::CODE_ADDED:
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      add_dynamic_symbol_func(event->code_start, event->code_len,
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              event->name.str, event->name.len);
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case v8::JitCodeEvent::CODE_MOVED:
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      move_dynamic_symbol_func(event->code_start, event->new_code_start);
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    default:
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetProfileName() {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kDefaultProfileName[] = "chrome-profile-{type}-{pid}";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_name.empty()) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (command_line.HasSwitch(switches::kProfilingFile))
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_name = std::string(kDefaultProfileName);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string process_type =
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProcessType);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string type = process_type.empty() ?
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string("browser") : std::string(process_type);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_name;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FlushProfilingData(base::Thread* thread) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kProfilingFlushSeconds = 10;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Profiling::BeingProfiled())
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::FlushProfiling();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int flush_seconds;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!flush_seconds) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string profiling_flush =
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProfilingFlush);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!profiling_flush.empty()) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_seconds = atoi(profiling_flush.c_str());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(flush_seconds > 0);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flush_seconds = kProfilingFlushSeconds;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread->message_loop()->PostDelayedTask(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&FlushProfilingData, thread),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(flush_seconds));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProfilingThreadControl {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfilingThreadControl() : thread_(NULL) {}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(lock_);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (thread_ && thread_->IsRunning())
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_ = new base::Thread("Profiling_Flush");
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->Start();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->message_loop()->PostTask(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&FlushProfilingData, thread_));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop() {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(lock_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!thread_ || !thread_->IsRunning())
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->Stop();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete thread_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_ = NULL;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Thread* thread_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ProfilingThreadControl);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<ProfilingThreadControl>::Leaky
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_flush_thread_control = LAZY_INSTANCE_INITIALIZER;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::ProcessStarted() {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string process_type =
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kProcessType);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Establish the V8 profiling hooks if we're an instrumented binary.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::debug::IsBinaryInstrumented()) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::debug::ReturnAddressLocationResolver resolve_func =
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::debug::GetProfilerReturnAddrResolutionFunc();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (resolve_func != NULL) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      v8::V8::SetReturnAddressLocationResolver(resolve_func);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Set up the JIT code entry handler and the symbol callbacks if the
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // profiler supplies them.
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // TODO(siggi): Maybe add a switch or an environment variable to turn off
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    //     V8 profiling?
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::debug::DynamicFunctionEntryHook entry_hook_func =
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        base::debug::GetProfilerDynamicFunctionEntryHookFunc();
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    add_dynamic_symbol_func = base::debug::GetProfilerAddDynamicSymbolFunc();
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    move_dynamic_symbol_func = base::debug::GetProfilerMoveDynamicSymbolFunc();
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    v8::Isolate* isolate = v8::Isolate::GetCurrent();
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (isolate != NULL &&
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        entry_hook_func != NULL &&
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        add_dynamic_symbol_func != NULL &&
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        move_dynamic_symbol_func != NULL) {
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      v8::V8::SetFunctionEntryHook(isolate, entry_hook_func);
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                     &JitCodeEventHandler);
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line.HasSwitch(switches::kProfilingAtStart)) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string process_type_to_start =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kProfilingAtStart);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (process_type == process_type_to_start)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Start();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Start() {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool flush = command_line.HasSwitch(switches::kProfilingFlush);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::StartProfiling(GetProfileName());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule profile data flushing for single process because it doesn't
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // get written out correctly on exit.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flush)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_flush_thread_control.Get().Start();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Stop() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_flush_thread_control.Get().Stop();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::StopProfiling();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Profiling::BeingProfiled() {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::debug::BeingProfiled();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Profiling::Toggle() {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (BeingProfiled())
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Start();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
198