Chromium Code Reviews

Side by Side Diff: chrome/browser/chromeos/resource_reporter/resource_reporter.cc

Issue 2363223002: Fix the Chrome OS ResourceReporter (Closed)
Patch Set: No hardcoded memory threshold, keep watch TM until something will be reported or mem pressure level… Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/chromeos/resource_reporter/resource_reporter.h" 5 #include "chrome/browser/chromeos/resource_reporter/resource_reporter.h"
6 6
7 #include <cstdint> 7 #include <cstdint>
8 #include <queue> 8 #include <queue>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/memory/memory_pressure_monitor.h"
12 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
13 #include "base/rand_util.h" 14 #include "base/rand_util.h"
14 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
15 #include "base/sys_info.h" 16 #include "base/sys_info.h"
17 #include "base/time/time.h"
16 #include "chrome/browser/browser_process.h" 18 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/task_manager/task_manager_interface.h" 19 #include "chrome/browser/task_manager/task_manager_interface.h"
18 #include "components/rappor/rappor_service.h" 20 #include "components/rappor/rappor_service.h"
19 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
20 22
21 namespace chromeos { 23 namespace chromeos {
22 24
23 namespace { 25 namespace {
24 26
25 #define GET_ENUM_VAL(enum_entry) static_cast<int>(enum_entry) 27 #define GET_ENUM_VAL(enum_entry) static_cast<int>(enum_entry)
26 28
27 // The task manager refresh interval, currently at 1 minute. 29 // At a critical memory pressure event, we only care about a single complete
28 const int64_t kRefreshIntervalSeconds = 60; 30 // refresh from the task manager (with background calculations). So we request
31 // the minimum refresh rate (once per second).
32 constexpr int64_t kRefreshIntervalSeconds = 1;
29 33
30 // Various memory usage sizes in bytes. 34 // Various memory usage sizes in bytes.
31 const int64_t kMemory1GB = 1024 * 1024 * 1024; 35 constexpr int64_t kMemory1GB = 1024 * 1024 * 1024;
32 const int64_t kMemory800MB = 800 * 1024 * 1024; 36 constexpr int64_t kMemory800MB = 800 * 1024 * 1024;
33 const int64_t kMemory600MB = 600 * 1024 * 1024; 37 constexpr int64_t kMemory600MB = 600 * 1024 * 1024;
34 const int64_t kMemory400MB = 400 * 1024 * 1024; 38 constexpr int64_t kMemory400MB = 400 * 1024 * 1024;
35 const int64_t kMemory200MB = 200 * 1024 * 1024; 39 constexpr int64_t kMemory200MB = 200 * 1024 * 1024;
36 40
37 // The name of the Rappor metric to report the CPU usage. 41 // The name of the Rappor metric to report the CPU usage.
38 const char kCpuRapporMetric[] = "ResourceReporter.Cpu"; 42 constexpr char kCpuRapporMetric[] = "ResourceReporter.Cpu";
39 43
40 // The name of the Rappor metric to report the memory usage. 44 // The name of the Rappor metric to report the memory usage.
41 const char kMemoryRapporMetric[] = "ResourceReporter.Memory"; 45 constexpr char kMemoryRapporMetric[] = "ResourceReporter.Memory";
42 46
43 // The name of the string field of the Rappor metrics in which we'll record the 47 // The name of the string field of the Rappor metrics in which we'll record the
44 // task's Rappor sample name. 48 // task's Rappor sample name.
45 const char kRapporTaskStringField[] = "task"; 49 constexpr char kRapporTaskStringField[] = "task";
46 50
47 // The name of the flags field of the Rappor metrics in which we'll store the 51 // The name of the flags field of the Rappor metrics in which we'll store the
48 // priority of the process on which the task is running. 52 // priority of the process on which the task is running.
49 const char kRapporPriorityFlagsField[] = "priority"; 53 constexpr char kRapporPriorityFlagsField[] = "priority";
50 54
51 // The name of the flags field of the CPU usage Rappor metrics in which we'll 55 // The name of the flags field of the CPU usage Rappor metrics in which we'll
52 // record the number of cores in the current system. 56 // record the number of cores in the current system.
53 const char kRapporNumCoresRangeFlagsField[] = "num_cores_range"; 57 constexpr char kRapporNumCoresRangeFlagsField[] = "num_cores_range";
54 58
55 // The name of the flags field of the Rappor metrics in which we'll store the 59 // The name of the flags field of the Rappor metrics in which we'll store the
56 // CPU / memory usage ranges. 60 // CPU / memory usage ranges.
57 const char kRapporUsageRangeFlagsField[] = "usage_range"; 61 constexpr char kRapporUsageRangeFlagsField[] = "usage_range";
58 62
59 // Currently set to be one day. 63 // Key used to store the last time a Rappor report was recorded in local_state.
60 const int kMinimumTimeBetweenReportsInMs = 1 * 24 * 60 * 60 * 1000; 64 constexpr char kLastRapporReportTimeKey[] =
65 "resource_reporter.last_report_time";
61 66
62 // A functor to sort the TaskRecords by their |cpu|. 67 // To keep privacy guarantees of Rappor, we limit the reports to at most once
63 struct TaskRecordCpuLessThan { 68 // per day.
64 bool operator()(ResourceReporter::TaskRecord* const& lhs, 69 constexpr base::TimeDelta kMinimumTimeBetweenReports =
65 ResourceReporter::TaskRecord* const& rhs) const { 70 base::TimeDelta::FromDays(1);
66 if (lhs->cpu_percent == rhs->cpu_percent)
67 return lhs->id < rhs->id;
68 return lhs->cpu_percent < rhs->cpu_percent;
69 }
70 };
71 71
72 // A functor to sort the TaskRecords by their |memory|. 72 // Gets the memory usage threshold of a process beyond which the process is
73 struct TaskRecordMemoryLessThan { 73 // considered memory-intensive on the current device it's running on.
74 bool operator()(ResourceReporter::TaskRecord* const& lhs, 74 int64_t GetMemoryThresholdForDeviceInBytes() {
75 ResourceReporter::TaskRecord* const& rhs) const { 75 const int64_t bytes_per_cpu = base::SysInfo::AmountOfPhysicalMemory() /
76 if (lhs->memory_bytes == rhs->memory_bytes) 76 base::SysInfo::NumberOfProcessors();
77 return lhs->id < rhs->id; 77
78 return lhs->memory_bytes < rhs->memory_bytes; 78 return bytes_per_cpu * 0.6;
79 } 79 }
80 };
81 80
82 } // namespace 81 } // namespace
83 82
84 ResourceReporter::TaskRecord::TaskRecord(task_manager::TaskId task_id) 83 ResourceReporter::TaskRecord::TaskRecord(task_manager::TaskId task_id)
85 : id(task_id), cpu_percent(0.0), memory_bytes(0), is_background(false) {} 84 : id(task_id), cpu_percent(0.0), memory_bytes(0), is_background(false) {}
86 85
87 ResourceReporter::TaskRecord::TaskRecord(task_manager::TaskId the_id, 86 ResourceReporter::TaskRecord::TaskRecord(task_manager::TaskId the_id,
88 const std::string& task_name, 87 const std::string& task_name,
89 double cpu_percent, 88 double cpu_percent,
90 int64_t memory_bytes, 89 int64_t memory_bytes,
91 bool background) 90 bool background)
92 : id(the_id), 91 : id(the_id),
93 task_name_for_rappor(task_name), 92 task_name_for_rappor(task_name),
94 cpu_percent(cpu_percent), 93 cpu_percent(cpu_percent),
95 memory_bytes(memory_bytes), 94 memory_bytes(memory_bytes),
96 is_background(background) {} 95 is_background(background) {}
97 96
98 ResourceReporter::~ResourceReporter() { 97 ResourceReporter::~ResourceReporter() {
99 } 98 }
100 99
101 // static 100 // static
102 ResourceReporter* ResourceReporter::GetInstance() { 101 ResourceReporter* ResourceReporter::GetInstance() {
103 return base::Singleton<ResourceReporter>::get(); 102 return base::Singleton<ResourceReporter>::get();
104 } 103 }
105 104
105 // static
106 void ResourceReporter::RegisterPrefs(PrefRegistrySimple* registry) {
107 registry->RegisterDoublePref(kLastRapporReportTimeKey, 0.0);
108 }
109
106 void ResourceReporter::StartMonitoring() { 110 void ResourceReporter::StartMonitoring() {
107 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 111 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
108 112
109 if (is_monitoring_) 113 if (is_monitoring_)
110 return; 114 return;
111 115
112 is_monitoring_ = true; 116 is_monitoring_ = true;
113 task_manager::TaskManagerInterface::GetTaskManager()->AddObserver(this);
114 memory_pressure_listener_.reset(new base::MemoryPressureListener( 117 memory_pressure_listener_.reset(new base::MemoryPressureListener(
115 base::Bind(&ResourceReporter::OnMemoryPressure, base::Unretained(this)))); 118 base::Bind(&ResourceReporter::OnMemoryPressure, base::Unretained(this))));
116 } 119 }
117 120
118 void ResourceReporter::StopMonitoring() { 121 void ResourceReporter::StopMonitoring() {
119 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 122 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
120 123
121 if (!is_monitoring_) 124 if (!is_monitoring_)
122 return; 125 return;
123 126
127 // We might be shutting down right after a critical memory pressure event, and
128 // before we get an update from the task manager with all background
129 // calculations refreshed. In this case we must unregister from the task
130 // manager here.
131 if (observed_task_manager())
132 observed_task_manager()->RemoveObserver(this);
133
124 is_monitoring_ = false; 134 is_monitoring_ = false;
125 memory_pressure_listener_.reset(); 135 memory_pressure_listener_.reset();
126 task_manager::TaskManagerInterface::GetTaskManager()->RemoveObserver(this);
127 } 136 }
128 137
129 void ResourceReporter::OnTaskAdded(task_manager::TaskId id) { 138 void ResourceReporter::OnTasksRefreshedWithBackgroundCalculations(
130 // Ignore this event. 139 const task_manager::TaskIdList& task_ids) {
131 } 140 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
132 141
133 void ResourceReporter::OnTaskToBeRemoved(task_manager::TaskId id) { 142 task_records_.clear();
134 auto it = task_records_.find(id); 143 task_records_.reserve(task_ids.size());
135 if (it == task_records_.end())
136 return;
137
138 // Must be erased from the sorted set first.
139 // Note: this could mean that the sorted records are now less than
140 // |kTopConsumerCount| with other records in |task_records_| that can be
141 // added now. That's ok, we ignore this case.
142 auto cpu_it = std::find(task_records_by_cpu_.begin(),
143 task_records_by_cpu_.end(),
144 it->second.get());
145 if (cpu_it != task_records_by_cpu_.end())
146 task_records_by_cpu_.erase(cpu_it);
147
148 auto memory_it = std::find(task_records_by_memory_.begin(),
149 task_records_by_memory_.end(),
150 it->second.get());
151 if (memory_it != task_records_by_memory_.end())
152 task_records_by_memory_.erase(memory_it);
153
154 task_records_.erase(it);
155 }
156
157 void ResourceReporter::OnTasksRefreshed(
158 const task_manager::TaskIdList& task_ids) {
159 have_seen_first_task_manager_refresh_ = true;
160
161 // A priority queue to sort the task records by their |cpu|. Greatest |cpu|
162 // first.
163 std::priority_queue<TaskRecord*,
164 std::vector<TaskRecord*>,
165 TaskRecordCpuLessThan> records_by_cpu_queue;
166 // A priority queue to sort the task records by their |memory|. Greatest
167 // |memory| first.
168 std::priority_queue<TaskRecord*,
169 std::vector<TaskRecord*>,
170 TaskRecordMemoryLessThan> records_by_memory_queue;
171 task_records_by_cpu_.clear();
172 task_records_by_cpu_.reserve(kTopConsumersCount);
173 task_records_by_memory_.clear();
174 task_records_by_memory_.reserve(kTopConsumersCount);
175 144
176 for (const auto& id : task_ids) { 145 for (const auto& id : task_ids) {
177 const double cpu_usage = observed_task_manager()->GetCpuUsage(id); 146 const double cpu_usage = observed_task_manager()->GetCpuUsage(id);
178 const int64_t memory_usage = 147 const int64_t memory_usage =
179 observed_task_manager()->GetPhysicalMemoryUsage(id); 148 observed_task_manager()->GetPhysicalMemoryUsage(id);
180 149
181 // Browser and GPU processes are reported later using UMA histograms as they 150 // Browser and GPU processes are reported later using UMA histograms as they
182 // don't have any privacy issues. 151 // don't have any privacy issues.
183 const auto task_type = observed_task_manager()->GetType(id); 152 const auto task_type = observed_task_manager()->GetType(id);
184 switch (task_type) { 153 switch (task_type) {
185 case task_manager::Task::UNKNOWN: 154 case task_manager::Task::UNKNOWN:
186 case task_manager::Task::ZYGOTE: 155 case task_manager::Task::ZYGOTE:
187 break; 156 break;
188 157
189 case task_manager::Task::BROWSER: 158 case task_manager::Task::BROWSER:
190 last_browser_process_cpu_ = cpu_usage; 159 last_browser_process_cpu_ = cpu_usage;
191 last_browser_process_memory_ = memory_usage >= 0 ? memory_usage : 0; 160 last_browser_process_memory_ = memory_usage >= 0 ? memory_usage : 0;
192 break; 161 break;
193 162
194 case task_manager::Task::GPU: 163 case task_manager::Task::GPU:
195 last_gpu_process_cpu_ = cpu_usage; 164 last_gpu_process_cpu_ = cpu_usage;
196 last_gpu_process_memory_ = memory_usage >= 0 ? memory_usage : 0; 165 last_gpu_process_memory_ = memory_usage >= 0 ? memory_usage : 0;
197 break; 166 break;
198 167
199 default: 168 default:
200 // Other tasks types will be reported using Rappor. 169 // Other tasks types will be reported using Rappor.
201 TaskRecord* task_data = nullptr; 170 if (memory_usage < kTaskMemoryThresholdForReporting &&
202 auto itr = task_records_.find(id); 171 cpu_usage < kTaskCpuThresholdForReporting) {
203 if (itr == task_records_.end()) { 172 // We only care about CPU and memory intensive tasks.
204 task_data = new TaskRecord(id); 173 break;
205 task_records_[id] = base::WrapUnique(task_data);
206 } else {
207 task_data = itr->second.get();
208 } 174 }
209 175
210 DCHECK_EQ(task_data->id, id); 176 task_records_.emplace_back(
211 task_data->task_name_for_rappor = 177 id, observed_task_manager()->GetTaskNameForRappor(id), cpu_usage,
212 observed_task_manager()->GetTaskNameForRappor(id); 178 memory_usage,
213 task_data->cpu_percent = cpu_usage; 179 observed_task_manager()->IsTaskOnBackgroundedProcess(id));
214 task_data->memory_bytes = memory_usage;
215 task_data->is_background =
216 observed_task_manager()->IsTaskOnBackgroundedProcess(id);
217
218 // Push only valid or useful data to both priority queues. They might
219 // end up having more records than |kTopConsumerCount|, that's fine.
220 // We'll take care of that next.
221 if (task_data->cpu_percent > 0)
222 records_by_cpu_queue.push(task_data);
223 if (task_data->memory_bytes > 0)
224 records_by_memory_queue.push(task_data);
225 } 180 }
226 } 181 }
227 182
228 // Sort the |kTopConsumersCount| task records by their CPU and memory usage. 183 // Now that we got the data, we don't need the task manager anymore.
229 while (!records_by_cpu_queue.empty() && 184 if (base::MemoryPressureMonitor::Get()->GetCurrentPressureLevel() !=
230 task_records_by_cpu_.size() < kTopConsumersCount) { 185 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL ||
231 task_records_by_cpu_.push_back(records_by_cpu_queue.top()); 186 !task_records_.empty()) {
232 records_by_cpu_queue.pop(); 187 // The memory pressure events are emitted once per second. In order to avoid
188 // unsubscribing and then resubscribing to the task manager again on the
189 // next event, we keep listening to the task manager as long as the memory
190 // pressure level is critical AND we couldn't find any violators yet.
191 observed_task_manager()->RemoveObserver(this);
233 } 192 }
234 193
235 while (!records_by_memory_queue.empty() && 194 // Schedule reporting the samples.
236 task_records_by_memory_.size() < kTopConsumersCount) { 195 base::ThreadTaskRunnerHandle::Get()->PostTask(
237 task_records_by_memory_.push_back(records_by_memory_queue.top()); 196 FROM_HERE,
238 records_by_memory_queue.pop(); 197 base::Bind(&ResourceReporter::ReportSamples, base::Unretained(this)));
239 }
240 } 198 }
241 199
242 // static 200 // static
243 const size_t ResourceReporter::kTopConsumersCount = 10U; 201 const double ResourceReporter::kTaskCpuThresholdForReporting = 70.0;
202
203 // static
204 const int64_t ResourceReporter::kTaskMemoryThresholdForReporting =
205 GetMemoryThresholdForDeviceInBytes();
244 206
245 ResourceReporter::ResourceReporter() 207 ResourceReporter::ResourceReporter()
246 : TaskManagerObserver(base::TimeDelta::FromSeconds(kRefreshIntervalSeconds), 208 : TaskManagerObserver(base::TimeDelta::FromSeconds(kRefreshIntervalSeconds),
247 task_manager::REFRESH_TYPE_CPU | 209 task_manager::REFRESH_TYPE_CPU |
248 task_manager::REFRESH_TYPE_MEMORY | 210 task_manager::REFRESH_TYPE_MEMORY |
249 task_manager::REFRESH_TYPE_PRIORITY), 211 task_manager::REFRESH_TYPE_PRIORITY),
250 system_cpu_cores_range_(GetCurrentSystemCpuCoresRange()) {} 212 task_manager_for_testing_(nullptr),
213 system_cpu_cores_range_(GetCurrentSystemCpuCoresRange()),
214 last_browser_process_cpu_(0.0),
215 last_gpu_process_cpu_(0.0),
216 last_browser_process_memory_(0),
217 last_gpu_process_memory_(0),
218 is_monitoring_(false) {}
251 219
252 // static 220 // static
253 std::unique_ptr<rappor::Sample> ResourceReporter::CreateRapporSample( 221 std::unique_ptr<rappor::Sample> ResourceReporter::CreateRapporSample(
254 rappor::RapporService* rappor_service, 222 rappor::RapporService* rappor_service,
255 const ResourceReporter::TaskRecord& task_record) { 223 const ResourceReporter::TaskRecord& task_record) {
256 std::unique_ptr<rappor::Sample> sample( 224 std::unique_ptr<rappor::Sample> sample(
257 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE)); 225 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE));
258 sample->SetStringField(kRapporTaskStringField, 226 sample->SetStringField(kRapporTaskStringField,
259 task_record.task_name_for_rappor); 227 task_record.task_name_for_rappor);
260 sample->SetFlagsField(kRapporPriorityFlagsField, 228 sample->SetFlagsField(kRapporPriorityFlagsField,
(...skipping 54 matching lines...)
315 283
316 NOTREACHED(); 284 NOTREACHED();
317 return CpuCoresNumberRange::RANGE_NA; 285 return CpuCoresNumberRange::RANGE_NA;
318 } 286 }
319 287
320 const ResourceReporter::TaskRecord* ResourceReporter::SampleTaskByCpu() const { 288 const ResourceReporter::TaskRecord* ResourceReporter::SampleTaskByCpu() const {
321 // Perform a weighted random sampling taking the tasks' CPU usage as their 289 // Perform a weighted random sampling taking the tasks' CPU usage as their
322 // weights to randomly select one of them to be reported by Rappor. The higher 290 // weights to randomly select one of them to be reported by Rappor. The higher
323 // the CPU usage, the higher the chance that the task will be selected. 291 // the CPU usage, the higher the chance that the task will be selected.
324 // See https://en.wikipedia.org/wiki/Reservoir_sampling. 292 // See https://en.wikipedia.org/wiki/Reservoir_sampling.
325 TaskRecord* sampled_task = nullptr; 293 const TaskRecord* sampled_task = nullptr;
326 double cpu_weights_sum = 0; 294 double cpu_weights_sum = 0;
327 for (auto* task_data : task_records_by_cpu_) { 295 for (const auto& task_data : task_records_) {
328 if ((base::RandDouble() * (cpu_weights_sum + task_data->cpu_percent)) >= 296 if ((base::RandDouble() * (cpu_weights_sum + task_data.cpu_percent)) >=
329 cpu_weights_sum) { 297 cpu_weights_sum) {
330 sampled_task = task_data; 298 sampled_task = &task_data;
331 } 299 }
332 cpu_weights_sum += task_data->cpu_percent; 300 cpu_weights_sum += task_data.cpu_percent;
333 } 301 }
334 302
335 return sampled_task; 303 return sampled_task;
336 } 304 }
337 305
338 const ResourceReporter::TaskRecord* 306 const ResourceReporter::TaskRecord*
339 ResourceReporter::SampleTaskByMemory() const { 307 ResourceReporter::SampleTaskByMemory() const {
340 // Perform a weighted random sampling taking the tasks' memory usage as their 308 // Perform a weighted random sampling taking the tasks' memory usage as their
341 // weights to randomly select one of them to be reported by Rappor. The higher 309 // weights to randomly select one of them to be reported by Rappor. The higher
342 // the memory usage, the higher the chance that the task will be selected. 310 // the memory usage, the higher the chance that the task will be selected.
343 // See https://en.wikipedia.org/wiki/Reservoir_sampling. 311 // See https://en.wikipedia.org/wiki/Reservoir_sampling.
344 TaskRecord* sampled_task = nullptr; 312 const TaskRecord* sampled_task = nullptr;
345 int64_t memory_weights_sum = 0; 313 int64_t memory_weights_sum = 0;
346 for (auto* task_data : task_records_by_memory_) { 314 for (const auto& task_data : task_records_) {
347 if ((base::RandDouble() * (memory_weights_sum + task_data->memory_bytes)) >= 315 if ((base::RandDouble() * (memory_weights_sum + task_data.memory_bytes)) >=
348 memory_weights_sum) { 316 memory_weights_sum) {
349 sampled_task = task_data; 317 sampled_task = &task_data;
350 } 318 }
351 memory_weights_sum += task_data->memory_bytes; 319 memory_weights_sum += task_data.memory_bytes;
352 } 320 }
353 321
354 return sampled_task; 322 return sampled_task;
355 } 323 }
356 324
325 void ResourceReporter::ReportSamples() {
326 // Report browser and GPU processes usage using UMA histograms.
327 UMA_HISTOGRAM_ENUMERATION(
328 "ResourceReporter.BrowserProcess.CpuUsage",
329 GET_ENUM_VAL(GetCpuUsageRange(last_browser_process_cpu_)),
330 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
331 UMA_HISTOGRAM_ENUMERATION(
332 "ResourceReporter.BrowserProcess.MemoryUsage",
333 GET_ENUM_VAL(GetMemoryUsageRange(last_browser_process_memory_)),
334 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
335 UMA_HISTOGRAM_ENUMERATION(
336 "ResourceReporter.GpuProcess.CpuUsage",
337 GET_ENUM_VAL(GetCpuUsageRange(last_gpu_process_cpu_)),
338 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
339 UMA_HISTOGRAM_ENUMERATION(
340 "ResourceReporter.GpuProcess.MemoryUsage",
341 GET_ENUM_VAL(GetMemoryUsageRange(last_gpu_process_memory_)),
342 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
343
344 // For the rest of tasks, report them using Rappor.
345 auto* rappor_service = g_browser_process->rappor_service();
346 if (!rappor_service || task_records_.empty())
347 return;
348
349 // We have samples to report via Rappor. Store 'now' as the time of the last
350 // report.
351 if (g_browser_process->local_state()) {
352 g_browser_process->local_state()->SetDouble(
353 kLastRapporReportTimeKey, base::Time::NowFromSystemTime().ToDoubleT());
354 }
355
356 // Use weighted random sampling to select a task to report in the CPU
357 // metric.
358 const TaskRecord* sampled_cpu_task = SampleTaskByCpu();
359 if (sampled_cpu_task) {
360 std::unique_ptr<rappor::Sample> cpu_sample(
361 CreateRapporSample(rappor_service, *sampled_cpu_task));
362 cpu_sample->SetFlagsField(kRapporNumCoresRangeFlagsField,
363 GET_ENUM_VAL(system_cpu_cores_range_),
364 GET_ENUM_VAL(CpuCoresNumberRange::NUM_RANGES));
365 cpu_sample->SetFlagsField(
366 kRapporUsageRangeFlagsField,
367 GET_ENUM_VAL(GetCpuUsageRange(sampled_cpu_task->cpu_percent)),
368 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
369 rappor_service->RecordSampleObj(kCpuRapporMetric, std::move(cpu_sample));
370 }
371
372 // Use weighted random sampling to select a task to report in the memory
373 // metric.
374 const TaskRecord* sampled_memory_task = SampleTaskByMemory();
375 if (sampled_memory_task) {
376 std::unique_ptr<rappor::Sample> memory_sample(
377 CreateRapporSample(rappor_service, *sampled_memory_task));
378 memory_sample->SetFlagsField(
379 kRapporUsageRangeFlagsField,
380 GET_ENUM_VAL(GetMemoryUsageRange(sampled_memory_task->memory_bytes)),
381 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
382 rappor_service->RecordSampleObj(kMemoryRapporMetric,
383 std::move(memory_sample));
384 }
385 }
386
357 void ResourceReporter::OnMemoryPressure( 387 void ResourceReporter::OnMemoryPressure(
358 MemoryPressureLevel memory_pressure_level) { 388 MemoryPressureLevel memory_pressure_level) {
359 if (have_seen_first_task_manager_refresh_ && 389 if (memory_pressure_level ==
360 memory_pressure_level ==
361 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL) { 390 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL) {
362 // Report browser and GPU processes usage using UMA histograms. 391 // If we are already listening to the task manager, then we're waiting for
363 UMA_HISTOGRAM_ENUMERATION( 392 // a refresh event.
364 "ResourceReporter.BrowserProcess.CpuUsage", 393 if (observed_task_manager())
365 GET_ENUM_VAL(GetCpuUsageRange(last_browser_process_cpu_)),
366 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
367 UMA_HISTOGRAM_ENUMERATION(
368 "ResourceReporter.BrowserProcess.MemoryUsage",
369 GET_ENUM_VAL(GetMemoryUsageRange(last_browser_process_memory_)),
370 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
371 UMA_HISTOGRAM_ENUMERATION(
372 "ResourceReporter.GpuProcess.CpuUsage",
373 GET_ENUM_VAL(GetCpuUsageRange(last_gpu_process_cpu_)),
374 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
375 UMA_HISTOGRAM_ENUMERATION(
376 "ResourceReporter.GpuProcess.MemoryUsage",
377 GET_ENUM_VAL(GetMemoryUsageRange(last_gpu_process_memory_)),
378 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
379
380 // For the rest of tasks, report them using Rappor.
381 auto* rappor_service = g_browser_process->rappor_service();
382 if (!rappor_service)
383 return; 394 return;
384 395
385 // We only record Rappor samples only if it's the first ever critical memory 396 // We only record Rappor samples only if it's the first ever critical memory
386 // pressure event we receive, or it has been more than 397 // pressure event we receive, or it has been more than
387 // |kMinimumTimeBetweenReportsInMs| since the last time we recorded samples. 398 // |kMinimumTimeBetweenReportsInMs| since the last time we recorded samples.
388 if (!have_seen_first_memory_pressure_event_) { 399 if (g_browser_process->local_state()) {
389 have_seen_first_memory_pressure_event_ = true; 400 const base::Time now = base::Time::NowFromSystemTime();
390 } else if ((base::TimeTicks::Now() - last_memory_pressure_event_time_) < 401 const base::Time last_rappor_report_time =
391 base::TimeDelta::FromMilliseconds(kMinimumTimeBetweenReportsInMs)) { 402 base::Time::FromDoubleT(g_browser_process->local_state()->GetDouble(
392 return; 403 kLastRapporReportTimeKey));
404 const base::TimeDelta delta_since_last_report =
405 now >= last_rappor_report_time ? now - last_rappor_report_time
406 : base::TimeDelta::Max();
407
408 if (delta_since_last_report < kMinimumTimeBetweenReports)
409 return;
393 } 410 }
394 411
395 last_memory_pressure_event_time_ = base::TimeTicks::Now(); 412 // Start listening to the task manager and wait for the first refresh event
396 413 // with background calculations completion.
397 // Use weighted random sampling to select a task to report in the CPU 414 if (task_manager_for_testing_)
398 // metric. 415 task_manager_for_testing_->AddObserver(this);
399 const TaskRecord* sampled_cpu_task = SampleTaskByCpu(); 416 else
400 if (sampled_cpu_task) { 417 task_manager::TaskManagerInterface::GetTaskManager()->AddObserver(this);
401 std::unique_ptr<rappor::Sample> cpu_sample( 418 } else {
402 CreateRapporSample(rappor_service, *sampled_cpu_task)); 419 // If we are still listening to the task manager from an earlier critical
403 cpu_sample->SetFlagsField(kRapporNumCoresRangeFlagsField, 420 // memory pressure level, we need to stop listening to it.
404 GET_ENUM_VAL(system_cpu_cores_range_), 421 if (observed_task_manager())
405 GET_ENUM_VAL(CpuCoresNumberRange::NUM_RANGES)); 422 observed_task_manager()->RemoveObserver(this);
406 cpu_sample->SetFlagsField(
407 kRapporUsageRangeFlagsField,
408 GET_ENUM_VAL(GetCpuUsageRange(sampled_cpu_task->cpu_percent)),
409 GET_ENUM_VAL(CpuUsageRange::NUM_RANGES));
410 rappor_service->RecordSampleObj(kCpuRapporMetric, std::move(cpu_sample));
411 }
412
413 // Use weighted random sampling to select a task to report in the memory
414 // metric.
415 const TaskRecord* sampled_memory_task = SampleTaskByMemory();
416 if (sampled_memory_task) {
417 std::unique_ptr<rappor::Sample> memory_sample(
418 CreateRapporSample(rappor_service, *sampled_memory_task));
419 memory_sample->SetFlagsField(
420 kRapporUsageRangeFlagsField,
421 GET_ENUM_VAL(GetMemoryUsageRange(sampled_memory_task->memory_bytes)),
422 GET_ENUM_VAL(MemoryUsageRange::NUM_RANGES));
423 rappor_service->RecordSampleObj(kMemoryRapporMetric,
424 std::move(memory_sample));
425 }
426 } 423 }
427 } 424 }
428 425
429 } // namespace chromeos 426 } // namespace chromeos
OLDNEW

Powered by Google App Engine