summaryrefslogtreecommitdiffstats
path: root/chrome/browser/memory_details.cc
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-11 23:55:10 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-11 23:55:10 +0000
commita27a938d8511abfaf89d6e2d0e4d4242c76dffed (patch)
tree98b133536459106b96a0ee09e0deb94b8d92c4b3 /chrome/browser/memory_details.cc
parent342c2c40bd1729fe985d5a6ee06f6eb28bbcdc22 (diff)
downloadchromium_src-a27a938d8511abfaf89d6e2d0e4d4242c76dffed.zip
chromium_src-a27a938d8511abfaf89d6e2d0e4d4242c76dffed.tar.gz
chromium_src-a27a938d8511abfaf89d6e2d0e4d4242c76dffed.tar.bz2
Refactor plugin process code in the browser process so that the browser/about:memory/task manager/metrics code doesn't depend on PluginProcessHost pointers. In a future changelist I'll add one central child process registry in the browser process.
Review URL: http://codereview.chromium.org/20196 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9621 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/memory_details.cc')
-rw-r--r--chrome/browser/memory_details.cc286
1 files changed, 148 insertions, 138 deletions
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index f2c3f79..e1279fe 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -10,9 +10,9 @@
#include "base/image_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
+#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_trial.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
@@ -64,155 +64,190 @@ void MemoryDetails::StartFetch() {
// In order to process this request, we need to use the plugin information.
// However, plugin process information is only available from the IO thread.
g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &MemoryDetails::CollectPluginInformation));
+ NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnIOThread));
}
-void MemoryDetails::CollectPluginInformation() {
+void MemoryDetails::CollectChildInfoOnIOThread() {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::IO));
+ std::vector<ProcessMemoryInformation> child_info;
+
// Collect the list of plugins.
for (PluginProcessHostIterator plugin_iter;
!plugin_iter.Done(); ++plugin_iter) {
- PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*plugin_iter);
- DCHECK(plugin);
- if (!plugin || !plugin->process())
+ ChildProcessInfo* child = const_cast<PluginProcessHost*>(*plugin_iter);
+ DCHECK(child);
+ if (!child || !child->process().handle())
continue;
- PluginProcessInformation info;
- info.pid = base::GetProcId(plugin->process());
- if (info.pid != 0) {
- info.plugin_path = plugin->plugin_path();
- plugins_.push_back(info);
- }
+ ProcessMemoryInformation info;
+ info.pid = child->process().pid();
+ if (!info.pid)
+ continue;
+
+ info.type = child->type();
+ info.titles.push_back(child->name());
+ child_info.push_back(info);
}
// Now go do expensive memory lookups from the file thread.
ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
- NewRunnableMethod(this, &MemoryDetails::CollectProcessData));
+ NewRunnableMethod(this, &MemoryDetails::CollectProcessData, child_info));
}
-void MemoryDetails::CollectProcessData() {
+void MemoryDetails::CollectProcessData(
+ std::vector<ProcessMemoryInformation> child_info) {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::FILE));
int array_size = 32;
- DWORD* process_list = NULL;
+ scoped_ptr_malloc<DWORD> process_list;
DWORD bytes_used = 0;
do {
array_size *= 2;
- process_list = static_cast<DWORD*>(
- realloc(process_list, sizeof(*process_list) * array_size));
+ process_list.reset(static_cast<DWORD*>(
+ realloc(process_list.release(), sizeof(DWORD) * array_size)));
// EnumProcesses doesn't return an error if the array is too small.
// We have to check if the return buffer is full, and if so, call it
// again. See msdn docs for more info.
- if (!EnumProcesses(process_list, array_size * sizeof(*process_list),
+ if (!EnumProcesses(process_list.get(), array_size * sizeof(DWORD),
&bytes_used)) {
LOG(ERROR) << "EnumProcesses failed: " << GetLastError();
return;
}
- } while (bytes_used == (array_size * sizeof(*process_list)));
+ } while (bytes_used == (array_size * sizeof(DWORD)));
- int num_processes = bytes_used / sizeof(*process_list);
+ int num_processes = bytes_used / sizeof(DWORD);
// Clear old data.
for (int index = 0; index < arraysize(g_process_template); index++)
process_data_[index].processes.clear();
for (int index = 0; index < num_processes; index++) {
- HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
- FALSE, process_list[index]);
- if (handle) {
- TCHAR name[MAX_PATH];
- if (GetModuleBaseName(handle, NULL, name, MAX_PATH-1)) {
- for (int index2 = 0; index2 < arraysize(g_process_template); index2++) {
- if (_wcsicmp(process_data_[index2].process_name, name) == 0) {
- // Get Memory Information.
- ProcessMemoryInformation info;
- info.pid = process_list[index];
- scoped_ptr<base::ProcessMetrics> metrics;
- metrics.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
- metrics->GetCommittedKBytes(&info.committed);
- metrics->GetWorkingSetKBytes(&info.working_set);
-
- // Get Version Information.
- if (index2 == 0) { // Chrome
- scoped_ptr<FileVersionInfo> version_info(
- FileVersionInfo::CreateFileVersionInfoForCurrentModule());
- if (version_info != NULL)
- info.version = version_info->file_version();
- } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH-1)) {
- std::wstring str_name(name);
- scoped_ptr<FileVersionInfo> version_info(
- FileVersionInfo::CreateFileVersionInfo(str_name));
- if (version_info != NULL) {
- info.version = version_info->product_version();
- info.product_name = version_info->product_name();
- }
- }
-
- // Add the process info to our list.
- process_data_[index2].processes.push_back(info);
- break;
- }
+ int pid = process_list.get()[index];
+ ScopedHandle handle(OpenProcess(
+ PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
+ if (!handle.Get())
+ continue;
+ TCHAR name[MAX_PATH];
+ if (!GetModuleBaseName(handle, NULL, name, MAX_PATH - 1))
+ continue;
+ for (int index2 = 0; index2 < arraysize(g_process_template); index2++) {
+ if (_wcsicmp(process_data_[index2].process_name, name) != 0)
+ continue;
+ // Get Memory Information.
+ ProcessMemoryInformation info;
+ info.pid = pid;
+ if (info.pid == GetCurrentProcessId())
+ info.type = ChildProcessInfo::BROWSER_PROCESS;
+ else
+ info.type = ChildProcessInfo::UNKNOWN_PROCESS;
+
+ scoped_ptr<base::ProcessMetrics> metrics;
+ metrics.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
+ metrics->GetCommittedKBytes(&info.committed);
+ metrics->GetWorkingSetKBytes(&info.working_set);
+
+ // Get Version Information.
+ if (index2 == 0) { // Chrome
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfoForCurrentModule());
+ if (version_info != NULL)
+ info.version = version_info->file_version();
+ // Check if this is one of the child processes whose data we collected
+ // on the IO thread, and if so copy over that data.
+ for (size_t child = 0; child < child_info.size(); child++) {
+ if (child_info[child].pid != info.pid)
+ continue;
+ info.titles = child_info[child].titles;
+ info.type = child_info[child].type;
+ break;
+ }
+ } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH - 1)) {
+ std::wstring str_name(name);
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfo(str_name));
+ if (version_info != NULL) {
+ info.version = version_info->product_version();
+ info.product_name = version_info->product_name();
}
}
- CloseHandle(handle);
+
+ // Add the process info to our list.
+ process_data_[index2].processes.push_back(info);
+ break;
}
}
- free(process_list);
// Finally return to the browser thread.
ui_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &MemoryDetails::CollectRenderHostInformation));
+ NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnUIThread));
}
-void MemoryDetails::CollectRenderHostInformation() {
+void MemoryDetails::CollectChildInfoOnUIThread() {
DCHECK(MessageLoop::current() == ui_loop_);
- // Determine if this is a diagnostics-related process. We skip all
- // diagnostics pages (e.g. "about:xxx" URLs). Iterate the RenderProcessHosts
- // to find the tab contents. If it is of type TAB_CONTENTS_ABOUT_UI, mark
- // the process as diagnostics related.
+ // Get more information about the process.
for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size();
index++) {
+ // Check if it's a renderer, if so get the list of page titles in it and
+ // check if it's a diagnostics-related process. We skip all diagnostics
+ // pages (e.g. "about:xxx" URLs). Iterate the RenderProcessHosts to find
+ // the tab contents. If it is of type TAB_CONTENTS_ABOUT_UI, mark the
+ // process as diagnostics related.
RenderProcessHost::iterator renderer_iter;
for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
RenderProcessHost::end(); ++renderer_iter) {
DCHECK(renderer_iter->second);
- if (process_data_[CHROME_BROWSER].processes[index].pid ==
- renderer_iter->second->process().pid()) {
- // The RenderProcessHost may host multiple TabContents. Any
- // of them which contain diagnostics information make the whole
- // process be considered a diagnostics process.
- //
- // NOTE: This is a bit dangerous. We know that for now, listeners
- // are always RenderWidgetHosts. But in theory, they don't
- // have to be.
- RenderProcessHost::listeners_iterator iter;
- for (iter = renderer_iter->second->listeners_begin();
- iter != renderer_iter->second->listeners_end(); ++iter) {
- RenderWidgetHost* widget =
- static_cast<RenderWidgetHost*>(iter->second);
- DCHECK(widget);
- if (!widget || !widget->IsRenderView())
- continue;
-
- RenderViewHost* host = static_cast<RenderViewHost*>(widget);
- TabContents* contents =
- static_cast<WebContents*>(host->delegate());
- DCHECK(contents);
- if (!contents)
- continue;
-
- if (contents->type() == TAB_CONTENTS_ABOUT_UI)
- process_data_[CHROME_BROWSER].processes[index].is_diagnostics =
- true;
- }
+ ProcessMemoryInformation& process =
+ process_data_[CHROME_BROWSER].processes[index];
+ if (process.pid != renderer_iter->second->process().pid())
+ continue;
+ process.type = ChildProcessInfo::RENDER_PROCESS;
+ // The RenderProcessHost may host multiple TabContents. Any
+ // of them which contain diagnostics information make the whole
+ // process be considered a diagnostics process.
+ //
+ // NOTE: This is a bit dangerous. We know that for now, listeners
+ // are always RenderWidgetHosts. But in theory, they don't
+ // have to be.
+ RenderProcessHost::listeners_iterator iter;
+ for (iter = renderer_iter->second->listeners_begin();
+ iter != renderer_iter->second->listeners_end(); ++iter) {
+ RenderWidgetHost* widget =
+ static_cast<RenderWidgetHost*>(iter->second);
+ DCHECK(widget);
+ if (!widget || !widget->IsRenderView())
+ continue;
+
+ RenderViewHost* host = static_cast<RenderViewHost*>(widget);
+ TabContents* contents =
+ static_cast<WebContents*>(host->delegate());
+ DCHECK(contents);
+ if (!contents)
+ continue;
+ std::wstring title = contents->GetTitle();
+ if (!title.length())
+ title = L"Untitled";
+ process.titles.push_back(title);
+ if (contents->type() == TAB_CONTENTS_ABOUT_UI)
+ process.is_diagnostics = true;
}
}
}
+ // Get rid of other Chrome processes that are from a different profile.
+ for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size();
+ index++) {
+ if (process_data_[CHROME_BROWSER].processes[index].type ==
+ ChildProcessInfo::UNKNOWN_PROCESS) {
+ process_data_[CHROME_BROWSER].processes.erase(
+ process_data_[CHROME_BROWSER].processes.begin() + index);
+ index --;
+ }
+ }
+
UpdateHistograms();
OnDetailsAvailable();
@@ -222,61 +257,36 @@ void MemoryDetails::UpdateHistograms() {
// Reports a set of memory metrics to UMA.
// Memory is measured in units of 10KB.
- // If field trial is active, report results in special histograms.
- static scoped_refptr<FieldTrial> trial(
- FieldTrialList::Find(BrowserTrial::kMemoryModelFieldTrial));
-
- DWORD browser_pid = GetCurrentProcessId();
ProcessData browser = process_data_[CHROME_BROWSER];
size_t aggregate_memory = 0;
+ int plugin_count = 0;
+ int worker_count = 0;
for (size_t index = 0; index < browser.processes.size(); index++) {
int sample = static_cast<int>(browser.processes[index].working_set.priv);
aggregate_memory += sample;
- if (browser.processes[index].pid == browser_pid) {
- if (trial.get()) {
- if (trial->boolean_value())
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_high_memory", sample);
- else
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_med_memory", sample);
- } else {
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser", sample);
- }
- } else {
- bool is_plugin_process = false;
- for (size_t index2 = 0; index2 < plugins_.size(); index2++) {
- if (browser.processes[index].pid == plugins_[index2].pid) {
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Plugin", sample);
- is_plugin_process = true;
- break;
- }
- }
- if (!is_plugin_process) {
- if (trial.get()) {
- if (trial->boolean_value())
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_trial_high_memory",
- sample);
- else
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_trial_med_memory",
- sample);
- } else {
- UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer", sample);
- }
- }
+ switch (browser.processes[index].type) {
+ case ChildProcessInfo::BROWSER_PROCESS:
+ UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser", sample);
+ break;
+ case ChildProcessInfo::RENDER_PROCESS:
+ UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer", sample);
+ break;
+ case ChildProcessInfo::PLUGIN_PROCESS:
+ UMA_HISTOGRAM_MEMORY_KB(L"Memory.Plugin", sample);
+ plugin_count++;
+ break;
+ case ChildProcessInfo::WORKER_PROCESS:
+ UMA_HISTOGRAM_MEMORY_KB(L"Memory.Worker", sample);
+ worker_count++;
+ break;
}
}
+
UMA_HISTOGRAM_COUNTS_100(L"Memory.ProcessCount",
static_cast<int>(browser.processes.size()));
- UMA_HISTOGRAM_COUNTS_100(L"Memory.PluginProcessCount",
- static_cast<int>(plugins_.size()));
+ UMA_HISTOGRAM_COUNTS_100(L"Memory.PluginProcessCount", plugin_count);
+ UMA_HISTOGRAM_COUNTS_100(L"Memory.WorkerProcessCount", worker_count);
int total_sample = static_cast<int>(aggregate_memory / 1000);
- if (trial.get()) {
- if (trial->boolean_value())
- UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_high_memory", total_sample);
- else
- UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_med_memory", total_sample);
- } else {
- UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total", total_sample);
- }
+ UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total", total_sample);
}
-