diff options
Diffstat (limited to 'chrome')
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(); |