OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <iomanip> | |
12 #include <iostream> | |
13 #include <vector> | |
14 | |
15 #if defined(WEBRTC_WIN) | |
16 #include "webrtc/base/win32.h" | |
17 #endif | |
18 | |
19 #include "webrtc/base/cpumonitor.h" | |
20 #include "webrtc/base/flags.h" | |
21 #include "webrtc/base/gunit.h" | |
22 #include "webrtc/base/scoped_ptr.h" | |
23 #include "webrtc/base/thread.h" | |
24 #include "webrtc/base/timeutils.h" | |
25 #include "webrtc/base/timing.h" | |
26 #include "webrtc/test/testsupport/gtest_disable.h" | |
27 | |
28 namespace rtc { | |
29 | |
30 static const int kMaxCpus = 1024; | |
31 static const int kSettleTime = 100; // Amount of time to between tests. | |
32 static const int kIdleTime = 500; // Amount of time to be idle in ms. | |
33 static const int kBusyTime = 1000; // Amount of time to be busy in ms. | |
34 static const int kLongInterval = 2000; // Interval longer than busy times | |
35 | |
36 class BusyThread : public rtc::Thread { | |
37 public: | |
38 BusyThread(double load, double duration, double interval) : | |
39 load_(load), duration_(duration), interval_(interval) { | |
40 } | |
41 virtual ~BusyThread() { | |
42 Stop(); | |
43 } | |
44 void Run() { | |
45 Timing time; | |
46 double busy_time = interval_ * load_ / 100.0; | |
47 for (;;) { | |
48 time.BusyWait(busy_time); | |
49 time.IdleWait(interval_ - busy_time); | |
50 if (duration_) { | |
51 duration_ -= interval_; | |
52 if (duration_ <= 0) { | |
53 break; | |
54 } | |
55 } | |
56 } | |
57 } | |
58 private: | |
59 double load_; | |
60 double duration_; | |
61 double interval_; | |
62 }; | |
63 | |
64 class CpuLoadListener : public sigslot::has_slots<> { | |
65 public: | |
66 CpuLoadListener() | |
67 : current_cpus_(0), | |
68 cpus_(0), | |
69 process_load_(.0f), | |
70 system_load_(.0f), | |
71 count_(0) { | |
72 } | |
73 | |
74 void OnCpuLoad(int current_cpus, int cpus, float proc_load, float sys_load) { | |
75 current_cpus_ = current_cpus; | |
76 cpus_ = cpus; | |
77 process_load_ = proc_load; | |
78 system_load_ = sys_load; | |
79 ++count_; | |
80 } | |
81 | |
82 int current_cpus() const { return current_cpus_; } | |
83 int cpus() const { return cpus_; } | |
84 float process_load() const { return process_load_; } | |
85 float system_load() const { return system_load_; } | |
86 int count() const { return count_; } | |
87 | |
88 private: | |
89 int current_cpus_; | |
90 int cpus_; | |
91 float process_load_; | |
92 float system_load_; | |
93 int count_; | |
94 }; | |
95 | |
96 // Set affinity (which cpu to run on), but respecting FLAG_affinity: | |
97 // -1 means no affinity - run on whatever cpu is available. | |
98 // 0 .. N means run on specific cpu. The tool will create N threads and call | |
99 // SetThreadAffinity on 0 to N - 1 as cpu. FLAG_affinity sets the first cpu | |
100 // so the range becomes affinity to affinity + N - 1 | |
101 // Note that this function affects Windows scheduling, effectively giving | |
102 // the thread with affinity for a specified CPU more priority on that CPU. | |
103 bool SetThreadAffinity(BusyThread* t, int cpu, int affinity) { | |
104 #if defined(WEBRTC_WIN) | |
105 if (affinity >= 0) { | |
106 return ::SetThreadAffinityMask(t->GetHandle(), | |
107 1 << (cpu + affinity)) != FALSE; | |
108 } | |
109 #endif | |
110 return true; | |
111 } | |
112 | |
113 bool SetThreadPriority(BusyThread* t, int prio) { | |
114 if (!prio) { | |
115 return true; | |
116 } | |
117 bool ok = t->SetPriority(static_cast<rtc::ThreadPriority>(prio)); | |
118 if (!ok) { | |
119 std::cout << "Error setting thread priority." << std::endl; | |
120 } | |
121 return ok; | |
122 } | |
123 | |
124 int CpuLoad(double cpuload, double duration, int numthreads, | |
125 int priority, double interval, int affinity) { | |
126 int ret = 0; | |
127 std::vector<BusyThread*> threads; | |
128 for (int i = 0; i < numthreads; ++i) { | |
129 threads.push_back(new BusyThread(cpuload, duration, interval)); | |
130 // NOTE(fbarchard): Priority must be done before Start. | |
131 if (!SetThreadPriority(threads[i], priority) || | |
132 !threads[i]->Start() || | |
133 !SetThreadAffinity(threads[i], i, affinity)) { | |
134 ret = 1; | |
135 break; | |
136 } | |
137 } | |
138 // Wait on each thread | |
139 if (ret == 0) { | |
140 for (int i = 0; i < numthreads; ++i) { | |
141 threads[i]->Stop(); | |
142 } | |
143 } | |
144 | |
145 for (int i = 0; i < numthreads; ++i) { | |
146 delete threads[i]; | |
147 } | |
148 return ret; | |
149 } | |
150 | |
151 // Make 2 CPUs busy | |
152 static void CpuTwoBusyLoop(int busytime) { | |
153 CpuLoad(100.0, busytime / 1000.0, 2, 1, 0.050, -1); | |
154 } | |
155 | |
156 // Make 1 CPUs busy | |
157 static void CpuBusyLoop(int busytime) { | |
158 CpuLoad(100.0, busytime / 1000.0, 1, 1, 0.050, -1); | |
159 } | |
160 | |
161 // Make 1 use half CPU time. | |
162 static void CpuHalfBusyLoop(int busytime) { | |
163 CpuLoad(50.0, busytime / 1000.0, 1, 1, 0.050, -1); | |
164 } | |
165 | |
166 void TestCpuSampler(bool test_proc, bool test_sys, bool force_fallback) { | |
167 CpuSampler sampler; | |
168 sampler.set_force_fallback(force_fallback); | |
169 EXPECT_TRUE(sampler.Init()); | |
170 sampler.set_load_interval(100); | |
171 int cpus = sampler.GetMaxCpus(); | |
172 | |
173 // Test1: CpuSampler under idle situation. | |
174 Thread::SleepMs(kSettleTime); | |
175 sampler.GetProcessLoad(); | |
176 sampler.GetSystemLoad(); | |
177 | |
178 Thread::SleepMs(kIdleTime); | |
179 | |
180 float proc_idle = 0.f, sys_idle = 0.f; | |
181 if (test_proc) { | |
182 proc_idle = sampler.GetProcessLoad(); | |
183 } | |
184 if (test_sys) { | |
185 sys_idle = sampler.GetSystemLoad(); | |
186 } | |
187 if (test_proc) { | |
188 LOG(LS_INFO) << "ProcessLoad Idle: " | |
189 << std::setiosflags(std::ios_base::fixed) | |
190 << std::setprecision(2) << std::setw(6) << proc_idle; | |
191 EXPECT_GE(proc_idle, 0.f); | |
192 EXPECT_LE(proc_idle, static_cast<float>(cpus)); | |
193 } | |
194 if (test_sys) { | |
195 LOG(LS_INFO) << "SystemLoad Idle: " | |
196 << std::setiosflags(std::ios_base::fixed) | |
197 << std::setprecision(2) << std::setw(6) << sys_idle; | |
198 EXPECT_GE(sys_idle, 0.f); | |
199 EXPECT_LE(sys_idle, static_cast<float>(cpus)); | |
200 } | |
201 | |
202 // Test2: CpuSampler with main process at 50% busy. | |
203 Thread::SleepMs(kSettleTime); | |
204 sampler.GetProcessLoad(); | |
205 sampler.GetSystemLoad(); | |
206 | |
207 CpuHalfBusyLoop(kBusyTime); | |
208 | |
209 float proc_halfbusy = 0.f, sys_halfbusy = 0.f; | |
210 if (test_proc) { | |
211 proc_halfbusy = sampler.GetProcessLoad(); | |
212 } | |
213 if (test_sys) { | |
214 sys_halfbusy = sampler.GetSystemLoad(); | |
215 } | |
216 if (test_proc) { | |
217 LOG(LS_INFO) << "ProcessLoad Halfbusy: " | |
218 << std::setiosflags(std::ios_base::fixed) | |
219 << std::setprecision(2) << std::setw(6) << proc_halfbusy; | |
220 EXPECT_GE(proc_halfbusy, 0.f); | |
221 EXPECT_LE(proc_halfbusy, static_cast<float>(cpus)); | |
222 } | |
223 if (test_sys) { | |
224 LOG(LS_INFO) << "SystemLoad Halfbusy: " | |
225 << std::setiosflags(std::ios_base::fixed) | |
226 << std::setprecision(2) << std::setw(6) << sys_halfbusy; | |
227 EXPECT_GE(sys_halfbusy, 0.f); | |
228 EXPECT_LE(sys_halfbusy, static_cast<float>(cpus)); | |
229 } | |
230 | |
231 // Test3: CpuSampler with main process busy. | |
232 Thread::SleepMs(kSettleTime); | |
233 sampler.GetProcessLoad(); | |
234 sampler.GetSystemLoad(); | |
235 | |
236 CpuBusyLoop(kBusyTime); | |
237 | |
238 float proc_busy = 0.f, sys_busy = 0.f; | |
239 if (test_proc) { | |
240 proc_busy = sampler.GetProcessLoad(); | |
241 } | |
242 if (test_sys) { | |
243 sys_busy = sampler.GetSystemLoad(); | |
244 } | |
245 if (test_proc) { | |
246 LOG(LS_INFO) << "ProcessLoad Busy: " | |
247 << std::setiosflags(std::ios_base::fixed) | |
248 << std::setprecision(2) << std::setw(6) << proc_busy; | |
249 EXPECT_GE(proc_busy, 0.f); | |
250 EXPECT_LE(proc_busy, static_cast<float>(cpus)); | |
251 } | |
252 if (test_sys) { | |
253 LOG(LS_INFO) << "SystemLoad Busy: " | |
254 << std::setiosflags(std::ios_base::fixed) | |
255 << std::setprecision(2) << std::setw(6) << sys_busy; | |
256 EXPECT_GE(sys_busy, 0.f); | |
257 EXPECT_LE(sys_busy, static_cast<float>(cpus)); | |
258 } | |
259 | |
260 // Test4: CpuSampler with 2 cpus process busy. | |
261 if (cpus >= 2) { | |
262 Thread::SleepMs(kSettleTime); | |
263 sampler.GetProcessLoad(); | |
264 sampler.GetSystemLoad(); | |
265 | |
266 CpuTwoBusyLoop(kBusyTime); | |
267 | |
268 float proc_twobusy = 0.f, sys_twobusy = 0.f; | |
269 if (test_proc) { | |
270 proc_twobusy = sampler.GetProcessLoad(); | |
271 } | |
272 if (test_sys) { | |
273 sys_twobusy = sampler.GetSystemLoad(); | |
274 } | |
275 if (test_proc) { | |
276 LOG(LS_INFO) << "ProcessLoad 2 CPU Busy:" | |
277 << std::setiosflags(std::ios_base::fixed) | |
278 << std::setprecision(2) << std::setw(6) << proc_twobusy; | |
279 EXPECT_GE(proc_twobusy, 0.f); | |
280 EXPECT_LE(proc_twobusy, static_cast<float>(cpus)); | |
281 } | |
282 if (test_sys) { | |
283 LOG(LS_INFO) << "SystemLoad 2 CPU Busy: " | |
284 << std::setiosflags(std::ios_base::fixed) | |
285 << std::setprecision(2) << std::setw(6) << sys_twobusy; | |
286 EXPECT_GE(sys_twobusy, 0.f); | |
287 EXPECT_LE(sys_twobusy, static_cast<float>(cpus)); | |
288 } | |
289 } | |
290 | |
291 // Test5: CpuSampler with idle process after being busy. | |
292 Thread::SleepMs(kSettleTime); | |
293 sampler.GetProcessLoad(); | |
294 sampler.GetSystemLoad(); | |
295 | |
296 Thread::SleepMs(kIdleTime); | |
297 | |
298 if (test_proc) { | |
299 proc_idle = sampler.GetProcessLoad(); | |
300 } | |
301 if (test_sys) { | |
302 sys_idle = sampler.GetSystemLoad(); | |
303 } | |
304 if (test_proc) { | |
305 LOG(LS_INFO) << "ProcessLoad Idle: " | |
306 << std::setiosflags(std::ios_base::fixed) | |
307 << std::setprecision(2) << std::setw(6) << proc_idle; | |
308 EXPECT_GE(proc_idle, 0.f); | |
309 EXPECT_LE(proc_idle, proc_busy); | |
310 } | |
311 if (test_sys) { | |
312 LOG(LS_INFO) << "SystemLoad Idle: " | |
313 << std::setiosflags(std::ios_base::fixed) | |
314 << std::setprecision(2) << std::setw(6) << sys_idle; | |
315 EXPECT_GE(sys_idle, 0.f); | |
316 EXPECT_LE(sys_idle, static_cast<float>(cpus)); | |
317 } | |
318 } | |
319 | |
320 TEST(CpuMonitorTest, TestCpus) { | |
321 CpuSampler sampler; | |
322 EXPECT_TRUE(sampler.Init()); | |
323 int current_cpus = sampler.GetCurrentCpus(); | |
324 int cpus = sampler.GetMaxCpus(); | |
325 LOG(LS_INFO) << "Current Cpus: " << std::setw(9) << current_cpus; | |
326 LOG(LS_INFO) << "Maximum Cpus: " << std::setw(9) << cpus; | |
327 EXPECT_GT(cpus, 0); | |
328 EXPECT_LE(cpus, kMaxCpus); | |
329 EXPECT_GT(current_cpus, 0); | |
330 EXPECT_LE(current_cpus, cpus); | |
331 } | |
332 | |
333 #if defined(WEBRTC_WIN) | |
334 // Tests overall system CpuSampler using legacy OS fallback code if applicable. | |
335 TEST(CpuMonitorTest, TestGetSystemLoadForceFallback) { | |
336 TestCpuSampler(false, true, true); | |
337 } | |
338 #endif | |
339 | |
340 // Tests both process and system functions in use at same time. | |
341 TEST(CpuMonitorTest, TestGetBothLoad) { | |
342 TestCpuSampler(true, true, false); | |
343 } | |
344 | |
345 // Tests a query less than the interval produces the same value. | |
346 TEST(CpuMonitorTest, TestInterval) { | |
347 CpuSampler sampler; | |
348 EXPECT_TRUE(sampler.Init()); | |
349 | |
350 // Test1: Set interval to large value so sampler will not update. | |
351 sampler.set_load_interval(kLongInterval); | |
352 | |
353 sampler.GetProcessLoad(); | |
354 sampler.GetSystemLoad(); | |
355 | |
356 float proc_orig = sampler.GetProcessLoad(); | |
357 float sys_orig = sampler.GetSystemLoad(); | |
358 | |
359 Thread::SleepMs(kIdleTime); | |
360 | |
361 float proc_halftime = sampler.GetProcessLoad(); | |
362 float sys_halftime = sampler.GetSystemLoad(); | |
363 | |
364 EXPECT_EQ(proc_orig, proc_halftime); | |
365 EXPECT_EQ(sys_orig, sys_halftime); | |
366 } | |
367 | |
368 TEST(CpuMonitorTest, TestCpuMonitor) { | |
369 CpuMonitor monitor(Thread::Current()); | |
370 CpuLoadListener listener; | |
371 monitor.SignalUpdate.connect(&listener, &CpuLoadListener::OnCpuLoad); | |
372 EXPECT_TRUE(monitor.Start(10)); | |
373 // We have checked cpu load more than twice. | |
374 EXPECT_TRUE_WAIT(listener.count() > 2, 1000); | |
375 EXPECT_GT(listener.current_cpus(), 0); | |
376 EXPECT_GT(listener.cpus(), 0); | |
377 EXPECT_GE(listener.process_load(), .0f); | |
378 EXPECT_GE(listener.system_load(), .0f); | |
379 | |
380 monitor.Stop(); | |
381 // Wait 20 ms to ake sure all signals are delivered. | |
382 Thread::Current()->ProcessMessages(20); | |
383 int old_count = listener.count(); | |
384 Thread::Current()->ProcessMessages(20); | |
385 // Verfy no more siganls. | |
386 EXPECT_EQ(old_count, listener.count()); | |
387 } | |
388 | |
389 } // namespace rtc | |
OLD | NEW |