1 /*
2  *  Copyright (c) 2012 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 "system_wrappers/interface/cpu_wrapper.h"
12 #include "system_wrappers/interface/event_wrapper.h"
13 #include "system_wrappers/interface/scoped_ptr.h"
14 #include "system_wrappers/source/cpu_measurement_harness.h"
15 
16 const int kCpuCheckPeriodMs = 100;
17 
18 namespace webrtc {
19 
Create(CpuTarget * target,int work_period_ms,int work_iterations_per_period,int duration_ms)20 CpuMeasurementHarness* CpuMeasurementHarness::Create(
21     CpuTarget* target,
22     int work_period_ms,
23     int work_iterations_per_period,
24     int duration_ms) {
25   if (target == NULL) {
26     return NULL;
27   }
28   if (work_period_ms > duration_ms) {
29     return NULL;
30   }
31   if (work_period_ms < 0) {
32     return NULL;
33   }
34   if (duration_ms < 0) {
35     return NULL;
36   }
37   if (work_iterations_per_period < 1) {
38     return NULL;
39   }
40   return new CpuMeasurementHarness(target, work_period_ms,
41                                    work_iterations_per_period, duration_ms);
42 }
43 
CpuMeasurementHarness(CpuTarget * target,int work_period_ms,int work_iterations_per_period,int duration_ms)44 CpuMeasurementHarness::CpuMeasurementHarness(CpuTarget* target,
45                                              int work_period_ms,
46                                              int work_iterations_per_period,
47                                              int duration_ms)
48     : cpu_target_(target),
49       work_period_ms_(work_period_ms),
50       work_iterations_per_period_(work_iterations_per_period),
51       duration_ms_(duration_ms),
52       cpu_sum_(0),
53       cpu_iterations_(0),
54       cpu_(CpuWrapper::CreateCpu()),
55       event_(EventWrapper::Create()) {
56 }
57 
~CpuMeasurementHarness()58 CpuMeasurementHarness::~CpuMeasurementHarness() {
59 }
60 
Run()61 bool CpuMeasurementHarness::Run() {
62   if (!WaitForCpuInit()) {
63     return false;
64   }
65   // No need for precision. Run for approximately the asked for duration.
66   // TODO(hellner): very low prio if at all, the actual duration of the test
67   // will be longer if calling DoWork() is not negligable and/or called many
68   // times. It may make sense to compensate for drift here. This will,
69   // however, only add complexity with minimal gains. Perhaps renaming the
70   // duration_ms_ to something more fuzzy is a better idea. However, the name
71   // would be very convoluted if it is to be self documenting.
72   int elapsed_time_ms = 0;
73   int last_measured_time = 0;
74   while (elapsed_time_ms < duration_ms_) {
75     if (((elapsed_time_ms - last_measured_time) / kCpuCheckPeriodMs) >= 1) {
76       last_measured_time = elapsed_time_ms;
77       Measure();
78     }
79     if (!DoWork()) {
80       return false;
81     }
82     event_->Wait(work_period_ms_);
83     elapsed_time_ms += work_period_ms_;
84   }
85   return true;
86 }
87 
AverageCpu()88 int CpuMeasurementHarness::AverageCpu() {
89   if (cpu_iterations_ == 0) {
90     return 0;
91   }
92   assert(cpu_sum_ >= 0);
93   assert(cpu_iterations_ >= 0);
94   return cpu_sum_ / cpu_iterations_;
95 }
96 
WaitForCpuInit()97 bool CpuMeasurementHarness::WaitForCpuInit() {
98   bool cpu_usage_available = false;
99   int num_iterations = 0;
100   // Initializing the CPU measurements may take a couple of seconds on Windows.
101   // Since the initialization is lazy we need to wait until it is completed.
102   // Should not take more than 10000 ms.
103   while (!cpu_usage_available && (++num_iterations < 10000)) {
104     event_->Wait(1);
105     cpu_usage_available = cpu_->CpuUsage() != -1;
106   }
107   return cpu_usage_available;
108 }
109 
Measure()110 void CpuMeasurementHarness::Measure() {
111   WebRtc_UWord32 num_cores = 0;
112   WebRtc_UWord32* cores = NULL;
113   // Return the average CPU for now.
114   cpu_sum_ = cpu_->CpuUsageMultiCore(num_cores, cores);
115   ++cpu_iterations_;
116 }
117 
DoWork()118 bool CpuMeasurementHarness::DoWork() {
119   for (int i = 0; i < work_iterations_per_period_; ++i) {
120     if (!cpu_target_->DoWork()) {
121       return false;
122     }
123   }
124   return true;
125 }
126 
127 }  // namespace webrtc
128