summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-01 23:35:25 +0000
committerdavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-01 23:35:25 +0000
commit7664ab3d9d921bc769977c2921ecb4e5ea0cc793 (patch)
treeab884002c040253f951d05ef7b3e5033d35d1c99
parent22258c851d500a42113c833ac06d244cf4d4236b (diff)
downloadchromium_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.gypi2
-rw-r--r--base/debug/profiler.cc65
-rw-r--r--base/debug/profiler.h35
-rw-r--r--build/common.gypi13
-rw-r--r--chrome/app/chrome_command_ids.h1
-rw-r--r--chrome/app/chrome_main.cc3
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/browser_main.cc2
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc3
-rw-r--r--chrome/browser/ui/browser.cc5
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.cc8
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/common/chrome_switches.cc20
-rw-r--r--chrome/common/chrome_switches.h3
-rw-r--r--chrome/common/profiling.cc112
-rw-r--r--chrome/common/profiling.h48
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">
&amp;Always show bookmarks bar
</message>
+ <message name="IDS_PROFILING_ENABLED" desc="The toggle to turn profiling on / off">
+ &amp;Profiling enabled
+ </message>
<message name="IDS_FULLSCREEN" desc="Switches into fullscreen mode">
&amp;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">
&amp;Always Show Bookmarks Bar
</message>
+ <message name="IDS_PROFILING_ENABLED" desc="In Title Case: The toggle to turn profiling on / off">
+ &amp;Profiling Enabled
+ </message>
<message name="IDS_FULLSCREEN" desc="In Title Case: Switches into fullscreen mode">
&amp;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_
+