Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: chrome/browser/memory_details.cc

Issue 177024: Linux: about:memory (Closed)
Patch Set: ... Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/memory_details.h ('k') | chrome/browser/memory_details_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/memory_details.h" 5 #include "chrome/browser/memory_details.h"
6 #include <psapi.h>
7 6
8 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
9 #include "base/file_version_info.h" 8 #include "base/file_version_info.h"
10 #include "base/string_util.h" 9 #include "base/string_util.h"
11 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_thread.h" 11 #include "chrome/browser/chrome_thread.h"
13 #include "chrome/browser/renderer_host/backing_store_manager.h" 12 #include "chrome/browser/renderer_host/backing_store_manager.h"
14 #include "chrome/browser/renderer_host/render_process_host.h" 13 #include "chrome/browser/renderer_host/render_process_host.h"
15 #include "chrome/browser/tab_contents/navigation_entry.h" 14 #include "chrome/browser/tab_contents/navigation_entry.h"
16 #include "chrome/browser/tab_contents/tab_contents.h" 15 #include "chrome/browser/tab_contents/tab_contents.h"
17 #include "chrome/common/child_process_host.h" 16 #include "chrome/common/child_process_host.h"
18 #include "chrome/common/url_constants.h" 17 #include "chrome/common/url_constants.h"
19 #include "grit/chromium_strings.h" 18 #include "grit/chromium_strings.h"
20 19
21 class RenderViewHostDelegate; 20 #if defined(OS_LINUX)
22 21 #include "chrome/browser/zygote_host_linux.h"
23 // Template of static data we use for finding browser process information. 22 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
24 // These entries must match the ordering for MemoryDetails::BrowserProcess. 23 #endif
25 static ProcessData g_process_template[MemoryDetails::MAX_BROWSERS];
26 24
27 // About threading: 25 // About threading:
28 // 26 //
29 // This operation will hit no fewer than 3 threads. 27 // This operation will hit no fewer than 3 threads.
30 // 28 //
31 // The ChildProcessInfo::Iterator can only be accessed from the IO thread. 29 // The ChildProcessInfo::Iterator can only be accessed from the IO thread.
32 // 30 //
33 // The RenderProcessHostIterator can only be accessed from the UI thread. 31 // The RenderProcessHostIterator can only be accessed from the UI thread.
34 // 32 //
35 // This operation can take 30-100ms to complete. We never want to have 33 // This operation can take 30-100ms to complete. We never want to have
36 // one task run for that long on the UI or IO threads. So, we run the 34 // one task run for that long on the UI or IO threads. So, we run the
37 // expensive parts of this operation over on the file thread. 35 // expensive parts of this operation over on the file thread.
38 // 36 //
39 37
40 MemoryDetails::MemoryDetails()
41 : ui_loop_(NULL) {
42 static const std::wstring google_browser_name =
43 l10n_util::GetString(IDS_PRODUCT_NAME);
44 ProcessData g_process_template[MemoryDetails::MAX_BROWSERS] = {
45 { google_browser_name.c_str(), L"chrome.exe", },
46 { L"IE", L"iexplore.exe", },
47 { L"Firefox", L"firefox.exe", },
48 { L"Opera", L"opera.exe", },
49 { L"Safari", L"safari.exe", },
50 { L"IE (64bit)", L"iexplore.exe", },
51 { L"Konqueror", L"konqueror.exe", },
52 };
53
54 for (int index = 0; index < arraysize(g_process_template); ++index) {
55 process_data_[index].name = g_process_template[index].name;
56 process_data_[index].process_name = g_process_template[index].process_name;
57 }
58 }
59
60 void MemoryDetails::StartFetch() { 38 void MemoryDetails::StartFetch() {
61 ui_loop_ = MessageLoop::current(); 39 ui_loop_ = MessageLoop::current();
62 40
63 DCHECK(ui_loop_ != g_browser_process->io_thread()->message_loop()); 41 DCHECK(ui_loop_ != g_browser_process->io_thread()->message_loop());
64 DCHECK(ui_loop_ != g_browser_process->file_thread()->message_loop()); 42 DCHECK(ui_loop_ != g_browser_process->file_thread()->message_loop());
65 43
66 // In order to process this request, we need to use the plugin information. 44 // In order to process this request, we need to use the plugin information.
67 // However, plugin process information is only available from the IO thread. 45 // However, plugin process information is only available from the IO thread.
68 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, 46 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
69 NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnIOThread)); 47 NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnIOThread));
(...skipping 15 matching lines...) Expand all
85 info.type = iter->type(); 63 info.type = iter->type();
86 info.titles.push_back(iter->name()); 64 info.titles.push_back(iter->name());
87 child_info.push_back(info); 65 child_info.push_back(info);
88 } 66 }
89 67
90 // Now go do expensive memory lookups from the file thread. 68 // Now go do expensive memory lookups from the file thread.
91 ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE, 69 ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
92 NewRunnableMethod(this, &MemoryDetails::CollectProcessData, child_info)); 70 NewRunnableMethod(this, &MemoryDetails::CollectProcessData, child_info));
93 } 71 }
94 72
95 void MemoryDetails::CollectProcessData(
96 std::vector<ProcessMemoryInformation> child_info) {
97 DCHECK(MessageLoop::current() ==
98 ChromeThread::GetMessageLoop(ChromeThread::FILE));
99
100 // Clear old data.
101 for (int index = 0; index < arraysize(g_process_template); index++)
102 process_data_[index].processes.clear();
103
104 SYSTEM_INFO system_info;
105 GetNativeSystemInfo(&system_info);
106 bool is_64bit_os =
107 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
108
109 ScopedHandle snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
110 PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
111 if (!snapshot.Get()) {
112 LOG(ERROR) << "CreateToolhelp32Snaphot failed: " << GetLastError();
113 return;
114 }
115 if (!::Process32First(snapshot, &process_entry)) {
116 LOG(ERROR) << "Process32First failed: " << GetLastError();
117 return;
118 }
119 do {
120 int pid = process_entry.th32ProcessID;
121 ScopedHandle handle(::OpenProcess(
122 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
123 if (!handle.Get())
124 continue;
125 bool is_64bit_process = false;
126 // IsWow64Process() returns FALSE for a 32bit process on a 32bit OS.
127 // We need to check if the real OS is 64bit.
128 if (is_64bit_os) {
129 BOOL is_wow64 = FALSE;
130 // IsWow64Process() is supported by Windows XP SP2 or later.
131 IsWow64Process(handle, &is_wow64);
132 is_64bit_process = !is_wow64;
133 }
134 for (int index2 = 0; index2 < arraysize(g_process_template); index2++) {
135 if (_wcsicmp(process_data_[index2].process_name,
136 process_entry.szExeFile) != 0)
137 continue;
138 if (index2 == IE_BROWSER && is_64bit_process)
139 continue; // Should use IE_64BIT_BROWSER
140 // Get Memory Information.
141 ProcessMemoryInformation info;
142 info.pid = pid;
143 if (info.pid == GetCurrentProcessId())
144 info.type = ChildProcessInfo::BROWSER_PROCESS;
145 else
146 info.type = ChildProcessInfo::UNKNOWN_PROCESS;
147
148 scoped_ptr<base::ProcessMetrics> metrics;
149 metrics.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
150 metrics->GetCommittedKBytes(&info.committed);
151 metrics->GetWorkingSetKBytes(&info.working_set);
152
153 // Get Version Information.
154 TCHAR name[MAX_PATH];
155 if (index2 == CHROME_BROWSER) {
156 scoped_ptr<FileVersionInfo> version_info(
157 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
158 if (version_info != NULL)
159 info.version = version_info->file_version();
160 // Check if this is one of the child processes whose data we collected
161 // on the IO thread, and if so copy over that data.
162 for (size_t child = 0; child < child_info.size(); child++) {
163 if (child_info[child].pid != info.pid)
164 continue;
165 info.titles = child_info[child].titles;
166 info.type = child_info[child].type;
167 break;
168 }
169 } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH - 1)) {
170 std::wstring str_name(name);
171 scoped_ptr<FileVersionInfo> version_info(
172 FileVersionInfo::CreateFileVersionInfo(str_name));
173 if (version_info != NULL) {
174 info.version = version_info->product_version();
175 info.product_name = version_info->product_name();
176 }
177 }
178
179 // Add the process info to our list.
180 process_data_[index2].processes.push_back(info);
181 break;
182 }
183 } while (::Process32Next(snapshot, &process_entry));
184
185 // Finally return to the browser thread.
186 ui_loop_->PostTask(FROM_HERE,
187 NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnUIThread));
188 }
189
190 void MemoryDetails::CollectChildInfoOnUIThread() { 73 void MemoryDetails::CollectChildInfoOnUIThread() {
191 DCHECK(MessageLoop::current() == ui_loop_); 74 DCHECK(MessageLoop::current() == ui_loop_);
192 75
76 #if defined(OS_LINUX)
77 const pid_t zygote_pid = Singleton<ZygoteHost>()->pid();
78 const pid_t sandbox_helper_pid = Singleton<RenderSandboxHostLinux>()->pid();
79 #endif
80
81 ProcessData* const chrome_browser = ChromeBrowser();
193 // Get more information about the process. 82 // Get more information about the process.
194 for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size(); 83 for (size_t index = 0; index < chrome_browser->processes.size();
195 index++) { 84 index++) {
196 // Check if it's a renderer, if so get the list of page titles in it and 85 // Check if it's a renderer, if so get the list of page titles in it and
197 // check if it's a diagnostics-related process. We skip all diagnostics 86 // check if it's a diagnostics-related process. We skip all diagnostics
198 // pages (e.g. "about:xxx" URLs). Iterate the RenderProcessHosts to find 87 // pages (e.g. "about:xxx" URLs). Iterate the RenderProcessHosts to find
199 // the tab contents. 88 // the tab contents.
200 RenderProcessHost::iterator renderer_iter( 89 RenderProcessHost::iterator renderer_iter(
201 RenderProcessHost::AllHostsIterator()); 90 RenderProcessHost::AllHostsIterator());
91 ProcessMemoryInformation& process =
92 chrome_browser->processes[index];
93
202 for (; !renderer_iter.IsAtEnd(); renderer_iter.Advance()) { 94 for (; !renderer_iter.IsAtEnd(); renderer_iter.Advance()) {
203 DCHECK(renderer_iter.GetCurrentValue()); 95 DCHECK(renderer_iter.GetCurrentValue());
204 ProcessMemoryInformation& process =
205 process_data_[CHROME_BROWSER].processes[index];
206 if (process.pid != renderer_iter.GetCurrentValue()->process().pid()) 96 if (process.pid != renderer_iter.GetCurrentValue()->process().pid())
207 continue; 97 continue;
208 process.type = ChildProcessInfo::RENDER_PROCESS; 98 process.type = ChildProcessInfo::RENDER_PROCESS;
209 // The RenderProcessHost may host multiple TabContents. Any 99 // The RenderProcessHost may host multiple TabContents. Any
210 // of them which contain diagnostics information make the whole 100 // of them which contain diagnostics information make the whole
211 // process be considered a diagnostics process. 101 // process be considered a diagnostics process.
212 // 102 //
213 // NOTE: This is a bit dangerous. We know that for now, listeners 103 // NOTE: This is a bit dangerous. We know that for now, listeners
214 // are always RenderWidgetHosts. But in theory, they don't 104 // are always RenderWidgetHosts. But in theory, they don't
215 // have to be. 105 // have to be.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 contents->controller().GetLastCommittedEntry(); 140 contents->controller().GetLastCommittedEntry();
251 if ((last_committed_entry && 141 if ((last_committed_entry &&
252 LowerCaseEqualsASCII(last_committed_entry->virtual_url().spec(), 142 LowerCaseEqualsASCII(last_committed_entry->virtual_url().spec(),
253 chrome::kAboutMemoryURL)) || 143 chrome::kAboutMemoryURL)) ||
254 (pending_entry && 144 (pending_entry &&
255 LowerCaseEqualsASCII(pending_entry->virtual_url().spec(), 145 LowerCaseEqualsASCII(pending_entry->virtual_url().spec(),
256 chrome::kAboutMemoryURL))) 146 chrome::kAboutMemoryURL)))
257 process.is_diagnostics = true; 147 process.is_diagnostics = true;
258 } 148 }
259 } 149 }
150
151 #if defined(OS_LINUX)
152 if (process.pid == zygote_pid) {
153 process.type = ChildProcessInfo::ZYGOTE_PROCESS;
154 } else if (process.pid == sandbox_helper_pid) {
155 process.type = ChildProcessInfo::SANDBOX_HELPER_PROCESS;
156 }
157 #endif
260 } 158 }
261 159
262 // Get rid of other Chrome processes that are from a different profile. 160 // Get rid of other Chrome processes that are from a different profile.
263 for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size(); 161 for (size_t index = 0; index < chrome_browser->processes.size();
264 index++) { 162 index++) {
265 if (process_data_[CHROME_BROWSER].processes[index].type == 163 if (chrome_browser->processes[index].type ==
266 ChildProcessInfo::UNKNOWN_PROCESS) { 164 ChildProcessInfo::UNKNOWN_PROCESS) {
267 process_data_[CHROME_BROWSER].processes.erase( 165 chrome_browser->processes.erase(
268 process_data_[CHROME_BROWSER].processes.begin() + index); 166 chrome_browser->processes.begin() + index);
269 index--; 167 index--;
270 } 168 }
271 } 169 }
272 170
273 UpdateHistograms(); 171 UpdateHistograms();
274 172
275 OnDetailsAvailable(); 173 OnDetailsAvailable();
276 } 174 }
277 175
278 void MemoryDetails::UpdateHistograms() { 176 void MemoryDetails::UpdateHistograms() {
279 // Reports a set of memory metrics to UMA. 177 // Reports a set of memory metrics to UMA.
280 // Memory is measured in KB. 178 // Memory is measured in KB.
281 179
282 ProcessData browser = process_data_[CHROME_BROWSER]; 180 const ProcessData& browser = *ChromeBrowser();
283 size_t aggregate_memory = 0; 181 size_t aggregate_memory = 0;
284 int plugin_count = 0; 182 int plugin_count = 0;
285 int worker_count = 0; 183 int worker_count = 0;
286 for (size_t index = 0; index < browser.processes.size(); index++) { 184 for (size_t index = 0; index < browser.processes.size(); index++) {
287 int sample = static_cast<int>(browser.processes[index].working_set.priv); 185 int sample = static_cast<int>(browser.processes[index].working_set.priv);
288 aggregate_memory += sample; 186 aggregate_memory += sample;
289 switch (browser.processes[index].type) { 187 switch (browser.processes[index].type) {
290 case ChildProcessInfo::BROWSER_PROCESS: 188 case ChildProcessInfo::BROWSER_PROCESS:
291 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); 189 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample);
292 break; 190 break;
293 case ChildProcessInfo::RENDER_PROCESS: 191 case ChildProcessInfo::RENDER_PROCESS:
294 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); 192 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample);
295 break; 193 break;
296 case ChildProcessInfo::PLUGIN_PROCESS: 194 case ChildProcessInfo::PLUGIN_PROCESS:
297 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); 195 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample);
298 plugin_count++; 196 plugin_count++;
299 break; 197 break;
300 case ChildProcessInfo::WORKER_PROCESS: 198 case ChildProcessInfo::WORKER_PROCESS:
301 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample); 199 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample);
302 worker_count++; 200 worker_count++;
303 break; 201 break;
202 case ChildProcessInfo::ZYGOTE_PROCESS;
203 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample);
204 break;
205 case ChildProcessInfo::SANDBOX_HELPER_PROCESS;
206 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample);
207 break;
208 default:
209 NOTREACHED();
304 } 210 }
305 } 211 }
306 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", 212 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore",
307 BackingStoreManager::MemorySize() / 1024); 213 BackingStoreManager::MemorySize() / 1024);
308 214
309 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", 215 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
310 static_cast<int>(browser.processes.size())); 216 static_cast<int>(browser.processes.size()));
311 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); 217 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count);
312 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); 218 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count);
313 219
314 int total_sample = static_cast<int>(aggregate_memory / 1000); 220 int total_sample = static_cast<int>(aggregate_memory / 1000);
315 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); 221 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample);
316 } 222 }
OLDNEW
« no previous file with comments | « chrome/browser/memory_details.h ('k') | chrome/browser/memory_details_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698