blob: 7d8c3c98c85968c3684e8102b07fc20f3f48f609 [file] [log] [blame]
[email protected]b0b67cf2012-01-18 21:59:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/browser/memory_details.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]24d69692011-10-21 18:26:517#include "base/bind.h"
initial.commit09911bf2008-07-26 23:55:298#include "base/file_version_info.h"
[email protected]835d7c82010-10-14 04:38:389#include "base/metrics/histogram.h"
[email protected]f9b294362013-06-10 20:22:3110#include "base/strings/string_util.h"
11#include "base/strings/stringprintf.h"
[email protected]112158af2013-06-07 23:46:1812#include "base/strings/utf_string_conversions.h"
[email protected]79dc42cd2011-01-08 21:43:3513#include "chrome/browser/profiles/profile.h"
[email protected]cd3d7892009-03-04 23:55:0614#include "chrome/common/url_constants.h"
[email protected]af39f002014-08-22 10:18:1815#include "chrome/grit/generated_resources.h"
[email protected]d5d383252013-07-04 14:44:3216#include "components/nacl/common/nacl_process_type.h"
[email protected]4967f792012-01-20 22:14:4017#include "content/public/browser/browser_child_process_host_iterator.h"
[email protected]c38831a12011-10-28 12:44:4918#include "content/public/browser/browser_thread.h"
[email protected]9c1662b2012-03-06 15:44:3319#include "content/public/browser/child_process_data.h"
[email protected]a53209b2012-01-20 16:48:1620#include "content/public/browser/navigation_controller.h"
[email protected]022af742011-12-28 18:37:2521#include "content/public/browser/navigation_entry.h"
[email protected]f3b1a082011-11-18 00:34:3022#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3323#include "content/public/browser/render_view_host.h"
[email protected]a801cb32013-09-11 18:02:2724#include "content/public/browser/render_widget_host_iterator.h"
[email protected]83ff91c2012-01-05 20:54:1325#include "content/public/browser/web_contents.h"
[email protected]e091df82011-10-11 18:13:2126#include "content/public/common/bindings_policy.h"
[email protected]c051a1b2011-01-21 23:30:1727#include "ui/base/l10n/l10n_util.h"
initial.commit09911bf2008-07-26 23:55:2928
[email protected]a423c9e2012-03-06 18:02:3129#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]c2c68b1f2012-02-25 00:29:1530#include "content/public/browser/zygote_host_linux.h"
[email protected]54fd1d32009-09-01 00:12:5831#endif
initial.commit09911bf2008-07-26 23:55:2932
[email protected]ddef62e2014-07-12 06:18:5733#if defined(ENABLE_EXTENSIONS)
34#include "chrome/browser/extensions/extension_service.h"
35#include "extensions/browser/extension_system.h"
36#include "extensions/browser/process_manager.h"
37#include "extensions/browser/process_map.h"
38#include "extensions/browser/view_type_utils.h"
39#include "extensions/common/extension.h"
40#endif
41
[email protected]4306df72012-04-20 18:58:5742using base::StringPrintf;
[email protected]4967f792012-01-20 22:14:4043using content::BrowserChildProcessHostIterator;
[email protected]631bb742011-11-02 11:29:3944using content::BrowserThread;
[email protected]10f417c52011-12-28 21:04:2345using content::NavigationEntry;
[email protected]eaabba22012-03-07 15:02:1146using content::RenderViewHost;
47using content::RenderWidgetHost;
[email protected]83ff91c2012-01-05 20:54:1348using content::WebContents;
[email protected]ddef62e2014-07-12 06:18:5749#if defined(ENABLE_EXTENSIONS)
[email protected]1c321ee2012-05-21 03:02:3450using extensions::Extension;
[email protected]ddef62e2014-07-12 06:18:5751#endif
[email protected]631bb742011-11-02 11:29:3952
[email protected]2c1978a2011-11-29 17:02:3953// static
54std::string ProcessMemoryInformation::GetRendererTypeNameInEnglish(
55 RendererProcessType type) {
56 switch (type) {
57 case RENDERER_NORMAL:
58 return "Tab";
59 case RENDERER_CHROME:
60 return "Tab (Chrome)";
61 case RENDERER_EXTENSION:
62 return "Extension";
63 case RENDERER_DEVTOOLS:
64 return "Devtools";
65 case RENDERER_INTERSTITIAL:
66 return "Interstitial";
[email protected]2c1978a2011-11-29 17:02:3967 case RENDERER_BACKGROUND_APP:
68 return "Background App";
69 case RENDERER_UNKNOWN:
70 default:
71 NOTREACHED() << "Unknown renderer process type!";
72 return "Unknown";
73 }
74}
75
76// static
77std::string ProcessMemoryInformation::GetFullTypeNameInEnglish(
[email protected]f3b357692013-03-22 05:16:1378 int process_type,
[email protected]2c1978a2011-11-29 17:02:3979 RendererProcessType rtype) {
[email protected]f3b357692013-03-22 05:16:1380 if (process_type == content::PROCESS_TYPE_RENDERER)
[email protected]2c1978a2011-11-29 17:02:3981 return GetRendererTypeNameInEnglish(rtype);
[email protected]f3b357692013-03-22 05:16:1382 return content::GetProcessTypeNameInEnglish(process_type);
[email protected]2c1978a2011-11-29 17:02:3983}
84
[email protected]8e383412010-10-19 16:57:0385ProcessMemoryInformation::ProcessMemoryInformation()
86 : pid(0),
87 num_processes(0),
88 is_diagnostics(false),
[email protected]f3b357692013-03-22 05:16:1389 process_type(content::PROCESS_TYPE_UNKNOWN),
[email protected]2c1978a2011-11-29 17:02:3990 renderer_type(RENDERER_UNKNOWN) {
[email protected]8e383412010-10-19 16:57:0391}
92
93ProcessMemoryInformation::~ProcessMemoryInformation() {}
94
[email protected]8e23c882012-05-05 01:14:1195bool ProcessMemoryInformation::operator<(
96 const ProcessMemoryInformation& rhs) const {
97 return working_set.priv < rhs.working_set.priv;
98}
99
[email protected]93aa89c72010-10-20 21:32:04100ProcessData::ProcessData() {}
101
102ProcessData::ProcessData(const ProcessData& rhs)
103 : name(rhs.name),
104 process_name(rhs.process_name),
105 processes(rhs.processes) {
106}
107
108ProcessData::~ProcessData() {}
109
110ProcessData& ProcessData::operator=(const ProcessData& rhs) {
111 name = rhs.name;
112 process_name = rhs.process_name;
113 processes = rhs.processes;
114 return *this;
115}
116
[email protected]8a5b2da2014-07-07 10:56:51117MemoryGrowthTracker::MemoryGrowthTracker() {}
118
119MemoryGrowthTracker::~MemoryGrowthTracker() {}
120
121bool MemoryGrowthTracker::UpdateSample(
122 base::ProcessId pid,
123 int sample,
124 int* diff) {
125 // |sample| is memory usage in kB.
126 const base::TimeTicks current_time = base::TimeTicks::Now();
127 std::map<base::ProcessId, int>::iterator found_size = memory_sizes_.find(pid);
128 if (found_size != memory_sizes_.end()) {
129 const int last_size = found_size->second;
130 std::map<base::ProcessId, base::TimeTicks>::iterator found_time =
131 times_.find(pid);
132 const base::TimeTicks last_time = found_time->second;
133 if (last_time < (current_time - base::TimeDelta::FromMinutes(30))) {
134 // Note that it is undefined how division of a negative integer gets
135 // rounded. |*diff| may have a difference of 1 from the correct number
136 // if |sample| < |last_size|. We ignore it as 1 is small enough.
137 *diff = ((sample - last_size) * 30 /
138 (current_time - last_time).InMinutes());
139 found_size->second = sample;
140 found_time->second = current_time;
141 return true;
142 }
143 // Skip if a last record is found less than 30 minutes ago.
144 } else {
145 // Not reporting if it's the first record for |pid|.
146 times_[pid] = current_time;
147 memory_sizes_[pid] = sample;
148 }
149 return false;
150}
151
initial.commit09911bf2008-07-26 23:55:29152// About threading:
153//
154// This operation will hit no fewer than 3 threads.
155//
[email protected]8be45842012-04-13 19:49:29156// The BrowserChildProcessHostIterator can only be accessed from the IO thread.
initial.commit09911bf2008-07-26 23:55:29157//
158// The RenderProcessHostIterator can only be accessed from the UI thread.
159//
160// This operation can take 30-100ms to complete. We never want to have
161// one task run for that long on the UI or IO threads. So, we run the
162// expensive parts of this operation over on the file thread.
163//
[email protected]4306df72012-04-20 18:58:57164void MemoryDetails::StartFetch(UserMetricsMode user_metrics_mode) {
[email protected]9bb480ee2011-08-03 21:41:16165 // This might get called from the UI or FILE threads, but should not be
166 // getting called from the IO thread.
[email protected]f8b3ef82010-10-11 02:45:52167 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4306df72012-04-20 18:58:57168 user_metrics_mode_ = user_metrics_mode;
initial.commit09911bf2008-07-26 23:55:29169
170 // In order to process this request, we need to use the plugin information.
171 // However, plugin process information is only available from the IO thread.
[email protected]f8b3ef82010-10-11 02:45:52172 BrowserThread::PostTask(
173 BrowserThread::IO, FROM_HERE,
[email protected]24d69692011-10-21 18:26:51174 base::Bind(&MemoryDetails::CollectChildInfoOnIOThread, this));
initial.commit09911bf2008-07-26 23:55:29175}
176
[email protected]8e383412010-10-19 16:57:03177MemoryDetails::~MemoryDetails() {}
178
[email protected]4306df72012-04-20 18:58:57179std::string MemoryDetails::ToLogString() {
180 std::string log;
181 log.reserve(4096);
[email protected]8e23c882012-05-05 01:14:11182 ProcessMemoryInformationList processes = ChromeBrowser()->processes;
183 // Sort by memory consumption, low to high.
184 std::sort(processes.begin(), processes.end());
185 // Print from high to low.
186 for (ProcessMemoryInformationList::reverse_iterator iter1 =
187 processes.rbegin();
188 iter1 != processes.rend();
189 ++iter1) {
[email protected]4306df72012-04-20 18:58:57190 log += ProcessMemoryInformation::GetFullTypeNameInEnglish(
[email protected]f3b357692013-03-22 05:16:13191 iter1->process_type, iter1->renderer_type);
[email protected]4306df72012-04-20 18:58:57192 if (!iter1->titles.empty()) {
193 log += " [";
[email protected]d2065e062013-12-12 23:49:52194 for (std::vector<base::string16>::const_iterator iter2 =
[email protected]4306df72012-04-20 18:58:57195 iter1->titles.begin();
196 iter2 != iter1->titles.end(); ++iter2) {
197 if (iter2 != iter1->titles.begin())
198 log += "|";
[email protected]6778fed2013-12-24 20:09:37199 log += base::UTF16ToUTF8(*iter2);
[email protected]4306df72012-04-20 18:58:57200 }
201 log += "]";
202 }
[email protected]aa1255b2013-07-31 22:03:09203 log += StringPrintf(" %d MB private, %d MB shared",
[email protected]4306df72012-04-20 18:58:57204 static_cast<int>(iter1->working_set.priv) / 1024,
205 static_cast<int>(iter1->working_set.shared) / 1024);
[email protected]aa1255b2013-07-31 22:03:09206#if defined(OS_CHROMEOS)
207 log += StringPrintf(", %d MB swapped",
208 static_cast<int>(iter1->working_set.swapped) / 1024);
209#endif
210 log += "\n";
[email protected]4306df72012-04-20 18:58:57211 }
212 return log;
213}
214
[email protected]8a5b2da2014-07-07 10:56:51215void MemoryDetails::SetMemoryGrowthTracker(
216 MemoryGrowthTracker* memory_growth_tracker) {
217 memory_growth_tracker_ = memory_growth_tracker;
218}
219
[email protected]a27a9382009-02-11 23:55:10220void MemoryDetails::CollectChildInfoOnIOThread() {
[email protected]f8b3ef82010-10-11 02:45:52221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
initial.commit09911bf2008-07-26 23:55:29222
[email protected]a27a9382009-02-11 23:55:10223 std::vector<ProcessMemoryInformation> child_info;
224
[email protected]82a14c12012-11-13 18:40:55225 // Collect the list of child processes. A 0 |handle| means that
226 // the process is being launched, so we skip it.
[email protected]4967f792012-01-20 22:14:40227 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]a27a9382009-02-11 23:55:10228 ProcessMemoryInformation info;
[email protected]82a14c12012-11-13 18:40:55229 if (!iter.GetData().handle)
230 continue;
[email protected]4967f792012-01-20 22:14:40231 info.pid = base::GetProcId(iter.GetData().handle);
[email protected]a27a9382009-02-11 23:55:10232 if (!info.pid)
233 continue;
234
[email protected]f3b357692013-03-22 05:16:13235 info.process_type = iter.GetData().process_type;
[email protected]2c1978a2011-11-29 17:02:39236 info.renderer_type = ProcessMemoryInformation::RENDERER_UNKNOWN;
[email protected]4967f792012-01-20 22:14:40237 info.titles.push_back(iter.GetData().name);
[email protected]a27a9382009-02-11 23:55:10238 child_info.push_back(info);
initial.commit09911bf2008-07-26 23:55:29239 }
240
241 // Now go do expensive memory lookups from the file thread.
[email protected]f8b3ef82010-10-11 02:45:52242 BrowserThread::PostTask(
243 BrowserThread::FILE, FROM_HERE,
[email protected]24d69692011-10-21 18:26:51244 base::Bind(&MemoryDetails::CollectProcessData, this, child_info));
initial.commit09911bf2008-07-26 23:55:29245}
246
[email protected]a27a9382009-02-11 23:55:10247void MemoryDetails::CollectChildInfoOnUIThread() {
[email protected]f8b3ef82010-10-11 02:45:52248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29249
[email protected]a423c9e2012-03-06 18:02:31250#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]c2c68b1f2012-02-25 00:29:15251 const pid_t zygote_pid = content::ZygoteHost::GetInstance()->GetPid();
[email protected]54fd1d32009-09-01 00:12:58252#endif
253
254 ProcessData* const chrome_browser = ChromeBrowser();
[email protected]a27a9382009-02-11 23:55:10255 // Get more information about the process.
[email protected]54fd1d32009-09-01 00:12:58256 for (size_t index = 0; index < chrome_browser->processes.size();
initial.commit09911bf2008-07-26 23:55:29257 index++) {
[email protected]a27a9382009-02-11 23:55:10258 // Check if it's a renderer, if so get the list of page titles in it and
[email protected]fcf79352010-12-28 20:13:20259 // check if it's a diagnostics-related process. We skip about:memory pages.
260 // Iterate the RenderProcessHosts to find the tab contents.
[email protected]54fd1d32009-09-01 00:12:58261 ProcessMemoryInformation& process =
262 chrome_browser->processes[index];
263
[email protected]a801cb32013-09-11 18:02:27264 scoped_ptr<content::RenderWidgetHostIterator> widgets(
265 RenderWidgetHost::GetRenderWidgetHosts());
266 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
[email protected]f3b1a082011-11-18 00:34:30267 content::RenderProcessHost* render_process_host =
[email protected]a801cb32013-09-11 18:02:27268 widget->GetProcess();
[email protected]fcf79352010-12-28 20:13:20269 DCHECK(render_process_host);
[email protected]8a34e6602010-10-02 17:29:43270 // Ignore processes that don't have a connection, such as crashed tabs.
[email protected]fcf79352010-12-28 20:13:20271 if (!render_process_host->HasConnection() ||
272 process.pid != base::GetProcId(render_process_host->GetHandle())) {
[email protected]a27a9382009-02-11 23:55:10273 continue;
[email protected]201b2732009-11-13 18:57:46274 }
[email protected]79dc42cd2011-01-08 21:43:35275
[email protected]0932b30c2012-04-17 13:25:10276 // The RenderProcessHost may host multiple WebContentses. Any
[email protected]a27a9382009-02-11 23:55:10277 // of them which contain diagnostics information make the whole
278 // process be considered a diagnostics process.
[email protected]a801cb32013-09-11 18:02:27279 if (!widget->IsRenderView())
[email protected]039b84a42013-06-21 20:23:37280 continue;
initial.commit09911bf2008-07-26 23:55:29281
[email protected]ddef62e2014-07-12 06:18:57282 process.process_type = content::PROCESS_TYPE_RENDERER;
283 bool is_extension = false;
[email protected]a801cb32013-09-11 18:02:27284 RenderViewHost* host = RenderViewHost::From(widget);
[email protected]ddef62e2014-07-12 06:18:57285#if defined(ENABLE_EXTENSIONS)
286 content::BrowserContext* context =
287 render_process_host->GetBrowserContext();
288 ExtensionService* extension_service =
289 extensions::ExtensionSystem::Get(context)->extension_service();
290 extensions::ProcessMap* extension_process_map =
291 extensions::ProcessMap::Get(context);
292 is_extension = extension_process_map->Contains(
293 host->GetProcess()->GetID());
294#endif
295
[email protected]039b84a42013-06-21 20:23:37296 WebContents* contents = WebContents::FromRenderViewHost(host);
297 GURL url;
298 if (contents) {
299 url = contents->GetURL();
300 SiteData* site_data =
301 &chrome_browser->site_data[contents->GetBrowserContext()];
302 SiteDetails::CollectSiteInfo(contents, site_data);
303 }
[email protected]ddef62e2014-07-12 06:18:57304#if defined(ENABLE_EXTENSIONS)
[email protected]039b84a42013-06-21 20:23:37305 extensions::ViewType type = extensions::GetViewType(contents);
[email protected]ddef62e2014-07-12 06:18:57306#endif
[email protected]039b84a42013-06-21 20:23:37307 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) {
308 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME;
[email protected]ddef62e2014-07-12 06:18:57309 } else if (is_extension) {
310#if defined(ENABLE_EXTENSIONS)
[email protected]039b84a42013-06-21 20:23:37311 // For our purposes, don't count processes containing only hosted apps
312 // as extension processes. See also: crbug.com/102533.
313 std::set<std::string> extension_ids =
314 extension_process_map->GetExtensionsInProcess(
315 host->GetProcess()->GetID());
316 for (std::set<std::string>::iterator iter = extension_ids.begin();
317 iter != extension_ids.end(); ++iter) {
[email protected]299d7f12012-05-23 05:31:15318 const Extension* extension =
[email protected]039b84a42013-06-21 20:23:37319 extension_service->GetExtensionById(*iter, false);
320 if (extension && !extension->is_hosted_app()) {
[email protected]04d9cc402012-08-17 22:30:12321 process.renderer_type =
322 ProcessMemoryInformation::RENDERER_EXTENSION;
[email protected]039b84a42013-06-21 20:23:37323 break;
[email protected]fcf79352010-12-28 20:13:20324 }
[email protected]fcf79352010-12-28 20:13:20325 }
[email protected]ddef62e2014-07-12 06:18:57326#endif
[email protected]039b84a42013-06-21 20:23:37327 }
[email protected]ddef62e2014-07-12 06:18:57328#if defined(ENABLE_EXTENSIONS)
329 if (is_extension) {
[email protected]039b84a42013-06-21 20:23:37330 const Extension* extension =
331 extension_service->extensions()->GetByID(url.host());
332 if (extension) {
[email protected]6778fed2013-12-24 20:09:37333 base::string16 title = base::UTF8ToUTF16(extension->name());
[email protected]039b84a42013-06-21 20:23:37334 process.titles.push_back(title);
[email protected]299d7f12012-05-23 05:31:15335 process.renderer_type =
[email protected]039b84a42013-06-21 20:23:37336 ProcessMemoryInformation::RENDERER_EXTENSION;
[email protected]299d7f12012-05-23 05:31:15337 continue;
338 }
[email protected]039b84a42013-06-21 20:23:37339 }
[email protected]ddef62e2014-07-12 06:18:57340#endif
[email protected]299d7f12012-05-23 05:31:15341
[email protected]039b84a42013-06-21 20:23:37342 if (!contents) {
343 process.renderer_type =
344 ProcessMemoryInformation::RENDERER_INTERSTITIAL;
345 continue;
346 }
[email protected]299d7f12012-05-23 05:31:15347
[email protected]ddef62e2014-07-12 06:18:57348#if defined(ENABLE_EXTENSIONS)
[email protected]039b84a42013-06-21 20:23:37349 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) {
[email protected]6778fed2013-12-24 20:09:37350 process.titles.push_back(base::UTF8ToUTF16(url.spec()));
[email protected]039b84a42013-06-21 20:23:37351 process.renderer_type =
352 ProcessMemoryInformation::RENDERER_BACKGROUND_APP;
353 continue;
354 }
[email protected]ddef62e2014-07-12 06:18:57355#endif
[email protected]299d7f12012-05-23 05:31:15356
[email protected]039b84a42013-06-21 20:23:37357 // Since we have a WebContents and and the renderer type hasn't been
358 // set yet, it must be a normal tabbed renderer.
359 if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN)
360 process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL;
[email protected]cd3d7892009-03-04 23:55:06361
[email protected]0085863a2013-12-06 21:19:03362 base::string16 title = contents->GetTitle();
[email protected]039b84a42013-06-21 20:23:37363 if (!title.length())
364 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
365 process.titles.push_back(title);
366
367 // We need to check the pending entry as well as the virtual_url to
368 // see if it's a chrome://memory URL (we don't want to count these in
369 // the total memory usage of the browser).
370 //
371 // When we reach here, chrome://memory will be the pending entry since
372 // we haven't responded with any data such that it would be committed.
373 // If you have another chrome://memory tab open (which would be
374 // committed), we don't want to count it either, so we also check the
375 // last committed entry.
376 //
377 // Either the pending or last committed entries can be NULL.
378 const NavigationEntry* pending_entry =
379 contents->GetController().GetPendingEntry();
380 const NavigationEntry* last_committed_entry =
381 contents->GetController().GetLastCommittedEntry();
382 if ((last_committed_entry &&
[email protected]df807042014-08-13 16:48:41383 LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(),
384 chrome::kChromeUIMemoryURL)) ||
[email protected]039b84a42013-06-21 20:23:37385 (pending_entry &&
[email protected]df807042014-08-13 16:48:41386 LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(),
387 chrome::kChromeUIMemoryURL))) {
[email protected]039b84a42013-06-21 20:23:37388 process.is_diagnostics = true;
initial.commit09911bf2008-07-26 23:55:29389 }
390 }
[email protected]54fd1d32009-09-01 00:12:58391
[email protected]a423c9e2012-03-06 18:02:31392#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]54fd1d32009-09-01 00:12:58393 if (process.pid == zygote_pid) {
[email protected]f3b357692013-03-22 05:16:13394 process.process_type = content::PROCESS_TYPE_ZYGOTE;
[email protected]54fd1d32009-09-01 00:12:58395 }
396#endif
initial.commit09911bf2008-07-26 23:55:29397 }
398
[email protected]a27a9382009-02-11 23:55:10399 // Get rid of other Chrome processes that are from a different profile.
[email protected]54fd1d32009-09-01 00:12:58400 for (size_t index = 0; index < chrome_browser->processes.size();
[email protected]a27a9382009-02-11 23:55:10401 index++) {
[email protected]f3b357692013-03-22 05:16:13402 if (chrome_browser->processes[index].process_type ==
[email protected]bd5d6cf2011-12-01 00:39:12403 content::PROCESS_TYPE_UNKNOWN) {
[email protected]54fd1d32009-09-01 00:12:58404 chrome_browser->processes.erase(
405 chrome_browser->processes.begin() + index);
[email protected]a436d922009-02-13 23:16:42406 index--;
[email protected]a27a9382009-02-11 23:55:10407 }
408 }
409
[email protected]4306df72012-04-20 18:58:57410 if (user_metrics_mode_ == UPDATE_USER_METRICS)
411 UpdateHistograms();
initial.commit09911bf2008-07-26 23:55:29412
413 OnDetailsAvailable();
414}
415
416void MemoryDetails::UpdateHistograms() {
417 // Reports a set of memory metrics to UMA.
[email protected]57c4b852009-08-17 21:59:29418 // Memory is measured in KB.
initial.commit09911bf2008-07-26 23:55:29419
[email protected]54fd1d32009-09-01 00:12:58420 const ProcessData& browser = *ChromeBrowser();
initial.commit09911bf2008-07-26 23:55:29421 size_t aggregate_memory = 0;
[email protected]fcf79352010-12-28 20:13:20422 int chrome_count = 0;
423 int extension_count = 0;
[email protected]a27a9382009-02-11 23:55:10424 int plugin_count = 0;
[email protected]eef348fb2011-08-01 21:11:08425 int pepper_plugin_count = 0;
[email protected]3f5f5162012-10-17 09:19:40426 int pepper_plugin_broker_count = 0;
[email protected]fcf79352010-12-28 20:13:20427 int renderer_count = 0;
428 int other_count = 0;
[email protected]a27a9382009-02-11 23:55:10429 int worker_count = 0;
[email protected]1ae93fb12013-06-14 03:38:56430 int process_limit = content::RenderProcessHost::GetMaxRendererProcessCount();
initial.commit09911bf2008-07-26 23:55:29431 for (size_t index = 0; index < browser.processes.size(); index++) {
[email protected]921cd0cc2008-10-21 22:30:55432 int sample = static_cast<int>(browser.processes[index].working_set.priv);
433 aggregate_memory += sample;
[email protected]f3b357692013-03-22 05:16:13434 switch (browser.processes[index].process_type) {
[email protected]bd5d6cf2011-12-01 00:39:12435 case content::PROCESS_TYPE_BROWSER:
[email protected]f164cea2009-11-05 23:37:40436 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample);
[email protected]23deabb72013-07-16 21:55:20437 continue;
[email protected]bd5d6cf2011-12-01 00:39:12438 case content::PROCESS_TYPE_RENDERER: {
[email protected]2c1978a2011-11-29 17:02:39439 ProcessMemoryInformation::RendererProcessType renderer_type =
[email protected]fcf79352010-12-28 20:13:20440 browser.processes[index].renderer_type;
441 switch (renderer_type) {
[email protected]2c1978a2011-11-29 17:02:39442 case ProcessMemoryInformation::RENDERER_EXTENSION:
[email protected]fcf79352010-12-28 20:13:20443 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample);
444 extension_count++;
[email protected]23deabb72013-07-16 21:55:20445 continue;
[email protected]2c1978a2011-11-29 17:02:39446 case ProcessMemoryInformation::RENDERER_CHROME:
[email protected]fcf79352010-12-28 20:13:20447 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample);
448 chrome_count++;
[email protected]23deabb72013-07-16 21:55:20449 continue;
[email protected]2c1978a2011-11-29 17:02:39450 case ProcessMemoryInformation::RENDERER_UNKNOWN:
[email protected]fcf79352010-12-28 20:13:20451 NOTREACHED() << "Unknown renderer process type.";
[email protected]23deabb72013-07-16 21:55:20452 continue;
[email protected]2c1978a2011-11-29 17:02:39453 case ProcessMemoryInformation::RENDERER_NORMAL:
[email protected]fcf79352010-12-28 20:13:20454 default:
455 // TODO(erikkay): Should we bother splitting out the other subtypes?
456 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample);
[email protected]8a5b2da2014-07-07 10:56:51457 int diff;
458 if (memory_growth_tracker_ &&
459 memory_growth_tracker_->UpdateSample(
460 browser.processes[index].pid, sample, &diff)) {
461 if (diff < 0)
462 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff);
463 else
464 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff);
465 }
[email protected]fcf79352010-12-28 20:13:20466 renderer_count++;
[email protected]23deabb72013-07-16 21:55:20467 continue;
[email protected]fcf79352010-12-28 20:13:20468 }
[email protected]fcf79352010-12-28 20:13:20469 }
[email protected]bd5d6cf2011-12-01 00:39:12470 case content::PROCESS_TYPE_PLUGIN:
[email protected]f164cea2009-11-05 23:37:40471 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample);
472 plugin_count++;
[email protected]23deabb72013-07-16 21:55:20473 continue;
[email protected]bd5d6cf2011-12-01 00:39:12474 case content::PROCESS_TYPE_UTILITY:
[email protected]f164cea2009-11-05 23:37:40475 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample);
[email protected]fcf79352010-12-28 20:13:20476 other_count++;
[email protected]23deabb72013-07-16 21:55:20477 continue;
[email protected]bd5d6cf2011-12-01 00:39:12478 case content::PROCESS_TYPE_ZYGOTE:
[email protected]f164cea2009-11-05 23:37:40479 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample);
[email protected]fcf79352010-12-28 20:13:20480 other_count++;
[email protected]23deabb72013-07-16 21:55:20481 continue;
[email protected]bd5d6cf2011-12-01 00:39:12482 case content::PROCESS_TYPE_SANDBOX_HELPER:
[email protected]f164cea2009-11-05 23:37:40483 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample);
[email protected]fcf79352010-12-28 20:13:20484 other_count++;
[email protected]23deabb72013-07-16 21:55:20485 continue;
[email protected]bd5d6cf2011-12-01 00:39:12486 case content::PROCESS_TYPE_GPU:
[email protected]96fcbf2d2010-08-03 16:10:27487 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample);
[email protected]fcf79352010-12-28 20:13:20488 other_count++;
[email protected]23deabb72013-07-16 21:55:20489 continue;
[email protected]bd5d6cf2011-12-01 00:39:12490 case content::PROCESS_TYPE_PPAPI_PLUGIN:
[email protected]eef348fb2011-08-01 21:11:08491 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample);
492 pepper_plugin_count++;
[email protected]23deabb72013-07-16 21:55:20493 continue;
[email protected]3f5f5162012-10-17 09:19:40494 case content::PROCESS_TYPE_PPAPI_BROKER:
495 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample);
496 pepper_plugin_broker_count++;
[email protected]23deabb72013-07-16 21:55:20497 continue;
[email protected]f3b357692013-03-22 05:16:13498 case PROCESS_TYPE_NACL_LOADER:
499 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample);
500 other_count++;
[email protected]23deabb72013-07-16 21:55:20501 continue;
[email protected]f3b357692013-03-22 05:16:13502 case PROCESS_TYPE_NACL_BROKER:
503 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample);
504 other_count++;
[email protected]23deabb72013-07-16 21:55:20505 continue;
[email protected]f164cea2009-11-05 23:37:40506 default:
507 NOTREACHED();
[email protected]23deabb72013-07-16 21:55:20508 continue;
initial.commit09911bf2008-07-26 23:55:29509 }
510 }
[email protected]dc0b5bd2012-12-11 21:24:39511#if defined(OS_CHROMEOS)
512 // Chrome OS exposes system-wide graphics driver memory which has historically
513 // been a source of leak/bloat.
514 base::SystemMemoryInfoKB meminfo;
515 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1)
516 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024);
517#endif
[email protected]a27a9382009-02-11 23:55:10518
[email protected]1ae93fb12013-06-14 03:38:56519 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit);
[email protected]553dba62009-02-24 19:08:23520 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
initial.commit09911bf2008-07-26 23:55:29521 static_cast<int>(browser.processes.size()));
[email protected]fcf79352010-12-28 20:13:20522 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count);
523 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count);
524 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count);
[email protected]553dba62009-02-24 19:08:23525 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count);
[email protected]eef348fb2011-08-01 21:11:08526 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount",
527 pepper_plugin_count);
[email protected]3f5f5162012-10-17 09:19:40528 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount",
529 pepper_plugin_broker_count);
[email protected]fcf79352010-12-28 20:13:20530 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count);
[email protected]553dba62009-02-24 19:08:23531 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count);
[email protected]f164cea2009-11-05 23:37:40532 // TODO(viettrungluu): Do we want separate counts for the other
533 // (platform-specific) process types?
[email protected]921cd0cc2008-10-21 22:30:55534
535 int total_sample = static_cast<int>(aggregate_memory / 1000);
[email protected]553dba62009-02-24 19:08:23536 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample);
[email protected]1ae93fb12013-06-14 03:38:56537
[email protected]23deabb72013-07-16 21:55:20538#if defined(OS_CHROMEOS)
539 UpdateSwapHistograms();
540#endif
initial.commit09911bf2008-07-26 23:55:29541}
[email protected]23deabb72013-07-16 21:55:20542
543#if defined(OS_CHROMEOS)
544void MemoryDetails::UpdateSwapHistograms() {
[email protected]f4134782013-08-29 21:25:20545 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info_.num_writes > 0);
546 if (swap_info_.num_writes == 0)
[email protected]48e303442013-07-18 19:13:15547 return;
548
549 // Only record swap info when any swaps have happened, to give us more
550 // detail in the histograms.
[email protected]23deabb72013-07-16 21:55:20551 const ProcessData& browser = *ChromeBrowser();
552 size_t aggregate_memory = 0;
553 for (size_t index = 0; index < browser.processes.size(); index++) {
554 int sample = static_cast<int>(browser.processes[index].working_set.swapped);
555 aggregate_memory += sample;
556 switch (browser.processes[index].process_type) {
557 case content::PROCESS_TYPE_BROWSER:
558 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample);
559 continue;
560 case content::PROCESS_TYPE_RENDERER: {
561 ProcessMemoryInformation::RendererProcessType renderer_type =
562 browser.processes[index].renderer_type;
563 switch (renderer_type) {
564 case ProcessMemoryInformation::RENDERER_EXTENSION:
565 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample);
566 continue;
567 case ProcessMemoryInformation::RENDERER_CHROME:
568 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample);
569 continue;
570 case ProcessMemoryInformation::RENDERER_UNKNOWN:
571 NOTREACHED() << "Unknown renderer process type.";
572 continue;
573 case ProcessMemoryInformation::RENDERER_NORMAL:
574 default:
575 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample);
576 continue;
577 }
578 }
579 case content::PROCESS_TYPE_PLUGIN:
580 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample);
581 continue;
[email protected]23deabb72013-07-16 21:55:20582 case content::PROCESS_TYPE_UTILITY:
583 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample);
584 continue;
585 case content::PROCESS_TYPE_ZYGOTE:
586 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample);
587 continue;
588 case content::PROCESS_TYPE_SANDBOX_HELPER:
589 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample);
590 continue;
591 case content::PROCESS_TYPE_GPU:
592 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample);
593 continue;
594 case content::PROCESS_TYPE_PPAPI_PLUGIN:
595 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample);
596 continue;
597 case content::PROCESS_TYPE_PPAPI_BROKER:
598 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample);
599 continue;
600 case PROCESS_TYPE_NACL_LOADER:
601 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample);
602 continue;
603 case PROCESS_TYPE_NACL_BROKER:
604 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample);
605 continue;
606 default:
607 NOTREACHED();
608 continue;
609 }
610 }
611
612 int total_sample = static_cast<int>(aggregate_memory / 1000);
613 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample);
[email protected]48e303442013-07-18 19:13:15614
615 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
[email protected]f4134782013-08-29 21:25:20616 swap_info_.compr_data_size / (1024 * 1024),
[email protected]48e303442013-07-18 19:13:15617 1, 4096, 50);
618 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
[email protected]f4134782013-08-29 21:25:20619 swap_info_.orig_data_size / (1024 * 1024),
[email protected]48e303442013-07-18 19:13:15620 1, 4096, 50);
621 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
[email protected]f4134782013-08-29 21:25:20622 swap_info_.mem_used_total / (1024 * 1024),
[email protected]48e303442013-07-18 19:13:15623 1, 4096, 50);
[email protected]aa1255b2013-07-31 22:03:09624 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads",
[email protected]f4134782013-08-29 21:25:20625 swap_info_.num_reads,
[email protected]aa1255b2013-07-31 22:03:09626 1, 100000000, 100);
627 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites",
[email protected]f4134782013-08-29 21:25:20628 swap_info_.num_writes,
[email protected]aa1255b2013-07-31 22:03:09629 1, 100000000, 100);
[email protected]48e303442013-07-18 19:13:15630
[email protected]f4134782013-08-29 21:25:20631 if (swap_info_.orig_data_size > 0 && swap_info_.compr_data_size > 0) {
[email protected]48e303442013-07-18 19:13:15632 UMA_HISTOGRAM_CUSTOM_COUNTS(
633 "Memory.Swap.CompressionRatio",
[email protected]f4134782013-08-29 21:25:20634 swap_info_.orig_data_size / swap_info_.compr_data_size,
[email protected]48e303442013-07-18 19:13:15635 1, 20, 20);
636 }
[email protected]23deabb72013-07-16 21:55:20637}
638
639#endif