diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-11 23:55:10 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-11 23:55:10 +0000 |
commit | a27a938d8511abfaf89d6e2d0e4d4242c76dffed (patch) | |
tree | 98b133536459106b96a0ee09e0deb94b8d92c4b3 /chrome/browser/memory_details.cc | |
parent | 342c2c40bd1729fe985d5a6ee06f6eb28bbcdc22 (diff) | |
download | chromium_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.cc | 286 |
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); } - |