Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / chrome / browser / memory_details_linux.cc
blob469e3aeb3dcaffbb4dd920c387c4539c63ee756b
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/files/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 "chrome/grit/chromium_strings.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/common/process_type.h"
24 #include "ui/base/l10n/l10n_util.h"
26 using base::ProcessEntry;
27 using content::BrowserThread;
29 namespace {
31 // Known browsers which we collect details for.
32 enum BrowserType {
33 CHROME = 0,
34 FIREFOX,
35 ICEWEASEL,
36 OPERA,
37 KONQUEROR,
38 EPIPHANY,
39 MIDORI,
40 MAX_BROWSERS
43 // The pretty printed names of those browsers. Matches up with enum
44 // BrowserType.
45 const char kBrowserPrettyNames[][10] = {
46 "Chrome",
47 "Firefox",
48 "Iceweasel",
49 "Opera",
50 "Konqueror",
51 "Epiphany",
52 "Midori",
55 // A mapping from process name to the type of browser.
56 const struct {
57 const char process_name[17];
58 BrowserType browser;
59 } kBrowserBinaryNames[] = {
60 { "firefox", FIREFOX },
61 { "firefox-3.5", FIREFOX },
62 { "firefox-3.0", FIREFOX },
63 { "firefox-bin", FIREFOX },
64 { "iceweasel", ICEWEASEL },
65 { "opera", OPERA },
66 { "konqueror", KONQUEROR },
67 { "epiphany-browser", EPIPHANY },
68 { "epiphany", EPIPHANY },
69 { "midori", MIDORI },
70 { "", MAX_BROWSERS },
73 struct Process {
74 pid_t pid;
75 pid_t parent;
76 std::string name;
79 typedef std::map<pid_t, Process> ProcessMap;
81 // Get information on all the processes running on the system.
82 ProcessMap GetProcesses() {
83 ProcessMap map;
85 base::ProcessIterator process_iter(NULL);
86 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
87 Process process;
88 process.pid = process_entry->pid();
89 process.parent = process_entry->parent_pid();
90 process.name = process_entry->exe_file();
91 map.insert(std::make_pair(process.pid, process));
93 return map;
96 // Given a process name, return the type of the browser which created that
97 // process, or |MAX_BROWSERS| if we don't know about it.
98 BrowserType GetBrowserType(const std::string& process_name) {
99 for (unsigned i = 0; kBrowserBinaryNames[i].process_name[0]; ++i) {
100 if (strcmp(process_name.c_str(), kBrowserBinaryNames[i].process_name) == 0)
101 return kBrowserBinaryNames[i].browser;
104 return MAX_BROWSERS;
107 // For each of a list of pids, collect memory information about that process.
108 ProcessData GetProcessDataMemoryInformation(
109 const std::vector<pid_t>& pids) {
110 ProcessData process_data;
111 for (pid_t pid : pids) {
112 ProcessMemoryInformation pmi;
114 pmi.pid = pid;
115 pmi.num_processes = 1;
117 if (pmi.pid == base::GetCurrentProcId())
118 pmi.process_type = content::PROCESS_TYPE_BROWSER;
119 else
120 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
122 scoped_ptr<base::ProcessMetrics> metrics(
123 base::ProcessMetrics::CreateProcessMetrics(pid));
124 metrics->GetWorkingSetKBytes(&pmi.working_set);
126 process_data.processes.push_back(pmi);
128 return process_data;
131 // Find all children of the given process with pid |root|.
132 std::vector<pid_t> GetAllChildren(const ProcessMap& processes, pid_t root) {
133 std::vector<pid_t> children;
134 children.push_back(root);
136 std::set<pid_t> wavefront, next_wavefront;
137 wavefront.insert(root);
139 while (wavefront.size()) {
140 for (const auto& entry : processes) {
141 const Process& process = entry.second;
142 if (wavefront.count(process.parent)) {
143 children.push_back(process.pid);
144 next_wavefront.insert(process.pid);
148 wavefront.clear();
149 wavefront.swap(next_wavefront);
151 return children;
154 } // namespace
156 MemoryDetails::MemoryDetails() {
159 ProcessData* MemoryDetails::ChromeBrowser() {
160 return &process_data_[0];
163 void MemoryDetails::CollectProcessData(
164 CollectionMode mode,
165 const std::vector<ProcessMemoryInformation>& child_info) {
166 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
168 ProcessMap process_map = GetProcesses();
169 std::set<pid_t> browsers_found;
171 // For each process on the system, if it appears to be a browser process and
172 // it's parent isn't a browser process, then record it in |browsers_found|.
173 for (const auto& entry : process_map) {
174 const Process& current_process = entry.second;
175 const BrowserType type = GetBrowserType(current_process.name);
176 if (type == MAX_BROWSERS)
177 continue;
178 if (type != CHROME && mode == FROM_CHROME_ONLY)
179 continue;
181 ProcessMap::const_iterator parent_iter =
182 process_map.find(current_process.parent);
183 if (parent_iter == process_map.end()) {
184 browsers_found.insert(current_process.pid);
185 continue;
188 if (GetBrowserType(parent_iter->second.name) != type) {
189 // We found a process whose type is different from its parent's type.
190 // That means it is the root process of the browser.
191 browsers_found.insert(current_process.pid);
192 continue;
196 ProcessData current_browser =
197 GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
198 current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
199 current_browser.process_name = base::ASCIIToUTF16("chrome");
201 for (std::vector<ProcessMemoryInformation>::iterator
202 i = current_browser.processes.begin();
203 i != current_browser.processes.end(); ++i) {
204 // Check if this is one of the child processes whose data we collected
205 // on the IO thread, and if so copy over that data.
206 for (size_t child = 0; child < child_info.size(); child++) {
207 if (child_info[child].pid != i->pid)
208 continue;
209 i->titles = child_info[child].titles;
210 i->process_type = child_info[child].process_type;
211 break;
215 process_data_.push_back(current_browser);
217 // For each browser process, collect a list of its children and get the
218 // memory usage of each.
219 for (pid_t pid : browsers_found) {
220 std::vector<pid_t> browser_processes = GetAllChildren(process_map, pid);
221 ProcessData browser = GetProcessDataMemoryInformation(browser_processes);
223 ProcessMap::const_iterator process_iter = process_map.find(pid);
224 if (process_iter == process_map.end())
225 continue;
226 BrowserType type = GetBrowserType(process_iter->second.name);
227 if (type != MAX_BROWSERS)
228 browser.name = base::ASCIIToUTF16(kBrowserPrettyNames[type]);
229 process_data_.push_back(browser);
232 #if defined(OS_CHROMEOS)
233 base::GetSwapInfo(&swap_info_);
234 #endif
236 // Finally return to the browser thread.
237 BrowserThread::PostTask(
238 BrowserThread::UI, FROM_HERE,
239 base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));