summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/status/memory_menu_button.cc95
-rw-r--r--chrome/browser/chromeos/status/memory_menu_button.h3
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.cc15
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.h4
-rw-r--r--chrome/common/render_messages.h17
-rw-r--r--chrome/renderer/chrome_render_process_observer.cc39
-rw-r--r--chrome/renderer/chrome_render_process_observer.h3
7 files changed, 167 insertions, 9 deletions
diff --git a/chrome/browser/chromeos/status/memory_menu_button.cc b/chrome/browser/chromeos/status/memory_menu_button.cc
index 634c985..d9d1190 100644
--- a/chrome/browser/chromeos/status/memory_menu_button.cc
+++ b/chrome/browser/chromeos/status/memory_menu_button.cc
@@ -4,16 +4,27 @@
#include "chrome/browser/chromeos/status/memory_menu_button.h"
+#include "base/file_util.h"
#include "base/process_util.h" // GetSystemMemoryInfo
#include "base/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "chrome/browser/memory_purger.h"
+#include "chrome/common/render_messages.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "views/widget/widget.h"
+#if defined(USE_TCMALLOC)
+#include "third_party/tcmalloc/chromium/src/google/heap-profiler.h"
+#endif
+
+#if defined(USE_TCMALLOC)
+const char kProfileDumpFilePrefix[] = "/tmp/chrome_tcmalloc";
+#endif
+
namespace {
// views::MenuItemView item ids
@@ -24,6 +35,10 @@ enum {
MEM_CACHE_ITEM,
SHMEM_ITEM,
PURGE_MEMORY_ITEM,
+#if defined(USE_TCMALLOC)
+ TOGGLE_PROFILING_ITEM,
+ DUMP_PROFILING_ITEM,
+#endif
};
} // namespace
@@ -88,6 +103,15 @@ std::wstring MemoryMenuButton::GetLabel(int id) const {
return StringPrintf(L"%d MB shmem", meminfo_->shmem / 1024);
case PURGE_MEMORY_ITEM:
return L"Purge memory";
+#if defined(USE_TCMALLOC)
+ case TOGGLE_PROFILING_ITEM:
+ if (!IsHeapProfilerRunning())
+ return L"Start profiling";
+ else
+ return L"Stop profiling";
+ case DUMP_PROFILING_ITEM:
+ return L"Dump profile";
+#endif
default:
return std::wstring();
}
@@ -97,16 +121,80 @@ bool MemoryMenuButton::IsCommandEnabled(int id) const {
switch (id) {
case PURGE_MEMORY_ITEM:
return true;
+#if defined(USE_TCMALLOC)
+ case TOGGLE_PROFILING_ITEM:
+ case DUMP_PROFILING_ITEM:
+ return true;
+#endif
default:
return false;
}
}
+namespace {
+#if defined(USE_TCMALLOC)
+FilePath::StringType GetProfileDumpFilePath(base::ProcessId pid) {
+ int int_pid = static_cast<int>(pid);
+ FilePath::StringType filepath = StringPrintf(
+ FILE_PATH_LITERAL("%s.%d.heap"),
+ FILE_PATH_LITERAL(kProfileDumpFilePrefix), int_pid);
+ return filepath;
+}
+#endif
+}
+
+void MemoryMenuButton::SendCommandToRenderers(int id) {
+#if defined(USE_TCMALLOC)
+ // Use the "is running" value for this process to determine whether to
+ // start or stop profiling on the renderer processes.
+ bool started = IsHeapProfilerRunning();
+ for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
+ !it.IsAtEnd(); it.Advance()) {
+ switch (id) {
+ case TOGGLE_PROFILING_ITEM:
+ it.GetCurrentValue()->Send(new ViewMsg_SetTcmallocHeapProfiling(
+ started, std::string(kProfileDumpFilePrefix)));
+ break;
+ case DUMP_PROFILING_ITEM:
+ it.GetCurrentValue()->Send(new ViewMsg_WriteTcmallocHeapProfile(
+ GetProfileDumpFilePath(
+ base::GetProcId(it.GetCurrentValue()->GetHandle()))));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+#endif
+}
+
void MemoryMenuButton::ExecuteCommand(int id) {
switch (id) {
case PURGE_MEMORY_ITEM:
MemoryPurger::PurgeAll();
break;
+#if defined(USE_TCMALLOC)
+ case TOGGLE_PROFILING_ITEM: {
+ if (!IsHeapProfilerRunning())
+ HeapProfilerStart(kProfileDumpFilePrefix);
+ else
+ HeapProfilerStop();
+ SendCommandToRenderers(id);
+ break;
+ }
+ case DUMP_PROFILING_ITEM: {
+ char* profile = GetHeapProfile();
+ if (profile) {
+ FilePath::StringType filepath =
+ GetProfileDumpFilePath(base::GetProcId(base::GetCurrentProcId()));
+ VLOG(0) << "Writing browser heap profile dump to: " << filepath;
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ file_util::WriteFile(FilePath(filepath), profile, strlen(profile));
+ delete profile;
+ }
+ SendCommandToRenderers(id);
+ break;
+ }
+#endif
default:
NOTREACHED();
break;
@@ -147,9 +235,14 @@ void MemoryMenuButton::EnsureMenu() {
menu_->AppendDelegateMenuItem(MEM_BUFFERS_ITEM);
menu_->AppendDelegateMenuItem(MEM_CACHE_ITEM);
menu_->AppendDelegateMenuItem(SHMEM_ITEM);
- // TODO(jamescook): Dump heap profiles?
menu_->AppendSeparator();
menu_->AppendDelegateMenuItem(PURGE_MEMORY_ITEM);
+#if defined(USE_TCMALLOC)
+ menu_->AppendSeparator();
+ menu_->AppendDelegateMenuItem(TOGGLE_PROFILING_ITEM);
+ if (IsHeapProfilerRunning())
+ menu_->AppendDelegateMenuItem(DUMP_PROFILING_ITEM);
+#endif
}
/////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/chromeos/status/memory_menu_button.h b/chrome/browser/chromeos/status/memory_menu_button.h
index d404c39..7e2c83a 100644
--- a/chrome/browser/chromeos/status/memory_menu_button.h
+++ b/chrome/browser/chromeos/status/memory_menu_button.h
@@ -55,6 +55,9 @@ class MemoryMenuButton : public StatusAreaButton,
virtual int horizontal_padding() OVERRIDE;
private:
+ // Execute command id for each renderer. Used for heap profiling.
+ void SendCommandToRenderers(int id);
+
// Create and initialize menu if not already present.
void EnsureMenu();
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index b7f1cfe..5cc1293 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
-#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
#include "chrome/browser/browser_process.h"
@@ -121,6 +121,8 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message,
OnExtensionRequestForIOThread)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_WriteTcmallocHeapProfile_ACK,
+ OnWriteTcmallocHeapProfile)
#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginPolicies, OnGetPluginPolicies)
IPC_MESSAGE_HANDLER(ViewHostMsg_AllowDatabase, OnAllowDatabase)
@@ -384,10 +386,17 @@ void ChromeRenderMessageFilter::OnExtensionRequestForIOThread(
}
#if defined(USE_TCMALLOC)
-void ChromeRenderMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
- const std::string& output) {
+void ChromeRenderMessageFilter::OnRendererTcmalloc(const std::string& output) {
+ base::ProcessId pid = base::GetProcId(peer_handle());
AboutTcmallocRendererCallback(pid, output);
}
+
+void ChromeRenderMessageFilter::OnWriteTcmallocHeapProfile(
+ const FilePath::StringType& filepath,
+ const std::string& output) {
+ VLOG(0) << "Writing renderer heap profile dump to: " << filepath;
+ file_util::WriteFile(FilePath(filepath), output.c_str(), output.size());
+}
#endif
void ChromeRenderMessageFilter::OnGetPluginPolicies(
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h
index a1c6311..cd64c14 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.h
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.h
@@ -88,7 +88,9 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter {
int routing_id,
const ExtensionHostMsg_Request_Params& params);
#if defined(USE_TCMALLOC)
- void OnRendererTcmalloc(base::ProcessId pid, const std::string& output);
+ void OnRendererTcmalloc(const std::string& output);
+ void OnWriteTcmallocHeapProfile(const FilePath::StringType& filename,
+ const std::string& output);
#endif
void OnGetPluginPolicies(ContentSetting* outdated_policy,
ContentSetting* authorize_policy);
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 88b0f5d..976a8e9 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -211,6 +211,16 @@ IPC_MESSAGE_CONTROL2(ViewMsg_SetFieldTrialGroup,
#if defined(USE_TCMALLOC)
// Asks the renderer to send back tcmalloc stats.
IPC_MESSAGE_CONTROL0(ViewMsg_GetRendererTcmalloc)
+// Asks the renderer to enable/disable Tcmalloc heap profiling.
+// Note: filename_prefix arg is effectively ignored since the render process
+// will be unable to write files to disk. Instead use WriteTcmallocHeapProfile
+// to write a profile file.
+IPC_MESSAGE_CONTROL2(ViewMsg_SetTcmallocHeapProfiling,
+ bool /* enable profiling */,
+ std::string /* filename prefix for profiles */)
+// Asks the renderer to write the Tcmalloc heap profile to a file.
+IPC_MESSAGE_CONTROL1(ViewMsg_WriteTcmallocHeapProfile,
+ FilePath::StringType /* filepath */)
#endif
// Asks the renderer to send back V8 heap stats.
@@ -414,9 +424,12 @@ IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererHistograms,
#if defined USE_TCMALLOC
// Send back tcmalloc stats output.
-IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererTcmalloc,
- int /* pid */,
+IPC_MESSAGE_CONTROL1(ViewHostMsg_RendererTcmalloc,
std::string /* tcmalloc debug output */)
+// Send back tcmalloc profile to write to a file.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_WriteTcmallocHeapProfile_ACK,
+ FilePath::StringType /* filepath */,
+ std::string /* heap profile */)
#endif
// Sends back stats about the V8 heap.
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 7805e7b..e36dc8d 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -33,6 +33,7 @@
#include "net/base/net_module.h"
#include "third_party/sqlite/sqlite3.h"
#include "third_party/tcmalloc/chromium/src/google/malloc_extension.h"
+#include "third_party/tcmalloc/chromium/src/google/heap-profiler.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h"
@@ -407,6 +408,10 @@ bool ChromeRenderProcessObserver::OnControlMessageReceived(
IPC_MESSAGE_HANDLER(ViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ViewMsg_GetRendererTcmalloc, OnGetRendererTcmalloc)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetTcmallocHeapProfiling,
+ OnSetTcmallocHeapProfiling)
+ IPC_MESSAGE_HANDLER(ViewMsg_WriteTcmallocHeapProfile,
+ OnWriteTcmallocHeapProfile)
#endif
IPC_MESSAGE_HANDLER(ViewMsg_GetV8HeapStats, OnGetV8HeapStats)
IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats, OnGetCacheResourceStats)
@@ -458,11 +463,41 @@ void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
void ChromeRenderProcessObserver::OnGetRendererTcmalloc() {
std::string result;
char buffer[1024 * 32];
- base::ProcessId pid = base::GetCurrentProcId();
MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
result.append(buffer);
- Send(new ViewHostMsg_RendererTcmalloc(pid, result));
+ Send(new ViewHostMsg_RendererTcmalloc(result));
}
+
+void ChromeRenderProcessObserver::OnSetTcmallocHeapProfiling(
+ bool profiling, const std::string& filename_prefix) {
+#if !defined(OS_WIN)
+ // TODO(stevenjb): Create MallocExtension wrappers for HeapProfile functions.
+ if (profiling)
+ HeapProfilerStart(filename_prefix.c_str());
+ else
+ HeapProfilerStop();
+#endif
+}
+
+void ChromeRenderProcessObserver::OnWriteTcmallocHeapProfile(
+ const FilePath::StringType& filename) {
+#if !defined(OS_WIN)
+ // TODO(stevenjb): Create MallocExtension wrappers for HeapProfile functions.
+ if (!IsHeapProfilerRunning())
+ return;
+ char* profile = GetHeapProfile();
+ if (!profile) {
+ LOG(WARNING) << "Unable to get heap profile.";
+ return;
+ }
+ // The render process can not write to a file, so copy the result into
+ // a string and pass it to the handler (which runs on the browser host).
+ std::string result(profile);
+ delete profile;
+ Send(new ViewHostMsg_WriteTcmallocHeapProfile_ACK(filename, result));
+#endif
+}
+
#endif
void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
diff --git a/chrome/renderer/chrome_render_process_observer.h b/chrome/renderer/chrome_render_process_observer.h
index 9361290..80bf18ef 100644
--- a/chrome/renderer/chrome_render_process_observer.h
+++ b/chrome/renderer/chrome_render_process_observer.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "base/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "content/renderer/render_process_observer.h"
@@ -49,6 +50,8 @@ class ChromeRenderProcessObserver : public RenderProcessObserver {
void OnSetFieldTrialGroup(const std::string& fiel_trial_name,
const std::string& group_name);
void OnGetRendererTcmalloc();
+ void OnSetTcmallocHeapProfiling(bool profiling, const std::string& prefix);
+ void OnWriteTcmallocHeapProfile(const FilePath::StringType& filename);
void OnGetV8HeapStats();
void OnPurgeMemory();