Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / memory_details_linux.cc
blob3da6ec76d217d44ef8310cd829e16ff24b2a0cdd
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/memory_details.h"
7 #include <sys/types.h>
8 #include <unistd.h>
10 #include <map>
11 #include <set>
13 #include "base/bind.h"
14 #include "base/file_util.h"
15 #include "base/process/process_iterator.h"
16 #include "base/process/process_metrics.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/process_type.h"
23 #include "grit/chromium_strings.h"
24 #include "ui/base/l10n/l10n_util.h"
26 using base::ProcessEntry;
27 using content::BrowserThread;
29 // Known browsers which we collect details for.
30 enum BrowserType {
31 CHROME = 0,
32 FIREFOX,
33 ICEWEASEL,
34 OPERA,
35 KONQUEROR,
36 EPIPHANY,
37 MIDORI,
38 MAX_BROWSERS
39 } BrowserProcess;
41 // The pretty printed names of those browsers. Matches up with enum
42 // BrowserType.
43 static const char kBrowserPrettyNames[][10] = {
44 "Chrome",
45 "Firefox",
46 "Iceweasel",
47 "Opera",
48 "Konqueror",
49 "Epiphany",
50 "Midori",
53 // A mapping from process name to the type of browser.
54 static const struct {
55 const char process_name[16];
56 BrowserType browser;
57 } kBrowserBinaryNames[] = {
58 { "firefox", FIREFOX },
59 { "firefox-3.5", FIREFOX },
60 { "firefox-3.0", FIREFOX },
61 { "firefox-bin", FIREFOX },
62 { "iceweasel", ICEWEASEL },
63 { "opera", OPERA },
64 { "konqueror", KONQUEROR },
65 { "epiphany-browse", EPIPHANY },
66 { "epiphany", EPIPHANY },
67 { "midori", MIDORI },
68 { "", MAX_BROWSERS },
71 MemoryDetails::MemoryDetails()
72 : user_metrics_mode_(UPDATE_USER_METRICS) {
75 ProcessData* MemoryDetails::ChromeBrowser() {
76 return &process_data_[0];
79 struct Process {
80 pid_t pid;
81 pid_t parent;
82 std::string name;
85 typedef std::map<pid_t, Process> ProcessMap;
87 // Get information on all the processes running on the system.
88 static ProcessMap GetProcesses() {
89 ProcessMap map;
91 base::ProcessIterator process_iter(NULL);
92 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
93 Process process;
94 process.pid = process_entry->pid();
95 process.parent = process_entry->parent_pid();
96 process.name = process_entry->exe_file();
97 map.insert(std::make_pair(process.pid, process));
99 return map;
102 // Given a process name, return the type of the browser which created that
103 // process, or |MAX_BROWSERS| if we don't know about it.
104 static BrowserType GetBrowserType(const std::string& process_name) {
105 for (unsigned i = 0; kBrowserBinaryNames[i].process_name[0]; ++i) {
106 if (strcmp(process_name.c_str(), kBrowserBinaryNames[i].process_name) == 0)
107 return kBrowserBinaryNames[i].browser;
110 return MAX_BROWSERS;
113 // For each of a list of pids, collect memory information about that process.
114 static ProcessData GetProcessDataMemoryInformation(
115 const std::vector<pid_t>& pids) {
116 ProcessData process_data;
117 for (std::vector<pid_t>::const_iterator iter = pids.begin();
118 iter != pids.end();
119 ++iter) {
120 ProcessMemoryInformation pmi;
122 pmi.pid = *iter;
123 pmi.num_processes = 1;
125 if (pmi.pid == base::GetCurrentProcId())
126 pmi.process_type = content::PROCESS_TYPE_BROWSER;
127 else
128 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
130 base::ProcessMetrics* metrics =
131 base::ProcessMetrics::CreateProcessMetrics(*iter);
132 metrics->GetWorkingSetKBytes(&pmi.working_set);
133 delete metrics;
135 process_data.processes.push_back(pmi);
137 return process_data;
140 // Find all children of the given process with pid |root|.
141 static std::vector<pid_t> GetAllChildren(const ProcessMap& processes,
142 const pid_t root) {
143 std::vector<pid_t> children;
144 children.push_back(root);
146 std::set<pid_t> wavefront, next_wavefront;
147 wavefront.insert(root);
149 while (wavefront.size()) {
150 for (ProcessMap::const_iterator iter = processes.begin();
151 iter != processes.end();
152 ++iter) {
153 const Process& process = iter->second;
154 if (wavefront.count(process.parent)) {
155 children.push_back(process.pid);
156 next_wavefront.insert(process.pid);
160 wavefront.clear();
161 wavefront.swap(next_wavefront);
163 return children;
166 void MemoryDetails::CollectProcessData(
167 const std::vector<ProcessMemoryInformation>& child_info) {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170 ProcessMap process_map = GetProcesses();
171 std::set<pid_t> browsers_found;
173 // For each process on the system, if it appears to be a browser process and
174 // it's parent isn't a browser process, then record it in |browsers_found|.
175 for (ProcessMap::const_iterator iter = process_map.begin();
176 iter != process_map.end();
177 ++iter) {
178 const Process& current_process = iter->second;
179 const BrowserType type = GetBrowserType(current_process.name);
180 if (type == MAX_BROWSERS)
181 continue;
183 ProcessMap::const_iterator parent_iter =
184 process_map.find(current_process.parent);
185 if (parent_iter == process_map.end()) {
186 browsers_found.insert(current_process.pid);
187 continue;
190 if (GetBrowserType(parent_iter->second.name) != type) {
191 // We found a process whose type is diffent from its parent's type.
192 // That means it is the root process of the browser.
193 browsers_found.insert(current_process.pid);
194 break;
198 ProcessData current_browser =
199 GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
200 current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
201 current_browser.process_name = base::ASCIIToUTF16("chrome");
203 for (std::vector<ProcessMemoryInformation>::iterator
204 i = current_browser.processes.begin();
205 i != current_browser.processes.end(); ++i) {
206 // Check if this is one of the child processes whose data we collected
207 // on the IO thread, and if so copy over that data.
208 for (size_t child = 0; child < child_info.size(); child++) {
209 if (child_info[child].pid != i->pid)
210 continue;
211 i->titles = child_info[child].titles;
212 i->process_type = child_info[child].process_type;
213 break;
217 process_data_.push_back(current_browser);
219 // For each browser process, collect a list of its children and get the
220 // memory usage of each.
221 for (std::set<pid_t>::const_iterator iter = browsers_found.begin();
222 iter != browsers_found.end();
223 ++iter) {
224 std::vector<pid_t> browser_processes = GetAllChildren(process_map, *iter);
225 ProcessData browser = GetProcessDataMemoryInformation(browser_processes);
227 ProcessMap::const_iterator process_iter = process_map.find(*iter);
228 if (process_iter == process_map.end())
229 continue;
230 BrowserType type = GetBrowserType(process_iter->second.name);
231 if (type != MAX_BROWSERS)
232 browser.name = base::ASCIIToUTF16(kBrowserPrettyNames[type]);
233 process_data_.push_back(browser);
236 #if defined(OS_CHROMEOS)
237 base::GetSwapInfo(&swap_info_);
238 #endif
240 // Finally return to the browser thread.
241 BrowserThread::PostTask(
242 BrowserThread::UI, FROM_HERE,
243 base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));