diff options
author | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-01 23:35:25 +0000 |
---|---|---|
committer | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-01 23:35:25 +0000 |
commit | 7664ab3d9d921bc769977c2921ecb4e5ea0cc793 (patch) | |
tree | ab884002c040253f951d05ef7b3e5033d35d1c99 | |
parent | 22258c851d500a42113c833ac06d244cf4d4236b (diff) | |
download | chromium_src-7664ab3d9d921bc769977c2921ecb4e5ea0cc793.zip chromium_src-7664ab3d9d921bc769977c2921ecb4e5ea0cc793.tar.gz chromium_src-7664ab3d9d921bc769977c2921ecb4e5ea0cc793.tar.bz2 |
Added command line switches and UI (controlled via a build option)
to make it easier to use the sampling profiler.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/6250070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73374 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.gypi | 2 | ||||
-rw-r--r-- | base/debug/profiler.cc | 65 | ||||
-rw-r--r-- | base/debug/profiler.h | 35 | ||||
-rw-r--r-- | build/common.gypi | 13 | ||||
-rw-r--r-- | chrome/app/chrome_command_ids.h | 1 | ||||
-rw-r--r-- | chrome/app/chrome_main.cc | 3 | ||||
-rw-r--r-- | chrome/app/generated_resources.grd | 6 | ||||
-rw-r--r-- | chrome/browser/browser_main.cc | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 3 | ||||
-rw-r--r-- | chrome/browser/ui/browser.cc | 5 | ||||
-rw-r--r-- | chrome/browser/ui/toolbar/wrench_menu_model.cc | 8 | ||||
-rw-r--r-- | chrome/chrome_common.gypi | 2 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 20 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 3 | ||||
-rw-r--r-- | chrome/common/profiling.cc | 112 | ||||
-rw-r--r-- | chrome/common/profiling.h | 48 |
16 files changed, 328 insertions, 0 deletions
diff --git a/base/base.gypi b/base/base.gypi index aee11f5..385794e 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -52,6 +52,8 @@ 'debug/debugger_win.cc', 'debug/leak_annotations.h', 'debug/leak_tracker.h', + 'debug/profiler.cc', + 'debug/profiler.h', 'debug/stack_trace.cc', 'debug/stack_trace.h', 'debug/stack_trace_posix.cc', diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc new file mode 100644 index 0000000..8597dac --- /dev/null +++ b/base/debug/profiler.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/profiler.h" + +#include <string> + +#include "base/process_util.h" +#include "base/string_util.h" + +#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) +#include "third_party/tcmalloc/chromium/src/google/profiler.h" +#endif + +namespace base { +namespace debug { + +#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) + +static int profile_count = 0; + +void StartProfiling(const std::string& name) { + ++profile_count; + std::string full_name(name); + std::string pid = StringPrintf("%d", GetCurrentProcId()); + std::string count = StringPrintf("%d", profile_count); + ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid); + ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count); + ProfilerStart(full_name.c_str()); +} + +void StopProfiling() { + ProfilerFlush(); + ProfilerStop(); +} + +void FlushProfiling() { + ProfilerFlush(); +} + +bool BeingProfiled() { + return ProfilingIsEnabledForAllThreads(); +} + +#else + +void StartProfiling(const std::string& name) { +} + +void StopProfiling() { +} + +void FlushProfiling() { +} + +bool BeingProfiled() { + return false; +} + +#endif + +} // namespace debug +} // namespace base + diff --git a/base/debug/profiler.h b/base/debug/profiler.h new file mode 100644 index 0000000..e3044d6 --- /dev/null +++ b/base/debug/profiler.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_PROFILER_H +#define BASE_DEBUG_PROFILER_H +#pragma once + +#include <string> + +// The Profiler functions allow usage of the underlying sampling based +// profiler. If the application has not been built with the necessary +// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions +// are noops. +namespace base { +namespace debug { + +// Start profiling with the supplied name. +// {pid} will be replaced by the process' pid and {count} will be replaced +// by the count of the profile run (starts at 1 with each process). +void StartProfiling(const std::string& name); + +// Stop profiling and write out data. +void StopProfiling(); + +// Force data to be written to file. +void FlushProfiling(); + +// Returns true if process is being profiled. +bool BeingProfiled(); + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_DEBUGGER_H diff --git a/build/common.gypi b/build/common.gypi index 46059bd..45446f6 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -282,6 +282,10 @@ 'clang_load%': '', 'clang_add_plugin%': '', + # Enable sampling based profiler. + # See http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html + 'profiling%': '0', + # Override whether we should use Breakpad on Linux. I.e. for Chrome bot. 'linux_breakpad%': 0, # And if we want to dump symbols for Breakpad-enabled builds. @@ -542,6 +546,9 @@ ['touchui==1', { 'defines': ['TOUCH_UI=1'], }], + ['profiling==1', { + 'defines': ['ENABLE_PROFILING=1'], + }], ['remoting==1', { 'defines': ['ENABLE_REMOTING=1'], }], @@ -1020,6 +1027,12 @@ '-fno-ident', ], }], + ['profiling==1', { + 'cflags': [ + '-fno-omit-frame-pointer', + '-g', + ], + }], ] }, }, diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index 926088d..7f7b0c7 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h @@ -161,6 +161,7 @@ #define IDC_VIEW_INCOMPATIBILITIES 40027 #define IDC_VIEW_BACKGROUND_PAGES 40028 #define IDC_SHOW_KEYBOARD_OVERLAY 40029 +#define IDC_PROFILING_ENABLED 40030 // Spell-check // Insert any additional suggestions before _LAST; these have to be consecutive. diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc index edbb38e..1613049 100644 --- a/chrome/app/chrome_main.cc +++ b/chrome/app/chrome_main.cc @@ -31,6 +31,7 @@ #include "chrome/common/chrome_version_info.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/main_function_params.h" +#include "chrome/common/profiling.h" #include "chrome/common/sandbox_init_wrapper.h" #include "chrome/common/set_process_title.h" #include "chrome/common/url_constants.h" @@ -646,6 +647,8 @@ int ChromeMain(int argc, char** argv) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + Profiling::ProcessStarted(); + #if defined(OS_POSIX) if (HandleVersionSwitches(command_line)) return 0; // Got a --version switch; exit with a success error code. diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 826657f..27b7db9 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -949,6 +949,9 @@ each locale. --> <message name="IDS_SHOW_BOOKMARK_BAR" desc="The toggle to show the bookmark bar"> &Always show bookmarks bar </message> + <message name="IDS_PROFILING_ENABLED" desc="The toggle to turn profiling on / off"> + &Profiling enabled + </message> <message name="IDS_FULLSCREEN" desc="Switches into fullscreen mode"> &Full screen </message> @@ -996,6 +999,9 @@ each locale. --> <message name="IDS_SHOW_BOOKMARK_BAR" desc="In Title Case: The toggle to show the bookmark bar"> &Always Show Bookmarks Bar </message> + <message name="IDS_PROFILING_ENABLED" desc="In Title Case: The toggle to turn profiling on / off"> + &Profiling Enabled + </message> <message name="IDS_FULLSCREEN" desc="In Title Case: Switches into fullscreen mode"> &Full Screen </message> diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 880502f..c6573b6 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -85,6 +85,7 @@ #include "chrome/common/main_function_params.h" #include "chrome/common/net/net_resource_provider.h" #include "chrome/common/pref_names.h" +#include "chrome/common/profiling.h" #include "chrome/common/result_codes.h" #include "chrome/installer/util/google_update_settings.h" #include "gfx/gfx_module.h" @@ -506,6 +507,7 @@ void BrowserMainParts::MainMessageLoopStart() { InitializeMainThread(); PostMainMessageLoopStart(); + Profiling::MainMessageLoopStarted(); } void BrowserMainParts::InitializeMainThread() { diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 51a5071..5d488cf 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -715,6 +715,9 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer( switches::kNoSandbox, switches::kPlaybackMode, switches::kPpapiOutOfProcess, + switches::kProfilingAtStart, + switches::kProfilingFile, + switches::kProfilingFlush, switches::kRecordMode, switches::kRegisterPepperPlugins, switches::kRemoteShellPort, diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 05fd143..0d16526 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -98,6 +98,7 @@ #include "chrome/common/notification_service.h" #include "chrome/common/page_transition_types.h" #include "chrome/common/pref_names.h" +#include "chrome/common/profiling.h" #include "chrome/common/url_constants.h" #include "chrome/common/web_apps.h" #include "grit/chromium_strings.h" @@ -1157,6 +1158,9 @@ void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui); +#if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC) + command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -2261,6 +2265,7 @@ void Browser::ExecuteCommandWithDisposition( case IDC_FEEDBACK: OpenBugReportDialog(); break; case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break; + case IDC_PROFILING_ENABLED: Profiling::Toggle(); break; case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break; case IDC_SHOW_APP_MENU: ShowAppMenu(); break; diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.cc b/chrome/browser/ui/toolbar/wrench_menu_model.cc index a1151df..dd4591a 100644 --- a/chrome/browser/ui/toolbar/wrench_menu_model.cc +++ b/chrome/browser/ui/toolbar/wrench_menu_model.cc @@ -30,6 +30,7 @@ #include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" +#include "chrome/common/profiling.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -184,6 +185,11 @@ void ToolsMenuModel::Build(Browser* browser) { AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS); AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE); } + +#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) + AddSeparator(); + AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED); +#endif } //////////////////////////////////////////////////////////////////////////////// @@ -258,6 +264,8 @@ void WrenchMenuModel::ExecuteCommand(int command_id) { bool WrenchMenuModel::IsCommandIdChecked(int command_id) const { if (command_id == IDC_SHOW_BOOKMARK_BAR) { return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); + } else if (command_id == IDC_PROFILING_ENABLED) { + return Profiling::BeingProfiled(); } return false; diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index cb8bc1d..931b279 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -145,6 +145,8 @@ 'common/process_watcher_win.cc', 'common/property_bag.cc', 'common/property_bag.h', + 'common/profiling.cc', + 'common/profiling.h', 'common/ref_counted_util.h', 'common/resource_response.cc', 'common/resource_response.h', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 032c0df..65f40a8 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -964,6 +964,26 @@ const char kProductVersion[] = "product-version"; // Causes the process to run as a profile import subprocess. const char kProfileImportProcess[] = "profile-import"; +// Starts the sampling based profiler for the browser process at +// startup. This will only work if chrome has been built with +// the gyp variable profiling=1. The output will go to the value +// of kProfilingFile. +const char kProfilingAtStart[] = "profiling-at-start"; + +// Specifies a location for profiling output. This will only work if chrome +// has been built with the gyp variable profiling=1. +// {pid} if present will be replaced by the pid of the process. +// {count} if present will be incremented each time a profile is generated +// for this process. +// The default is chrome-profile-{pid}. +const char kProfilingFile[] = "profiling-file"; + +// Controls whether profile data is periodically flushed to a file. +// Normally the data gets written on exit but cases exist where chrome +// doesn't exit cleanly (especially when using single-process). +// A time in seconds can be specified. +const char kProfilingFlush[] = "profiling-flush"; + // Force proxy auto-detection. const char kProxyAutoDetect[] = "proxy-auto-detect"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 708a55f..42a0390 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -274,6 +274,9 @@ extern const char kProcessPerTab[]; extern const char kProcessType[]; extern const char kProductVersion[]; extern const char kProfileImportProcess[]; +extern const char kProfilingAtStart[]; +extern const char kProfilingFile[]; +extern const char kProfilingFlush[]; extern const char kProxyAutoDetect[]; extern const char kProxyBypassList[]; extern const char kProxyPacUrl[]; diff --git a/chrome/common/profiling.cc b/chrome/common/profiling.cc new file mode 100644 index 0000000..bf67885 --- /dev/null +++ b/chrome/common/profiling.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/profiling.h" + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/debug/profiler.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "chrome/common/chrome_switches.h" + +namespace { +std::string GetProfileName() { + static const char kDefaultProfileName[] = "chrome-profile-{pid}"; + static std::string profile_name; + + if (profile_name.empty()) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kProfilingFile)) + profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile); + else + profile_name = std::string(kDefaultProfileName); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + std::string type = process_type.empty() ? + std::string("browser") : std::string(process_type); + ReplaceSubstringsAfterOffset(&profile_name, 0, "{type}", type.c_str()); + } + return profile_name; +} + +void FlushProfilingData() { + static const int kProfilingFlushSeconds = 10; + + if (!Profiling::BeingProfiled()) + return; + + base::debug::FlushProfiling(); + static int flush_seconds = 0; + if (!flush_seconds) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + std::string profiling_flush = + command_line.GetSwitchValueASCII(switches::kProfilingFlush); + if (!profiling_flush.empty()) { + flush_seconds = atoi(profiling_flush.c_str()); + DCHECK(flush_seconds > 0); + } else { + flush_seconds = kProfilingFlushSeconds; + } + } + MessageLoop::current()->PostDelayedTask(FROM_HERE, + NewRunnableFunction(FlushProfilingData), + flush_seconds * 1000); +} + +} // namespace + +// static +void Profiling::ProcessStarted() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + + if (command_line.HasSwitch(switches::kProfilingAtStart)) { + std::string process_type_to_start = + command_line.GetSwitchValueASCII(switches::kProfilingAtStart); + if (process_type == process_type_to_start) + Start(); + } +} + +// static +void Profiling::Start() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool flush = command_line.HasSwitch(switches::kProfilingFlush); + base::debug::StartProfiling(GetProfileName()); + + // Schedule profile data flushing for single process because it doesn't + // get written out correctly on exit. + if (flush && MessageLoop::current()) + FlushProfilingData(); +} + +// static +void Profiling::Stop() { + base::debug::StopProfiling(); +} + +// static +bool Profiling::BeingProfiled() { + return base::debug::BeingProfiled(); +} + +// static +void Profiling::Toggle() { + if (BeingProfiled()) + Stop(); + else + Start(); +} + +// static +void Profiling::MainMessageLoopStarted() { + if (BeingProfiled()) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool flush = command_line.HasSwitch(switches::kProfilingFlush); + if (flush) + FlushProfilingData(); + } +} diff --git a/chrome/common/profiling.h b/chrome/common/profiling.h new file mode 100644 index 0000000..21aebd1 --- /dev/null +++ b/chrome/common/profiling.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_PROFILING_H_ +#define CHROME_COMMON_PROFILING_H_ +#pragma once + +#include "build/build_config.h" + +#include "base/basictypes.h" +#include "base/debug/profiler.h" + +// The Profiling class manages the interaction with a sampling based profiler. +// Its function is controlled by the kProfilingAtStart, kProfilingFile, and +// kProfilingFlush command line values. +// All of the API should only be called from the main thread of the process. +class Profiling { + public: + // Called early in a process' life to allow profiling of startup time. + // the presence of kProfilingAtStart is checked. + static void ProcessStarted(); + + // Start profiling. + static void Start(); + + // Stop profiling and write out profiling file. + static void Stop(); + + // Returns true if the process is being profiled. + static bool BeingProfiled(); + + // Called when the main message loop is started, so that automatic flushing + // of the profile data file can be done. + static void MainMessageLoopStarted(); + + // Toggle profiling on/off. + static void Toggle(); + + private: + // Do not instantiate this class. + Profiling(); + + DISALLOW_COPY_AND_ASSIGN(Profiling); +}; + +#endif // CHROME_COMMON_PROFILING_H_ + |