OLD | NEW |
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 <stddef.h> | 5 #include <stddef.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <limits> | 8 #include <limits> |
9 #include <map> | 9 #include <map> |
10 #include <string> | 10 #include <string> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/memory/memory_pressure_monitor.h" |
| 15 #include "base/run_loop.h" |
14 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
15 #include "base/timer/mock_timer.h" | 17 #include "base/timer/mock_timer.h" |
16 #include "chrome/browser/chromeos/resource_reporter/resource_reporter.h" | 18 #include "chrome/browser/chromeos/resource_reporter/resource_reporter.h" |
17 #include "chrome/browser/task_manager/test_task_manager.h" | 19 #include "chrome/browser/task_manager/test_task_manager.h" |
| 20 #include "content/public/test/test_browser_thread_bundle.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
19 | 22 |
20 using task_manager::TaskId; | 23 using task_manager::TaskId; |
21 | 24 |
22 namespace chromeos { | 25 namespace chromeos { |
23 | 26 |
24 namespace { | 27 namespace { |
25 | 28 |
26 const int64_t k1KB = 1024; | 29 constexpr int64_t k1KB = 1024; |
27 const int64_t k1MB = 1024 * 1024; | 30 constexpr int64_t k1MB = 1024 * 1024; |
28 const int64_t k1GB = 1024 * 1024 * 1024; | 31 constexpr int64_t k1GB = 1024 * 1024 * 1024; |
| 32 |
| 33 constexpr double kBrowserProcessCpu = 21.0; |
| 34 constexpr int64_t kBrowserProcessMemory = 300 * k1MB; |
| 35 constexpr double kGpuProcessCpu = 60.0; |
| 36 constexpr int64_t kGpuProcessMemory = 900 * k1MB; |
29 | 37 |
30 // A list of task records that we'll use to fill the task manager. | 38 // A list of task records that we'll use to fill the task manager. |
31 const ResourceReporter::TaskRecord kTestTasks[] = { | 39 const ResourceReporter::TaskRecord kTestTasks[] = { |
32 { 0, "0", 30.0, 43 * k1KB, false }, | 40 {0, "0", 30.0, 43 * k1KB, false}, |
33 { 1, "1", 9.0, 20 * k1MB, false }, | 41 {1, "1", 9.0, 20 * k1MB, false}, |
34 { 2, "2", 35.0, 3 * k1GB, false }, | 42 {2, "2", 35.0, 3 * k1GB, false}, |
35 { 3, "3", 21.0, 300 * k1MB, false }, // Browser task. | 43 // Browser task. |
36 { 4, "4", 85.0, 400 * k1KB, false }, | 44 {3, "3", kBrowserProcessCpu, kBrowserProcessMemory, false}, |
37 { 5, "5", 30.1, 500 * k1MB, false }, | 45 {4, "4", 85.0, 400 * k1KB, false}, |
38 { 6, "6", 60.0, 900 * k1MB, false }, // GPU task. | 46 {5, "5", 30.1, 500 * k1MB, false}, |
39 { 7, "7", 4.0, 1 * k1GB, false }, | 47 // GPU task. |
40 { 8, "8", 40.0, 64 * k1KB, false }, | 48 {6, "6", kGpuProcessCpu, kGpuProcessMemory, false}, |
41 { 9, "9", 93.0, 64 * k1MB, false }, | 49 {7, "7", 4.0, 1 * k1GB, false}, |
42 { 10, "10", 2.23, 2 * k1KB, false }, | 50 {8, "8", 40.0, 64 * k1KB, false}, |
43 { 11, "11", 55.0, 40 * k1MB, false }, | 51 {9, "9", 93.0, 64 * k1MB, false}, |
44 { 12, "12", 87.0, 30 * k1KB, false }, | 52 {10, "10", 2.23, 2 * k1KB, false}, |
| 53 {11, "11", 55.0, 40 * k1MB, false}, |
| 54 {12, "12", 87.0, 30 * k1KB, false}, |
45 }; | 55 }; |
46 | 56 |
47 // A list of task IDs that will be removed from the task manager later after all | 57 constexpr size_t kTasksSize = arraysize(kTestTasks); |
48 // the above tasks have been added. | |
49 const task_manager::TaskId kIdsOfTasksToRemove[] = { | |
50 4, 7, 12, 8, 5, | |
51 }; | |
52 | |
53 // Must be larger than |ResourceReporter::kTopConsumerCount| + 2 (to account for | |
54 // the browser and GPU tasks). | |
55 const size_t kTasksSize = arraysize(kTestTasks); | |
56 | |
57 // Must be smaller than |ResourceReporter::kTopConsumerCount|. | |
58 const size_t kInitiallyAddedTasks = kTasksSize - 6; | |
59 | |
60 // Must be such that |kTasksSize| - |kTasksToBeRemovedSize| is less than | |
61 // |ResourceReporter::kTopConsumerCount|. | |
62 const size_t kTasksToBeRemovedSize = arraysize(kIdsOfTasksToRemove); | |
63 | 58 |
64 // A test implementation of the task manager that can be used to collect CPU and | 59 // A test implementation of the task manager that can be used to collect CPU and |
65 // memory usage so that they can be tested with the resource reporter. | 60 // memory usage so that they can be tested with the resource reporter. |
66 class DummyTaskManager : public task_manager::TestTaskManager { | 61 class DummyTaskManager : public task_manager::TestTaskManager { |
67 public: | 62 public: |
68 DummyTaskManager() { | 63 DummyTaskManager() { |
69 set_timer_for_testing( | 64 set_timer_for_testing( |
70 std::unique_ptr<base::Timer>(new base::MockTimer(false, false))); | 65 std::unique_ptr<base::Timer>(new base::MockTimer(false, false))); |
71 } | 66 } |
72 ~DummyTaskManager() override {} | 67 ~DummyTaskManager() override {} |
(...skipping 18 matching lines...) Expand all Loading... |
91 | 86 |
92 default: | 87 default: |
93 return task_manager::Task::RENDERER; | 88 return task_manager::Task::RENDERER; |
94 } | 89 } |
95 } | 90 } |
96 | 91 |
97 void AddTaskFromIndex(size_t index) { | 92 void AddTaskFromIndex(size_t index) { |
98 tasks_[kTestTasks[index].id] = &kTestTasks[index]; | 93 tasks_[kTestTasks[index].id] = &kTestTasks[index]; |
99 } | 94 } |
100 | 95 |
101 void RemoveTask(TaskId id) { | |
102 NotifyObserversOnTaskToBeRemoved(id); | |
103 | |
104 tasks_.erase(id); | |
105 } | |
106 | |
107 void ManualRefresh() { | 96 void ManualRefresh() { |
108 ids_.clear(); | 97 ids_.clear(); |
109 for (const auto& pair : tasks_) { | 98 for (const auto& pair : tasks_) |
110 ids_.push_back(pair.first); | 99 ids_.push_back(pair.first); |
111 } | |
112 | 100 |
113 NotifyObserversOnRefresh(ids_); | 101 NotifyObserversOnRefreshWithBackgroundCalculations(ids_); |
114 } | 102 } |
115 | 103 |
116 private: | 104 private: |
117 std::map<TaskId, const ResourceReporter::TaskRecord*> tasks_; | 105 std::map<TaskId, const ResourceReporter::TaskRecord*> tasks_; |
118 | 106 |
119 DISALLOW_COPY_AND_ASSIGN(DummyTaskManager); | 107 DISALLOW_COPY_AND_ASSIGN(DummyTaskManager); |
120 }; | 108 }; |
121 | 109 |
| 110 class DummyMemoryPressureMonitor : public base::MemoryPressureMonitor { |
| 111 public: |
| 112 DummyMemoryPressureMonitor() |
| 113 : MemoryPressureMonitor(), |
| 114 memory_pressure_level_( |
| 115 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_NONE) {} |
| 116 ~DummyMemoryPressureMonitor() override {} |
| 117 |
| 118 void SetAndNotifyMemoryPressure(MemoryPressureLevel level) { |
| 119 memory_pressure_level_ = level; |
| 120 base::MemoryPressureListener::SimulatePressureNotification(level); |
| 121 } |
| 122 |
| 123 // base::CriticalMemoryPressureMonitor: |
| 124 MemoryPressureLevel GetCurrentPressureLevel() const override { |
| 125 return memory_pressure_level_; |
| 126 } |
| 127 void SetDispatchCallback(const DispatchCallback& callback) override {} |
| 128 |
| 129 private: |
| 130 MemoryPressureLevel memory_pressure_level_; |
| 131 |
| 132 DISALLOW_COPY_AND_ASSIGN(DummyMemoryPressureMonitor); |
| 133 }; |
| 134 |
122 } // namespace | 135 } // namespace |
123 | 136 |
124 class ResourceReporterTest : public testing::Test { | 137 class ResourceReporterTest : public testing::Test { |
125 public: | 138 public: |
126 ResourceReporterTest() {} | 139 ResourceReporterTest() {} |
127 ~ResourceReporterTest() override {} | 140 ~ResourceReporterTest() override {} |
128 | 141 |
129 // Start / Stop observing the task manager. | 142 void SetUp() override { |
130 void Start() { | 143 resource_reporter()->StartMonitoring(&task_manager_); |
131 task_manager_.AddObserver(resource_reporter()); | |
132 } | |
133 void Stop() { | |
134 task_manager_.RemoveObserver(resource_reporter()); | |
135 } | 144 } |
136 | 145 |
| 146 void TearDown() override { resource_reporter()->StopMonitoring(); } |
| 147 |
137 // Adds a number of tasks less than |kTopConsumersCount| to the task manager. | 148 // Adds a number of tasks less than |kTopConsumersCount| to the task manager. |
138 void AddInitialTasks() { | 149 void AddTasks() { |
139 for (size_t i = 0; i < kInitiallyAddedTasks; ++i) | 150 for (size_t i = 0; i < kTasksSize; ++i) |
140 task_manager_.AddTaskFromIndex(i); | 151 task_manager_.AddTaskFromIndex(i); |
141 } | 152 } |
142 | 153 |
143 // Adds all the remaining tasks to the task manager so that we have more than | |
144 // |kTopConsumersCount|. | |
145 void AddRemainingTasks() { | |
146 for (size_t i = kInitiallyAddedTasks; i < kTasksSize; ++i) | |
147 task_manager_.AddTaskFromIndex(i); | |
148 } | |
149 | |
150 // Remove the task with |id| from the task manager. | |
151 void RemoveTask(TaskId id) { | |
152 task_manager_.RemoveTask(id); | |
153 } | |
154 | |
155 // Manually refresh the task manager. | 154 // Manually refresh the task manager. |
156 void RefreshTaskManager() { | 155 void RefreshTaskManager() { |
157 task_manager_.ManualRefresh(); | 156 task_manager_.ManualRefresh(); |
158 } | 157 } |
159 | 158 |
160 // Tests that the task records in |ResourceReporter::task_records_by_cpu_| are | |
161 // properly sorted by the CPU usage in a descending order. | |
162 bool IsCpuRecordsSetSorted() const { | |
163 double current_cpu = std::numeric_limits<double>::max(); | |
164 for (auto* record : resource_reporter()->task_records_by_cpu_) { | |
165 if (record->cpu_percent > current_cpu) | |
166 return false; | |
167 current_cpu = record->cpu_percent; | |
168 } | |
169 | |
170 return true; | |
171 } | |
172 | |
173 // Tests that the task records in |ResourceReporter::task_records_by_memory_| | |
174 // are properly sorted by the memory usage in a descending order. | |
175 bool IsMemoryRecordsSetSorted() const { | |
176 int64_t current_memory = std::numeric_limits<int64_t>::max(); | |
177 for (auto* record : resource_reporter()->task_records_by_memory_) { | |
178 if (record->memory_bytes > current_memory) | |
179 return false; | |
180 current_memory = record->memory_bytes; | |
181 } | |
182 | |
183 return true; | |
184 } | |
185 | |
186 ResourceReporter* resource_reporter() const { | 159 ResourceReporter* resource_reporter() const { |
187 return ResourceReporter::GetInstance(); | 160 return ResourceReporter::GetInstance(); |
188 } | 161 } |
189 | 162 |
| 163 DummyMemoryPressureMonitor* monitor() { return &monitor_; } |
| 164 |
190 private: | 165 private: |
| 166 content::TestBrowserThreadBundle thread_bundle_; |
| 167 |
| 168 DummyMemoryPressureMonitor monitor_; |
| 169 |
191 DummyTaskManager task_manager_; | 170 DummyTaskManager task_manager_; |
192 | 171 |
193 DISALLOW_COPY_AND_ASSIGN(ResourceReporterTest); | 172 DISALLOW_COPY_AND_ASSIGN(ResourceReporterTest); |
194 }; | 173 }; |
195 | 174 |
196 // Tests that ResourceReporter::GetCpuRapporMetricName() returns the correct | 175 // Tests that ResourceReporter::GetCpuRapporMetricName() returns the correct |
197 // metric name that corresponds to the given CPU usage. | 176 // metric name that corresponds to the given CPU usage. |
198 TEST_F(ResourceReporterTest, TestGetCpuRapporMetricName) { | 177 TEST_F(ResourceReporterTest, TestGetCpuRapporMetricName) { |
199 EXPECT_EQ(ResourceReporter::CpuUsageRange::RANGE_0_TO_10_PERCENT, | 178 EXPECT_EQ(ResourceReporter::CpuUsageRange::RANGE_0_TO_10_PERCENT, |
200 ResourceReporter::GetCpuUsageRange(0.3)); | 179 ResourceReporter::GetCpuUsageRange(0.3)); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 EXPECT_EQ(ResourceReporter::MemoryUsageRange::RANGE_800_TO_1_GB, | 234 EXPECT_EQ(ResourceReporter::MemoryUsageRange::RANGE_800_TO_1_GB, |
256 ResourceReporter::GetMemoryUsageRange(1 * k1GB)); | 235 ResourceReporter::GetMemoryUsageRange(1 * k1GB)); |
257 | 236 |
258 EXPECT_EQ(ResourceReporter::MemoryUsageRange::RANGE_ABOVE_1_GB, | 237 EXPECT_EQ(ResourceReporter::MemoryUsageRange::RANGE_ABOVE_1_GB, |
259 ResourceReporter::GetMemoryUsageRange(1 * k1GB + 1 * k1KB)); | 238 ResourceReporter::GetMemoryUsageRange(1 * k1GB + 1 * k1KB)); |
260 } | 239 } |
261 | 240 |
262 // Tests all the interactions between the resource reporter and the task | 241 // Tests all the interactions between the resource reporter and the task |
263 // manager. | 242 // manager. |
264 TEST_F(ResourceReporterTest, TestAll) { | 243 TEST_F(ResourceReporterTest, TestAll) { |
265 // First start by making sure that our assumptions are correct. | 244 using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel; |
266 ASSERT_LT(kInitiallyAddedTasks, ResourceReporter::kTopConsumersCount); | |
267 ASSERT_LT(ResourceReporter::kTopConsumersCount, kTasksSize - 2); | |
268 ASSERT_LT(kTasksSize - kTasksToBeRemovedSize - 2, | |
269 ResourceReporter::kTopConsumersCount); | |
270 | 245 |
271 Start(); | 246 // Moderate memory pressure events should not trigger any sampling. |
| 247 monitor()->SetAndNotifyMemoryPressure( |
| 248 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); |
| 249 base::RunLoop().RunUntilIdle(); |
| 250 EXPECT_FALSE(resource_reporter()->observed_task_manager()); |
272 | 251 |
273 // Add the initial tasks to the task manager, and expect that after a refresh | 252 // A critical memory pressure event, but the task manager is not tracking any |
274 // that the resource reporter is already tracking them, and the records are | 253 // resource intensive tasks yet. |
275 // sorted properly. | 254 monitor()->SetAndNotifyMemoryPressure( |
276 AddInitialTasks(); | 255 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL); |
| 256 base::RunLoop().RunUntilIdle(); |
| 257 // We should keep listening to the task manager, even after a refresh. |
277 RefreshTaskManager(); | 258 RefreshTaskManager(); |
278 // Browser and GPU tasks won't be added. | 259 EXPECT_TRUE(resource_reporter()->observed_task_manager()); |
279 EXPECT_EQ(kInitiallyAddedTasks - 2, | |
280 resource_reporter()->task_records_.size()); | |
281 EXPECT_LE(resource_reporter()->task_records_by_cpu_.size(), | |
282 ResourceReporter::kTopConsumersCount); | |
283 EXPECT_LE(resource_reporter()->task_records_by_memory_.size(), | |
284 ResourceReporter::kTopConsumersCount); | |
285 EXPECT_TRUE(IsCpuRecordsSetSorted()); | |
286 EXPECT_TRUE(IsMemoryRecordsSetSorted()); | |
287 | 260 |
288 // After adding the remaining tasks which are more than |kTopConsumerCount|, | 261 // Memory pressure reduces to moderate again, we should stop watching the task |
289 // we must expect that the records used for recording the samples are EQUAL to | 262 // manager. |
290 // |kTopConsumerCount|, and the records are still properly sorted. | 263 monitor()->SetAndNotifyMemoryPressure( |
291 AddRemainingTasks(); | 264 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE); |
| 265 base::RunLoop().RunUntilIdle(); |
| 266 EXPECT_FALSE(resource_reporter()->observed_task_manager()); |
| 267 |
| 268 // Memory pressure becomes critical and we have violating tasks. |
| 269 AddTasks(); |
| 270 monitor()->SetAndNotifyMemoryPressure( |
| 271 MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL); |
| 272 base::RunLoop().RunUntilIdle(); |
| 273 EXPECT_TRUE(resource_reporter()->observed_task_manager()); |
292 RefreshTaskManager(); | 274 RefreshTaskManager(); |
293 EXPECT_EQ(kTasksSize - 2, resource_reporter()->task_records_.size()); | |
294 EXPECT_EQ(ResourceReporter::kTopConsumersCount, | |
295 resource_reporter()->task_records_by_cpu_.size()); | |
296 EXPECT_EQ(ResourceReporter::kTopConsumersCount, | |
297 resource_reporter()->task_records_by_memory_.size()); | |
298 EXPECT_TRUE(IsCpuRecordsSetSorted()); | |
299 EXPECT_TRUE(IsMemoryRecordsSetSorted()); | |
300 | 275 |
301 // Removing tasks from the task manager must result in their removal from the | 276 // Make sure that the ResourceReporter is no longer listening to the task |
302 // resource reporter immediately without having to wait until the next | 277 // manager right after the refresh. |
303 // refresh. | 278 EXPECT_FALSE(resource_reporter()->observed_task_manager()); |
304 for (const auto& id : kIdsOfTasksToRemove) | |
305 RemoveTask(id); | |
306 const size_t kExpectedTasksCount = kTasksSize - kTasksToBeRemovedSize - 2; | |
307 EXPECT_EQ(kExpectedTasksCount, resource_reporter()->task_records_.size()); | |
308 EXPECT_LE(resource_reporter()->task_records_by_cpu_.size(), | |
309 ResourceReporter::kTopConsumersCount); | |
310 EXPECT_LE(resource_reporter()->task_records_by_memory_.size(), | |
311 ResourceReporter::kTopConsumersCount); | |
312 EXPECT_TRUE(IsCpuRecordsSetSorted()); | |
313 EXPECT_TRUE(IsMemoryRecordsSetSorted()); | |
314 | 279 |
315 // After refresh nothing changes. | 280 // Make sure the ResourceReporter is not tracking any but the tasks exceeding |
316 RefreshTaskManager(); | 281 // the defined resource use thresholds. |
317 EXPECT_EQ(kExpectedTasksCount, resource_reporter()->task_records_.size()); | 282 ASSERT_FALSE(resource_reporter()->task_records_.empty()); |
318 EXPECT_LE(resource_reporter()->task_records_by_cpu_.size(), | 283 for (const auto& task_record : resource_reporter()->task_records_) { |
319 ResourceReporter::kTopConsumersCount); | 284 EXPECT_TRUE(task_record.cpu_percent >= |
320 EXPECT_LE(resource_reporter()->task_records_by_memory_.size(), | 285 ResourceReporter::kTaskCpuThresholdForReporting || |
321 ResourceReporter::kTopConsumersCount); | 286 task_record.memory_bytes >= |
322 EXPECT_TRUE(IsCpuRecordsSetSorted()); | 287 ResourceReporter::kTaskMemoryThresholdForReporting); |
323 EXPECT_TRUE(IsMemoryRecordsSetSorted()); | 288 } |
324 | 289 |
325 Stop(); | 290 // Make sure you have the right info about the Browser and GPU process. |
| 291 EXPECT_EQ(resource_reporter()->last_browser_process_cpu_, kBrowserProcessCpu); |
| 292 EXPECT_EQ(resource_reporter()->last_browser_process_memory_, |
| 293 kBrowserProcessMemory); |
| 294 EXPECT_EQ(resource_reporter()->last_gpu_process_cpu_, kGpuProcessCpu); |
| 295 EXPECT_EQ(resource_reporter()->last_gpu_process_memory_, kGpuProcessMemory); |
326 } | 296 } |
327 | 297 |
328 } // namespace chromeos | 298 } // namespace chromeos |
OLD | NEW |