OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef CHROME_BROWSER_CHROMEOS_RESOURCE_REPORTER_RESOURCE_REPORTER_H_ | |
6 #define CHROME_BROWSER_CHROMEOS_RESOURCE_REPORTER_RESOURCE_REPORTER_H_ | |
7 | |
8 #include <map> | |
9 #include <set> | |
10 | |
11 #include "base/gtest_prod_util.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/memory_pressure_listener.h" | |
14 #include "chrome/browser/task_management/task_manager_observer.h" | |
15 #include "components/metrics/metrics_service.h" | |
16 #include "components/rappor/sample.h" | |
17 | |
18 namespace base { | |
19 template <typename T> | |
20 struct DefaultSingletonTraits; | |
21 } | |
22 | |
23 using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel; | |
24 | |
25 namespace chromeos { | |
26 | |
27 // A system that tracks the top |kTopConsumersCount| CPU and memory consumer | |
28 // Chrome tasks and reports them via Rappor whenever memory pressure is moderate | |
29 // or higher. | |
30 class ResourceReporter | |
31 : public task_management::TaskManagerObserver, | |
32 public metrics::MetricsServiceObserver { | |
33 public: | |
34 // A collection of the data of a task manager's task that the ResourceReporter | |
35 // is interested in. | |
36 struct TaskRecord { | |
37 // The ID of the task. | |
38 task_management::TaskId id; | |
39 | |
40 // The name of the Rappor sample to be used for recording a sample | |
41 // representing this task. | |
42 std::string rappor_sample; | |
43 | |
44 // The CPU usage of the task from most recent task manager refresh. | |
ncarter (slow)
2015/11/10 23:29:56
Is this a percentage? Clarify the comment.
afakhry
2015/11/12 00:21:28
Done.
| |
45 double cpu; | |
46 | |
47 // The physical memory usage of the task from the most recent task manager | |
48 // refresh. | |
ncarter (slow)
2015/11/10 23:29:56
In bytes? Does this include shared memory?
afakhry
2015/11/12 00:21:28
Done.
| |
49 int64_t memory; | |
50 | |
51 // True if the task is running on backgrounded process. | |
ncarter (slow)
2015/11/10 23:29:56
"running at background priority" might be a better
afakhry
2015/11/12 00:21:28
Done.
| |
52 bool is_background; | |
53 | |
54 explicit TaskRecord(task_management::TaskId the_id) | |
55 : id(the_id), cpu(0.0), memory(0), is_background(false) {} | |
56 | |
57 TaskRecord(task_management::TaskId the_id, | |
58 const std::string& the_sample, | |
59 double the_cpu, | |
60 int64_t the_memory, | |
61 bool background) | |
ncarter (slow)
2015/11/10 23:29:56
Should be in the .cc file.
afakhry
2015/11/12 00:21:28
Done.
| |
62 : id(the_id), | |
63 rappor_sample(the_sample), | |
64 cpu(the_cpu), | |
65 memory(the_memory), | |
66 is_background(background) {} | |
67 }; | |
68 | |
69 ~ResourceReporter() override; | |
70 | |
71 // The system runs only if the user has opted-in to send anonymous usage stats | |
72 // to Google. We observe state changes in the MetricsService which will | |
ncarter (slow)
2015/11/10 23:29:56
Is there a way to word this without saying "Google
afakhry
2015/11/12 00:21:28
Done.
| |
73 // determine if the ResourceReporter needs to observe the task manager and | |
74 // collect resource usage stats. | |
75 static void StartObservingMetricsService(); | |
76 static void StopObservingMetricsService(); | |
77 | |
78 // The singleton instance. | |
79 static ResourceReporter* GetInstance(); | |
80 | |
81 // task_management::TaskManagerObserver: | |
82 void OnTaskAdded(task_management::TaskId id) override; | |
83 void OnTaskToBeRemoved(task_management::TaskId id) override; | |
84 void OnTasksRefreshed(const task_management::TaskIdList& task_ids) override; | |
85 | |
86 // metrics::MetricsServiceObserver: | |
87 void OnMetricsServiceStart() override; | |
88 void OnMetricsServiceStop() override; | |
89 | |
90 private: | |
91 friend struct base::DefaultSingletonTraits<ResourceReporter>; | |
92 friend class ResourceReporterTest; | |
93 FRIEND_TEST_ALL_PREFIXES(ResourceReporterTest, TestGetCpuRapporMetricName); | |
94 FRIEND_TEST_ALL_PREFIXES(ResourceReporterTest, TestGetMemoryRapporMetricName); | |
95 FRIEND_TEST_ALL_PREFIXES(ResourceReporterTest, TestAll); | |
96 | |
97 // A functor to sort the TaskRecords by their |cpu| in a descending order. | |
98 struct TaskRecordByCpuSorter { | |
99 bool operator()(TaskRecord* const& lhs, TaskRecord* const& rhs) const { | |
100 if (lhs->cpu == rhs->cpu) | |
ncarter (slow)
2015/11/10 23:29:56
This is a nontrivial function; shouldn't be in a h
afakhry
2015/11/12 00:21:28
Done and modified for both sorters to be a Less th
| |
101 return lhs->id > rhs->id; | |
102 return lhs->cpu > rhs->cpu; | |
103 } | |
104 }; | |
105 | |
106 // A functor to sort the TaskRecords by their |memory| in a descending order. | |
107 struct TaskRecordByMemorySorter { | |
108 bool operator()(TaskRecord* const& lhs, TaskRecord* const& rhs) const { | |
109 if (lhs->memory == rhs->memory) | |
110 return lhs->id > rhs->id; | |
111 return lhs->memory > rhs->memory; | |
112 } | |
113 }; | |
114 | |
115 enum TaskProcessPriority { | |
116 FOREGROUND = 0, | |
117 BACKGROUND, | |
118 PRIORITIES_NUM, | |
119 }; | |
120 | |
121 enum CpuUsageRange { | |
122 RANGE_0_TO_10_PERCENT = 0, | |
123 RANGE_10_TO_30_PERCENT, | |
124 RANGE_30_TO_60_PERCENT, | |
125 RANGE_ABOVE_60_PERCENT, | |
126 CPU_RANGES_NUM, | |
127 }; | |
128 | |
129 enum MemoryUsageRange { | |
130 RANGE_0_TO_200_MB = 0, | |
131 RANGE_200_TO_400_MB, | |
132 RANGE_400_TO_600_MB, | |
133 RANGE_600_TO_800_MB, | |
134 RANGE_800_TO_1_GB, | |
135 RANGE_ABOVE_1_GB, | |
136 MEMORY_RANGES_NUM, | |
137 }; | |
138 | |
139 enum CpuCoresNumberRange { | |
140 RANGE_CORES_0_CORES = 0, | |
ncarter (slow)
2015/11/10 23:29:56
I've never seen a machine with 0 cores. How would
afakhry
2015/11/12 00:21:28
Done.
| |
141 RANGE_CORES_1_TO_2_CORES, // [1, 2] | |
ncarter (slow)
2015/11/10 23:29:56
Should 1 and 2 cores be separate buckets?
afakhry
2015/11/12 00:21:28
Done.
| |
142 RANGE_CORES_2_TO_4_CORES, // ]2, 4] | |
ncarter (slow)
2015/11/10 23:29:56
This "]2" notation (which I assume means an open i
afakhry
2015/11/12 00:21:28
Haha! Yes it means an open interval. We used to wr
| |
143 RANGE_CORES_4_TO_8_CORES, // ]4, 8] | |
144 RANGE_CORES_8_TO_16_CORES, // ]8, 16] | |
145 RANGE_CORES_ABOVE_16_CORES, // > 16 | |
146 CORES_RANGES_NUM, | |
147 }; | |
148 | |
149 // The maximum number of top consumer tasks of each resource that we're | |
150 // interested in reporting. | |
151 static const size_t kTopConsumersCount; | |
152 | |
153 ResourceReporter(); | |
154 | |
155 // Creates a Rappor sample for the given |task_record|. | |
156 static scoped_ptr<rappor::Sample> CreateRapporSample( | |
157 rappor::RapporService* rappor_service, | |
158 const TaskRecord& task_record); | |
159 | |
160 // Gets the CPU/memory usage ranges given the |cpu| / |memory_in_bytes| | |
161 // values. | |
162 static CpuUsageRange GetCpuUsageRange(double cpu); | |
163 static MemoryUsageRange GetMemoryUsageRange(int64_t memory_in_bytes); | |
164 | |
165 // Gets the bucket in which the current system's number of CPU cores fall | |
166 // into. | |
167 static CpuCoresNumberRange GetCurrentSystemCpuCoresRange(); | |
168 | |
169 // Start / stop observing the task manager and the memory pressure events. | |
170 void StartMonitoring(); | |
171 void StopMonitoring(); | |
172 | |
173 // The callback function that will be invoked on memory pressure events. | |
174 void OnMemoryPressure(MemoryPressureLevel memory_pressure_level); | |
175 | |
176 // We'll use this to watch for memory pressure events so that we can trigger | |
177 // Rappor sampling at moderate memory pressure or higher. | |
178 scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_; | |
179 | |
180 // Contains the collected data about the currently running tasks from the most | |
181 // recent task manager refresh. | |
182 std::map<task_management::TaskId, scoped_ptr<TaskRecord>> task_records_; | |
183 | |
184 // Contains the top |kTopConsumerCount| CPU consumer tasks sorted in a | |
185 // descending order by their CPU usage. | |
186 std::set<TaskRecord*, TaskRecordByCpuSorter> task_records_by_cpu_; | |
187 | |
188 // Contains the top |kTopConsumerCount| memory consumer tasks sorted in a | |
189 // descending order by their memory usage. | |
190 std::set<TaskRecord*, TaskRecordByMemorySorter> task_records_by_memory_; | |
191 | |
192 const CpuCoresNumberRange system_cpu_cores_range_; | |
193 | |
194 // the most recent reading for the browser and GPU processes to be reported as | |
195 // UMA histograms when the system is under moderate memory pressure or higher. | |
196 double last_browser_process_cpu_ = 0.0; | |
197 double last_gpu_process_cpu_ = 0.0; | |
198 int64_t last_browser_process_memory_ = 0; | |
199 int64_t last_gpu_process_memory_ = 0; | |
200 | |
201 MemoryPressureLevel previous_memory_pressure_level_ = | |
202 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_NONE; | |
203 | |
204 // MetricsService::Start()/Stop() can be called multiple times which can cause | |
205 // all sort of trouble. We need to track whether we have already started | |
206 // monitoring or not using the below flag. | |
207 bool is_monitoring_; | |
ncarter (slow)
2015/11/10 23:29:56
This is kind of weird. Why are there redundant Sta
afakhry
2015/11/12 00:21:28
The problem happens when Start() is called several
ncarter (slow)
2015/11/13 22:44:32
Are we just coding around a bug in the MetricsServ
| |
208 | |
209 DISALLOW_COPY_AND_ASSIGN(ResourceReporter); | |
210 }; | |
211 | |
212 } // namespace chromeos | |
213 | |
214 #endif // CHROME_BROWSER_CHROMEOS_RESOURCE_REPORTER_RESOURCE_REPORTER_H_ | |
OLD | NEW |