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

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

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

Powered by Google App Engine
This is Rietveld 408576698