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