3
* Copyright 2010 Google Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
8
* 1. Redistributions of source code must retain the above copyright notice,
9
* this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
13
* 3. The name of the author may not be used to endorse or promote products
14
* derived from this software without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
#include "talk/base/win32.h"
36
#include "talk/base/cpumonitor.h"
37
#include "talk/base/flags.h"
38
#include "talk/base/gunit.h"
39
#include "talk/base/scoped_ptr.h"
40
#include "talk/base/thread.h"
41
#include "talk/base/timeutils.h"
42
#include "talk/base/timing.h"
46
static const int kMaxCpus = 1024;
47
static const int kSettleTime = 100; // Amount of time to between tests.
48
static const int kIdleTime = 500; // Amount of time to be idle in ms.
49
static const int kBusyTime = 1000; // Amount of time to be busy in ms.
50
static const int kLongInterval = 2000; // Interval longer than busy times
52
class BusyThread : public talk_base::Thread {
54
BusyThread(double load, double duration, double interval) :
55
load_(load), duration_(duration), interval_(interval) {
59
double busy_time = interval_ * load_ / 100.0;
61
time.BusyWait(busy_time);
62
time.IdleWait(interval_ - busy_time);
64
duration_ -= interval_;
77
class CpuLoadListener : public sigslot::has_slots<> {
87
void OnCpuLoad(int current_cpus, int cpus, float proc_load, float sys_load) {
88
current_cpus_ = current_cpus;
90
process_load_ = proc_load;
91
system_load_ = sys_load;
95
int current_cpus() const { return current_cpus_; }
96
int cpus() const { return cpus_; }
97
float process_load() const { return process_load_; }
98
float system_load() const { return system_load_; }
99
int count() const { return count_; }
109
// Set affinity (which cpu to run on), but respecting FLAG_affinity:
110
// -1 means no affinity - run on whatever cpu is available.
111
// 0 .. N means run on specific cpu. The tool will create N threads and call
112
// SetThreadAffinity on 0 to N - 1 as cpu. FLAG_affinity sets the first cpu
113
// so the range becomes affinity to affinity + N - 1
114
// Note that this function affects Windows scheduling, effectively giving
115
// the thread with affinity for a specified CPU more priority on that CPU.
116
bool SetThreadAffinity(BusyThread* t, int cpu, int affinity) {
119
return ::SetThreadAffinityMask(t->GetHandle(),
120
1 << (cpu + affinity)) != FALSE;
126
bool SetThreadPriority(BusyThread* t, int prio) {
130
bool ok = t->SetPriority(static_cast<talk_base::ThreadPriority>(prio));
132
std::cout << "Error setting thread priority." << std::endl;
137
int CpuLoad(double cpuload, double duration, int numthreads,
138
int priority, double interval, int affinity) {
140
std::vector<BusyThread*> threads;
141
for (int i = 0; i < numthreads; ++i) {
142
threads.push_back(new BusyThread(cpuload, duration, interval));
143
// NOTE(fbarchard): Priority must be done before Start.
144
if (!SetThreadPriority(threads[i], priority) ||
145
!threads[i]->Start() ||
146
!SetThreadAffinity(threads[i], i, affinity)) {
151
// Wait on each thread
153
for (int i = 0; i < numthreads; ++i) {
158
for (int i = 0; i < numthreads; ++i) {
165
static void CpuTwoBusyLoop(int busytime) {
166
CpuLoad(100.0, busytime / 1000.0, 2, 1, 0.050, -1);
170
static void CpuBusyLoop(int busytime) {
171
CpuLoad(100.0, busytime / 1000.0, 1, 1, 0.050, -1);
174
// Make 1 use half CPU time.
175
static void CpuHalfBusyLoop(int busytime) {
176
CpuLoad(50.0, busytime / 1000.0, 1, 1, 0.050, -1);
179
void TestCpuSampler(bool test_proc, bool test_sys, bool force_fallback) {
181
sampler.set_force_fallback(force_fallback);
182
EXPECT_TRUE(sampler.Init());
183
sampler.set_load_interval(100);
184
int cpus = sampler.GetMaxCpus();
186
// Test1: CpuSampler under idle situation.
187
Thread::SleepMs(kSettleTime);
188
sampler.GetProcessLoad();
189
sampler.GetSystemLoad();
191
Thread::SleepMs(kIdleTime);
193
float proc_idle = 0.f, sys_idle = 0.f;
195
proc_idle = sampler.GetProcessLoad();
198
sys_idle = sampler.GetSystemLoad();
201
LOG(LS_INFO) << "ProcessLoad Idle: "
202
<< setiosflags(std::ios_base::fixed)
203
<< std::setprecision(2) << std::setw(6) << proc_idle;
204
EXPECT_GE(proc_idle, 0.f);
205
EXPECT_LE(proc_idle, static_cast<float>(cpus));
208
LOG(LS_INFO) << "SystemLoad Idle: "
209
<< setiosflags(std::ios_base::fixed)
210
<< std::setprecision(2) << std::setw(6) << sys_idle;
211
EXPECT_GE(sys_idle, 0.f);
212
EXPECT_LE(sys_idle, static_cast<float>(cpus));
215
// Test2: CpuSampler with main process at 50% busy.
216
Thread::SleepMs(kSettleTime);
217
sampler.GetProcessLoad();
218
sampler.GetSystemLoad();
220
CpuHalfBusyLoop(kBusyTime);
222
float proc_halfbusy = 0.f, sys_halfbusy = 0.f;
224
proc_halfbusy = sampler.GetProcessLoad();
227
sys_halfbusy = sampler.GetSystemLoad();
230
LOG(LS_INFO) << "ProcessLoad Halfbusy: "
231
<< setiosflags(std::ios_base::fixed)
232
<< std::setprecision(2) << std::setw(6) << proc_halfbusy;
233
EXPECT_GE(proc_halfbusy, 0.f);
234
EXPECT_LE(proc_halfbusy, static_cast<float>(cpus));
237
LOG(LS_INFO) << "SystemLoad Halfbusy: "
238
<< setiosflags(std::ios_base::fixed)
239
<< std::setprecision(2) << std::setw(6) << sys_halfbusy;
240
EXPECT_GE(sys_halfbusy, 0.f);
241
EXPECT_LE(sys_halfbusy, static_cast<float>(cpus));
244
// Test3: CpuSampler with main process busy.
245
Thread::SleepMs(kSettleTime);
246
sampler.GetProcessLoad();
247
sampler.GetSystemLoad();
249
CpuBusyLoop(kBusyTime);
251
float proc_busy = 0.f, sys_busy = 0.f;
253
proc_busy = sampler.GetProcessLoad();
256
sys_busy = sampler.GetSystemLoad();
259
LOG(LS_INFO) << "ProcessLoad Busy: "
260
<< setiosflags(std::ios_base::fixed)
261
<< std::setprecision(2) << std::setw(6) << proc_busy;
262
EXPECT_GE(proc_busy, 0.f);
263
EXPECT_LE(proc_busy, static_cast<float>(cpus));
266
LOG(LS_INFO) << "SystemLoad Busy: "
267
<< setiosflags(std::ios_base::fixed)
268
<< std::setprecision(2) << std::setw(6) << sys_busy;
269
EXPECT_GE(sys_busy, 0.f);
270
EXPECT_LE(sys_busy, static_cast<float>(cpus));
273
// Test4: CpuSampler with 2 cpus process busy.
275
Thread::SleepMs(kSettleTime);
276
sampler.GetProcessLoad();
277
sampler.GetSystemLoad();
279
CpuTwoBusyLoop(kBusyTime);
281
float proc_twobusy = 0.f, sys_twobusy = 0.f;
283
proc_twobusy = sampler.GetProcessLoad();
286
sys_twobusy = sampler.GetSystemLoad();
289
LOG(LS_INFO) << "ProcessLoad 2 CPU Busy:"
290
<< setiosflags(std::ios_base::fixed)
291
<< std::setprecision(2) << std::setw(6) << proc_twobusy;
292
EXPECT_GE(proc_twobusy, 0.f);
293
EXPECT_LE(proc_twobusy, static_cast<float>(cpus));
296
LOG(LS_INFO) << "SystemLoad 2 CPU Busy: "
297
<< setiosflags(std::ios_base::fixed)
298
<< std::setprecision(2) << std::setw(6) << sys_twobusy;
299
EXPECT_GE(sys_twobusy, 0.f);
300
EXPECT_LE(sys_twobusy, static_cast<float>(cpus));
304
// Test5: CpuSampler with idle process after being busy.
305
Thread::SleepMs(kSettleTime);
306
sampler.GetProcessLoad();
307
sampler.GetSystemLoad();
309
Thread::SleepMs(kIdleTime);
312
proc_idle = sampler.GetProcessLoad();
315
sys_idle = sampler.GetSystemLoad();
318
LOG(LS_INFO) << "ProcessLoad Idle: "
319
<< setiosflags(std::ios_base::fixed)
320
<< std::setprecision(2) << std::setw(6) << proc_idle;
321
EXPECT_GE(proc_idle, 0.f);
322
EXPECT_LE(proc_idle, proc_busy);
325
LOG(LS_INFO) << "SystemLoad Idle: "
326
<< setiosflags(std::ios_base::fixed)
327
<< std::setprecision(2) << std::setw(6) << sys_idle;
328
EXPECT_GE(sys_idle, 0.f);
329
EXPECT_LE(sys_idle, static_cast<float>(cpus));
333
TEST(CpuMonitorTest, TestCpus) {
335
EXPECT_TRUE(sampler.Init());
336
int current_cpus = sampler.GetCurrentCpus();
337
int cpus = sampler.GetMaxCpus();
338
LOG(LS_INFO) << "Current Cpus: " << std::setw(9) << current_cpus;
339
LOG(LS_INFO) << "Maximum Cpus: " << std::setw(9) << cpus;
341
EXPECT_LE(cpus, kMaxCpus);
342
EXPECT_GT(current_cpus, 0);
343
EXPECT_LE(current_cpus, cpus);
347
// Tests overall system CpuSampler using legacy OS fallback code if applicable.
348
TEST(CpuMonitorTest, TestGetSystemLoadForceFallback) {
349
TestCpuSampler(false, true, true);
353
// Tests both process and system functions in use at same time.
354
TEST(CpuMonitorTest, TestGetBothLoad) {
355
TestCpuSampler(true, true, false);
358
// Tests a query less than the interval produces the same value.
359
TEST(CpuMonitorTest, TestInterval) {
361
EXPECT_TRUE(sampler.Init());
363
// Test1: Set interval to large value so sampler will not update.
364
sampler.set_load_interval(kLongInterval);
366
sampler.GetProcessLoad();
367
sampler.GetSystemLoad();
369
float proc_orig = sampler.GetProcessLoad();
370
float sys_orig = sampler.GetSystemLoad();
372
Thread::SleepMs(kIdleTime);
374
float proc_halftime = sampler.GetProcessLoad();
375
float sys_halftime = sampler.GetSystemLoad();
377
EXPECT_EQ(proc_orig, proc_halftime);
378
EXPECT_EQ(sys_orig, sys_halftime);
381
TEST(CpuMonitorTest, TestCpuMonitor) {
382
CpuMonitor monitor(Thread::Current());
383
CpuLoadListener listener;
384
monitor.SignalUpdate.connect(&listener, &CpuLoadListener::OnCpuLoad);
385
EXPECT_TRUE(monitor.Start(10));
386
Thread::Current()->ProcessMessages(50);
387
EXPECT_GT(listener.count(), 2); // We have checked cpu load more than twice.
388
EXPECT_GT(listener.current_cpus(), 0);
389
EXPECT_GT(listener.cpus(), 0);
390
EXPECT_GE(listener.process_load(), .0f);
391
EXPECT_GE(listener.system_load(), .0f);
394
// Wait 20 ms to ake sure all signals are delivered.
395
Thread::Current()->ProcessMessages(20);
396
int old_count = listener.count();
397
Thread::Current()->ProcessMessages(20);
398
// Verfy no more siganls.
399
EXPECT_EQ(old_count, listener.count());
402
} // namespace talk_base