Revert 3736 "Removed CPU APIs from VoEHardware. Code is now only..."

> Removed CPU APIs from VoEHardware. Code is now only used by test applications.
> 
> BUG=8404677
> 
> Review URL: https://webrtc-codereview.appspot.com/1238004

TBR=henrike@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/1267004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3737 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org 2013-03-27 23:38:21 +00:00
parent 4c138e8fca
commit 80fccc29de
22 changed files with 1611 additions and 3 deletions

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_
#include "typedefs.h"
namespace webrtc {
class CpuWrapper {
public:
static CpuWrapper* CreateCpu();
virtual ~CpuWrapper() {}
// Returns the average CPU usage for all processors. The CPU usage can be
// between and including 0 to 100 (%)
virtual WebRtc_Word32 CpuUsage() = 0;
virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* process_name,
WebRtc_UWord32 length) = 0;
virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 process_id) = 0;
// The CPU usage per core is returned in cpu_usage. The CPU can be between
// and including 0 to 100 (%)
// Note that the pointer passed as cpu_usage is redirected to a local member
// of the CPU wrapper.
// num_cores is the number of cores in the cpu_usage array.
// The return value is -1 for failure or 0-100, indicating the average
// CPU usage across all cores.
// Note: on some OSs this class is initialized lazy. This means that it
// might not yet be possible to retrieve any CPU metrics. When this happens
// the return value will be zero (indicating that there is not a failure),
// num_cores will be 0 and cpu_usage will be set to NULL (indicating that
// no metrics are available yet). Once the initialization is completed,
// which can take in the order of seconds, CPU metrics can be retrieved.
virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& cpu_usage) = 0;
virtual void Reset() = 0;
virtual void Stop() = 0;
protected:
CpuWrapper() {}
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_

View File

@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
aligned_malloc.cc \
atomic32_posix.cc \
condition_variable.cc \
cpu_no_op.cc \
cpu_features.cc \
cpu_info.cc \
critical_section.cc \

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "system_wrappers/interface/cpu_wrapper.h"
#if defined(_WIN32)
#include "cpu_win.h"
#elif defined(WEBRTC_MAC)
#include "cpu_mac.h"
#elif defined(WEBRTC_ANDROID)
// Not implemented yet, might be possible to use Linux implementation
#else // defined(WEBRTC_LINUX)
#include "cpu_linux.h"
#endif
namespace webrtc {
CpuWrapper* CpuWrapper::CreateCpu() {
#if defined(_WIN32)
return new CpuWindows();
#elif defined(WEBRTC_MAC)
return new CpuWrapperMac();
#elif defined(WEBRTC_ANDROID)
return 0;
#else
return new CpuLinux();
#endif
}
} // namespace webrtc

View File

@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/cpu_info.h"
#include "system_wrappers/interface/cpu_info.h"
#if defined(_WIN32)
#include <Windows.h>
@ -22,7 +22,7 @@
#include <sys/sysinfo.h>
#endif
#include "system_wrappers/interface/trace.h"
#include "trace.h"
namespace webrtc {

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "system_wrappers/source/cpu_linux.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
namespace webrtc {
CpuLinux::CpuLinux()
: old_busy_time_(0),
old_idle_time_(0),
old_busy_time_multi_(NULL),
old_idle_time_multi_(NULL),
idle_array_(NULL),
busy_array_(NULL),
result_array_(NULL),
num_cores_(0) {
const int result = GetNumCores();
if (result != -1) {
num_cores_ = result;
old_busy_time_multi_ = new long long[num_cores_];
memset(old_busy_time_multi_, 0, sizeof(long long) * num_cores_);
old_idle_time_multi_ = new long long[num_cores_];
memset(old_idle_time_multi_, 0, sizeof(long long) * num_cores_);
idle_array_ = new long long[num_cores_];
memset(idle_array_, 0, sizeof(long long) * num_cores_);
busy_array_ = new long long[num_cores_];
memset(busy_array_, 0, sizeof(long long) * num_cores_);
result_array_ = new WebRtc_UWord32[num_cores_];
GetData(old_busy_time_, old_idle_time_, busy_array_, idle_array_);
}
}
CpuLinux::~CpuLinux() {
delete [] old_busy_time_multi_;
delete [] old_idle_time_multi_;
delete [] idle_array_;
delete [] busy_array_;
delete [] result_array_;
}
WebRtc_Word32 CpuLinux::CpuUsage() {
WebRtc_UWord32 dummy = 0;
WebRtc_UWord32* dummy_array = NULL;
return CpuUsageMultiCore(dummy, dummy_array);
}
WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& core_array) {
core_array = result_array_;
num_cores = num_cores_;
long long busy = 0;
long long idle = 0;
if (GetData(busy, idle, busy_array_, idle_array_) != 0)
return -1;
long long delta_busy = busy - old_busy_time_;
long long delta_idle = idle - old_idle_time_;
old_busy_time_ = busy;
old_idle_time_ = idle;
int ret_val = -1;
if (delta_busy + delta_idle == 0) {
ret_val = 0;
} else {
ret_val = (int)(100 * (delta_busy) / (delta_busy + delta_idle));
}
if (core_array == NULL) {
return ret_val;
}
for (WebRtc_UWord32 i = 0; i < num_cores_; ++i) {
delta_busy = busy_array_[i] - old_busy_time_multi_[i];
delta_idle = idle_array_[i] - old_idle_time_multi_[i];
old_busy_time_multi_[i] = busy_array_[i];
old_idle_time_multi_[i] = idle_array_[i];
if (delta_busy + delta_idle == 0) {
core_array[i] = 0;
} else {
core_array[i] = (int)(100 * (delta_busy) / (delta_busy + delta_idle));
}
}
return ret_val;
}
int CpuLinux::GetData(long long& busy, long long& idle, long long*& busy_array,
long long*& idle_array) {
FILE* fp = fopen("/proc/stat", "r");
if (!fp) {
return -1;
}
char line[100];
if (fgets(line, 100, fp) == NULL) {
fclose(fp);
return -1;
}
char first_word[100];
if (sscanf(line, "%s ", first_word) != 1) {
fclose(fp);
return -1;
}
if (strncmp(first_word, "cpu", 3) != 0) {
fclose(fp);
return -1;
}
char s_user[100];
char s_nice[100];
char s_system[100];
char s_idle[100];
if (sscanf(line, "%s %s %s %s %s ",
first_word, s_user, s_nice, s_system, s_idle) != 5) {
fclose(fp);
return -1;
}
long long luser = atoll(s_user);
long long lnice = atoll(s_nice);
long long lsystem = atoll(s_system);
long long lidle = atoll(s_idle);
busy = luser + lnice + lsystem;
idle = lidle;
for (WebRtc_UWord32 i = 0; i < num_cores_; ++i) {
if (fgets(line, 100, fp) == NULL) {
fclose(fp);
return -1;
}
if (sscanf(line, "%s %s %s %s %s ", first_word, s_user, s_nice, s_system,
s_idle) != 5) {
fclose(fp);
return -1;
}
luser = atoll(s_user);
lnice = atoll(s_nice);
lsystem = atoll(s_system);
lidle = atoll(s_idle);
busy_array[i] = luser + lnice + lsystem;
idle_array[i] = lidle;
}
fclose(fp);
return 0;
}
int CpuLinux::GetNumCores() {
FILE* fp = fopen("/proc/stat", "r");
if (!fp) {
return -1;
}
// Skip first line
char line[100];
if (!fgets(line, 100, fp)) {
fclose(fp);
return -1;
}
int num_cores = -1;
char first_word[100];
do {
num_cores++;
if (fgets(line, 100, fp)) {
if (sscanf(line, "%s ", first_word) != 1) {
first_word[0] = '\0';
}
} else {
break;
}
} while (strncmp(first_word, "cpu", 3) == 0);
fclose(fp);
return num_cores;
}
} // namespace webrtc

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_
#include "system_wrappers/interface/cpu_wrapper.h"
namespace webrtc {
class CpuLinux : public CpuWrapper {
public:
CpuLinux();
virtual ~CpuLinux();
virtual WebRtc_Word32 CpuUsage();
virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* process_name,
WebRtc_UWord32 length) {
return 0;
}
virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 process_id) {
return 0;
}
virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& array);
virtual void Reset() {
return;
}
virtual void Stop() {
return;
}
private:
int GetData(long long& busy, long long& idle, long long*& busy_array,
long long*& idle_array);
int GetNumCores();
long long old_busy_time_;
long long old_idle_time_;
long long* old_busy_time_multi_;
long long* old_idle_time_multi_;
long long* idle_array_;
long long* busy_array_;
WebRtc_UWord32* result_array_;
WebRtc_UWord32 num_cores_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "system_wrappers/source/cpu_mac.h"
#include <iostream>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include "tick_util.h"
namespace webrtc {
CpuWrapperMac::CpuWrapperMac()
: cpu_count_(0),
cpu_usage_(NULL),
total_cpu_usage_(0),
last_tick_count_(NULL),
last_time_(0) {
natural_t cpu_count;
processor_info_array_t info_array;
mach_msg_type_number_t info_count;
kern_return_t error = host_processor_info(mach_host_self(),
PROCESSOR_CPU_LOAD_INFO,
&cpu_count,
&info_array,
&info_count);
if (error) {
return;
}
cpu_count_ = cpu_count;
cpu_usage_ = new WebRtc_UWord32[cpu_count];
last_tick_count_ = new WebRtc_Word64[cpu_count];
last_time_ = TickTime::MillisecondTimestamp();
processor_cpu_load_info_data_t* cpu_load_info =
(processor_cpu_load_info_data_t*) info_array;
for (unsigned int cpu = 0; cpu < cpu_count; ++cpu) {
WebRtc_Word64 ticks = 0;
for (int state = 0; state < 2; ++state) {
ticks += cpu_load_info[cpu].cpu_ticks[state];
}
last_tick_count_[cpu] = ticks;
cpu_usage_[cpu] = 0;
}
vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count);
}
CpuWrapperMac::~CpuWrapperMac() {
delete[] cpu_usage_;
delete[] last_tick_count_;
}
WebRtc_Word32 CpuWrapperMac::CpuUsage() {
WebRtc_UWord32 num_cores;
WebRtc_UWord32* array = NULL;
return CpuUsageMultiCore(num_cores, array);
}
WebRtc_Word32
CpuWrapperMac::CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& array) {
// sanity check
if (cpu_usage_ == NULL) {
return -1;
}
WebRtc_Word64 now = TickTime::MillisecondTimestamp();
WebRtc_Word64 time_diff_ms = now - last_time_;
if (time_diff_ms >= 500) {
if (Update(time_diff_ms) != 0) {
return -1;
}
last_time_ = now;
}
num_cores = cpu_count_;
array = cpu_usage_;
return total_cpu_usage_ / cpu_count_;
}
WebRtc_Word32 CpuWrapperMac::Update(WebRtc_Word64 time_diff_ms) {
natural_t cpu_count;
processor_info_array_t info_array;
mach_msg_type_number_t info_count;
kern_return_t error = host_processor_info(mach_host_self(),
PROCESSOR_CPU_LOAD_INFO,
&cpu_count,
&info_array,
&info_count);
if (error) {
return -1;
}
processor_cpu_load_info_data_t* cpu_load_info =
(processor_cpu_load_info_data_t*) info_array;
total_cpu_usage_ = 0;
for (unsigned int cpu = 0; cpu < cpu_count; ++cpu) {
WebRtc_Word64 ticks = 0;
for (int state = 0; state < 2; ++state) {
ticks += cpu_load_info[cpu].cpu_ticks[state];
}
if (time_diff_ms <= 0) {
cpu_usage_[cpu] = 0;
} else {
cpu_usage_[cpu] = (WebRtc_UWord32)((1000 *
(ticks - last_tick_count_[cpu])) /
time_diff_ms);
}
last_tick_count_[cpu] = ticks;
total_cpu_usage_ += cpu_usage_[cpu];
}
vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count);
return 0;
}
} // namespace webrtc

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_
#include "system_wrappers/interface/cpu_wrapper.h"
namespace webrtc {
class CpuWrapperMac : public CpuWrapper {
public:
CpuWrapperMac();
virtual ~CpuWrapperMac();
virtual WebRtc_Word32 CpuUsage();
virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* process_name,
WebRtc_UWord32 length) {
return -1;
}
virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 process_id) {
return -1;
}
// Note: this class will block the call and sleep if called too fast
// This function blocks the calling thread if the thread is calling it more
// often than every 500 ms.
virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& array);
virtual void Reset() {}
virtual void Stop() {}
private:
WebRtc_Word32 Update(WebRtc_Word64 time_diffMS);
WebRtc_UWord32 cpu_count_;
WebRtc_UWord32* cpu_usage_;
WebRtc_Word32 total_cpu_usage_;
WebRtc_Word64* last_tick_count_;
WebRtc_Word64 last_time_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "system_wrappers/interface/cpu_wrapper.h"
#include "system_wrappers/interface/event_wrapper.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "system_wrappers/source/cpu_measurement_harness.h"
const int kCpuCheckPeriodMs = 100;
namespace webrtc {
CpuMeasurementHarness* CpuMeasurementHarness::Create(
CpuTarget* target,
int work_period_ms,
int work_iterations_per_period,
int duration_ms) {
if (target == NULL) {
return NULL;
}
if (work_period_ms > duration_ms) {
return NULL;
}
if (work_period_ms < 0) {
return NULL;
}
if (duration_ms < 0) {
return NULL;
}
if (work_iterations_per_period < 1) {
return NULL;
}
return new CpuMeasurementHarness(target, work_period_ms,
work_iterations_per_period, duration_ms);
}
CpuMeasurementHarness::CpuMeasurementHarness(CpuTarget* target,
int work_period_ms,
int work_iterations_per_period,
int duration_ms)
: cpu_target_(target),
work_period_ms_(work_period_ms),
work_iterations_per_period_(work_iterations_per_period),
duration_ms_(duration_ms),
cpu_sum_(0),
cpu_iterations_(0),
cpu_(CpuWrapper::CreateCpu()),
event_(EventWrapper::Create()) {
}
CpuMeasurementHarness::~CpuMeasurementHarness() {
}
bool CpuMeasurementHarness::Run() {
if (!WaitForCpuInit()) {
return false;
}
// No need for precision. Run for approximately the asked for duration.
// TODO(hellner): very low prio if at all, the actual duration of the test
// will be longer if calling DoWork() is not negligable and/or called many
// times. It may make sense to compensate for drift here. This will,
// however, only add complexity with minimal gains. Perhaps renaming the
// duration_ms_ to something more fuzzy is a better idea. However, the name
// would be very convoluted if it is to be self documenting.
int elapsed_time_ms = 0;
int last_measured_time = 0;
while (elapsed_time_ms < duration_ms_) {
if (((elapsed_time_ms - last_measured_time) / kCpuCheckPeriodMs) >= 1) {
last_measured_time = elapsed_time_ms;
Measure();
}
if (!DoWork()) {
return false;
}
event_->Wait(work_period_ms_);
elapsed_time_ms += work_period_ms_;
}
return true;
}
int CpuMeasurementHarness::AverageCpu() {
if (cpu_iterations_ == 0) {
return 0;
}
assert(cpu_sum_ >= 0);
assert(cpu_iterations_ >= 0);
return cpu_sum_ / cpu_iterations_;
}
bool CpuMeasurementHarness::WaitForCpuInit() {
bool cpu_usage_available = false;
int num_iterations = 0;
// Initializing the CPU measurements may take a couple of seconds on Windows.
// Since the initialization is lazy we need to wait until it is completed.
// Should not take more than 10000 ms.
while (!cpu_usage_available && (++num_iterations < 10000)) {
event_->Wait(1);
cpu_usage_available = cpu_->CpuUsage() != -1;
}
return cpu_usage_available;
}
void CpuMeasurementHarness::Measure() {
WebRtc_UWord32 num_cores = 0;
WebRtc_UWord32* cores = NULL;
// Return the average CPU for now.
cpu_sum_ = cpu_->CpuUsageMultiCore(num_cores, cores);
++cpu_iterations_;
}
bool CpuMeasurementHarness::DoWork() {
for (int i = 0; i < work_iterations_per_period_; ++i) {
if (!cpu_target_->DoWork()) {
return false;
}
}
return true;
}
} // namespace webrtc

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_
#define SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_
#include "system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
class CpuWrapper;
class EventWrapper;
class ThreadWrapper;
// This abstract class provides an interface that should be passed to
// CpuMeasurementHarness. CpuMeasurementHarness will call it with the
// frequency requested and measure the CPU usage for all calls.
class CpuTarget {
public:
// Callback function for which the CPU usage should be calculated.
virtual bool DoWork() = 0;
protected:
CpuTarget() {}
virtual ~CpuTarget() {}
};
class CpuMeasurementHarness {
public:
static CpuMeasurementHarness* Create(CpuTarget* target,
int work_period_ms,
int work_iterations_per_period,
int duration_ms);
~CpuMeasurementHarness();
bool Run();
int AverageCpu();
protected:
CpuMeasurementHarness(CpuTarget* target, int work_period_ms,
int work_iterations_per_period, int duration_ms);
private:
bool WaitForCpuInit();
void Measure();
bool DoWork();
CpuTarget* cpu_target_;
const int work_period_ms_;
const int work_iterations_per_period_;
const int duration_ms_;
int cpu_sum_;
int cpu_iterations_;
scoped_ptr<CpuWrapper> cpu_;
scoped_ptr<EventWrapper> event_;
};
} // namespace webrtc
#endif // SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "system_wrappers/interface/cpu_wrapper.h"
#include <stddef.h>
namespace webrtc {
CpuWrapper* CpuWrapper::CreateCpu() {
return NULL;
}
} // namespace webrtc

View File

@ -0,0 +1,526 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "cpu_win.h"
#define _WIN32_DCOM
#include <assert.h>
#include <iostream>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#include "condition_variable_wrapper.h"
#include "critical_section_wrapper.h"
#include "event_wrapper.h"
#include "thread_wrapper.h"
namespace webrtc {
WebRtc_Word32 CpuWindows::CpuUsage()
{
if (!has_initialized_)
{
return -1;
}
// Last element is the average
return cpu_usage_[number_of_objects_ - 1];
}
WebRtc_Word32 CpuWindows::CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& cpu_usage)
{
if (has_terminated_) {
num_cores = 0;
cpu_usage = NULL;
return -1;
}
if (!has_initialized_)
{
num_cores = 0;
cpu_usage = NULL;
return -1;
}
num_cores = number_of_objects_ - 1;
cpu_usage = cpu_usage_;
return cpu_usage_[number_of_objects_-1];
}
CpuWindows::CpuWindows()
: cpu_polling_thread(NULL),
initialize_(true),
has_initialized_(false),
terminate_(false),
has_terminated_(false),
cpu_usage_(NULL),
wbem_enum_access_(NULL),
number_of_objects_(0),
cpu_usage_handle_(0),
previous_processor_timestamp_(NULL),
timestamp_sys_100_ns_handle_(0),
previous_100ns_timestamp_(NULL),
wbem_service_(NULL),
wbem_service_proxy_(NULL),
wbem_refresher_(NULL),
wbem_enum_(NULL)
{
// All resources are allocated in PollingCpu().
if (AllocateComplexDataTypes())
{
StartPollingCpu();
}
else
{
assert(false);
}
}
CpuWindows::~CpuWindows()
{
// All resources are reclaimed in StopPollingCpu().
StopPollingCpu();
DeAllocateComplexDataTypes();
}
bool CpuWindows::AllocateComplexDataTypes()
{
cpu_polling_thread = ThreadWrapper::CreateThread(
CpuWindows::Process,
reinterpret_cast<void*>(this),
kNormalPriority,
"CpuWindows");
init_crit_ = CriticalSectionWrapper::CreateCriticalSection();
init_cond_ = ConditionVariableWrapper::CreateConditionVariable();
terminate_crit_ = CriticalSectionWrapper::CreateCriticalSection();
terminate_cond_ = ConditionVariableWrapper::CreateConditionVariable();
sleep_event = EventWrapper::Create();
return (cpu_polling_thread != NULL) && (init_crit_ != NULL) &&
(init_cond_ != NULL) && (terminate_crit_ != NULL) &&
(terminate_cond_ != NULL) && (sleep_event != NULL);
}
void CpuWindows::DeAllocateComplexDataTypes()
{
if (sleep_event != NULL)
{
delete sleep_event;
sleep_event = NULL;
}
if (terminate_cond_ != NULL)
{
delete terminate_cond_;
terminate_cond_ = NULL;
}
if (terminate_crit_ != NULL)
{
delete terminate_crit_;
terminate_crit_ = NULL;
}
if (init_cond_ != NULL)
{
delete init_cond_;
init_cond_ = NULL;
}
if (init_crit_ != NULL)
{
delete init_crit_;
init_crit_ = NULL;
}
if (cpu_polling_thread != NULL)
{
delete cpu_polling_thread;
cpu_polling_thread = NULL;
}
}
void CpuWindows::StartPollingCpu()
{
unsigned int dummy_id = 0;
if (!cpu_polling_thread->Start(dummy_id))
{
initialize_ = false;
has_terminated_ = true;
assert(false);
}
}
bool CpuWindows::StopPollingCpu()
{
{
// If StopPollingCpu is called immediately after StartPollingCpu() it is
// possible that cpu_polling_thread is in the process of initializing.
// Let initialization finish to avoid getting into a bad state.
CriticalSectionScoped cs(init_crit_);
while(initialize_)
{
init_cond_->SleepCS(*init_crit_);
}
}
CriticalSectionScoped cs(terminate_crit_);
terminate_ = true;
sleep_event->Set();
while (!has_terminated_)
{
terminate_cond_->SleepCS(*terminate_crit_);
}
cpu_polling_thread->Stop();
delete cpu_polling_thread;
cpu_polling_thread = NULL;
return true;
}
bool CpuWindows::Process(void* thread_object)
{
return reinterpret_cast<CpuWindows*>(thread_object)->ProcessImpl();
}
bool CpuWindows::ProcessImpl()
{
{
CriticalSectionScoped cs(terminate_crit_);
if (terminate_)
{
Terminate();
terminate_cond_->WakeAll();
return false;
}
}
// Initialize on first iteration
if (initialize_)
{
CriticalSectionScoped cs(init_crit_);
initialize_ = false;
const bool success = Initialize();
init_cond_->WakeAll();
if (!success || !has_initialized_)
{
has_initialized_ = false;
terminate_ = true;
return true;
}
}
// Approximately one seconds sleep for each CPU measurement. Precision is
// not important. 1 second refresh rate is also used by Performance Monitor
// (perfmon).
if(kEventTimeout != sleep_event->Wait(1000))
{
// Terminating. No need to update CPU usage.
assert(terminate_);
return true;
}
// UpdateCpuUsage() returns false if a single (or more) CPU read(s) failed.
// Not a major problem if it happens.
UpdateCpuUsage();
return true;
}
bool CpuWindows::CreateWmiConnection()
{
IWbemLocator* service_locator = NULL;
HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL,
CLSCTX_INPROC_SERVER, IID_IWbemLocator,
reinterpret_cast<void**> (&service_locator));
if (FAILED(hr))
{
return false;
}
// To get the WMI service specify the WMI namespace.
BSTR wmi_namespace = SysAllocString(L"\\\\.\\root\\cimv2");
if (wmi_namespace == NULL)
{
// This type of failure signifies running out of memory.
service_locator->Release();
return false;
}
hr = service_locator->ConnectServer(wmi_namespace, NULL, NULL, NULL, 0L,
NULL, NULL, &wbem_service_);
SysFreeString(wmi_namespace);
service_locator->Release();
return !FAILED(hr);
}
// Sets up WMI refresher and enum
bool CpuWindows::CreatePerfOsRefresher()
{
// Create refresher.
HRESULT hr = CoCreateInstance(CLSID_WbemRefresher, NULL,
CLSCTX_INPROC_SERVER, IID_IWbemRefresher,
reinterpret_cast<void**> (&wbem_refresher_));
if (FAILED(hr))
{
return false;
}
// Create PerfOS_Processor enum.
IWbemConfigureRefresher* wbem_refresher_config = NULL;
hr = wbem_refresher_->QueryInterface(
IID_IWbemConfigureRefresher,
reinterpret_cast<void**> (&wbem_refresher_config));
if (FAILED(hr))
{
return false;
}
// Create a proxy to the IWbemServices so that a local authentication
// can be set up (this is needed to be able to successfully call
// IWbemConfigureRefresher::AddEnum). Setting authentication with
// CoInitializeSecurity is process-wide (which is too intrusive).
hr = CoCopyProxy(static_cast<IUnknown*> (wbem_service_),
reinterpret_cast<IUnknown**> (&wbem_service_proxy_));
if(FAILED(hr))
{
return false;
}
// Set local authentication.
// RPC_C_AUTHN_WINNT means using NTLM instead of Kerberos which is default.
hr = CoSetProxyBlanket(static_cast<IUnknown*> (wbem_service_proxy_),
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if(FAILED(hr))
{
return false;
}
// Don't care about the particular id for the enum.
long enum_id = 0;
hr = wbem_refresher_config->AddEnum(wbem_service_proxy_,
L"Win32_PerfRawData_PerfOS_Processor",
0, NULL, &wbem_enum_, &enum_id);
wbem_refresher_config->Release();
wbem_refresher_config = NULL;
return !FAILED(hr);
}
// Have to pull the first round of data to be able set the handles.
bool CpuWindows::CreatePerfOsCpuHandles()
{
// Update the refresher so that there is data available in wbem_enum_.
wbem_refresher_->Refresh(0L);
// The number of enumerators is the number of processor + 1 (the total).
// This is unknown at this point.
DWORD number_returned = 0;
HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_,
wbem_enum_access_, &number_returned);
// number_returned indicates the number of enumerators that are needed.
if (hr == WBEM_E_BUFFER_TOO_SMALL &&
number_returned > number_of_objects_)
{
// Allocate the number IWbemObjectAccess asked for by the
// GetObjects(..) function.
wbem_enum_access_ = new IWbemObjectAccess*[number_returned];
cpu_usage_ = new WebRtc_UWord32[number_returned];
previous_processor_timestamp_ = new unsigned __int64[number_returned];
previous_100ns_timestamp_ = new unsigned __int64[number_returned];
if ((wbem_enum_access_ == NULL) || (cpu_usage_ == NULL) ||
(previous_processor_timestamp_ == NULL) ||
(previous_100ns_timestamp_ == NULL))
{
// Out of memory.
return false;
}
SecureZeroMemory(wbem_enum_access_, number_returned *
sizeof(IWbemObjectAccess*));
memset(cpu_usage_, 0, sizeof(int) * number_returned);
memset(previous_processor_timestamp_, 0, sizeof(unsigned __int64) *
number_returned);
memset(previous_100ns_timestamp_, 0, sizeof(unsigned __int64) *
number_returned);
number_of_objects_ = number_returned;
// Read should be successfull now that memory has been allocated.
hr = wbem_enum_->GetObjects(0L, number_of_objects_, wbem_enum_access_,
&number_returned);
if (FAILED(hr))
{
return false;
}
}
else
{
// 0 enumerators should not be enough. Something has gone wrong here.
return false;
}
// Get the enumerator handles that are needed for calculating CPU usage.
CIMTYPE cpu_usage_type;
hr = wbem_enum_access_[0]->GetPropertyHandle(L"PercentProcessorTime",
&cpu_usage_type,
&cpu_usage_handle_);
if (FAILED(hr))
{
return false;
}
CIMTYPE timestamp_sys_100_ns_type;
hr = wbem_enum_access_[0]->GetPropertyHandle(L"TimeStamp_Sys100NS",
&timestamp_sys_100_ns_type,
&timestamp_sys_100_ns_handle_);
return !FAILED(hr);
}
bool CpuWindows::Initialize()
{
if (terminate_)
{
return false;
}
// Initialize COM library.
HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if (FAILED(hr))
{
return false;
}
if (!CreateWmiConnection())
{
return false;
}
if (!CreatePerfOsRefresher())
{
return false;
}
if (!CreatePerfOsCpuHandles())
{
return false;
}
has_initialized_ = true;
return true;
}
bool CpuWindows::Terminate()
{
if (has_terminated_)
{
return false;
}
// Reverse order of Initialize().
// Some compilers complain about deleting NULL though it's well defined
if (previous_100ns_timestamp_ != NULL)
{
delete[] previous_100ns_timestamp_;
previous_100ns_timestamp_ = NULL;
}
if (previous_processor_timestamp_ != NULL)
{
delete[] previous_processor_timestamp_;
previous_processor_timestamp_ = NULL;
}
if (cpu_usage_ != NULL)
{
delete[] cpu_usage_;
cpu_usage_ = NULL;
}
if (wbem_enum_access_ != NULL)
{
for (DWORD i = 0; i < number_of_objects_; i++)
{
if(wbem_enum_access_[i] != NULL)
{
wbem_enum_access_[i]->Release();
}
}
delete[] wbem_enum_access_;
wbem_enum_access_ = NULL;
}
if (wbem_enum_ != NULL)
{
wbem_enum_->Release();
wbem_enum_ = NULL;
}
if (wbem_refresher_ != NULL)
{
wbem_refresher_->Release();
wbem_refresher_ = NULL;
}
if (wbem_service_proxy_ != NULL)
{
wbem_service_proxy_->Release();
wbem_service_proxy_ = NULL;
}
if (wbem_service_ != NULL)
{
wbem_service_->Release();
wbem_service_ = NULL;
}
// CoUninitialized should be called once for every CoInitializeEx.
// Regardless if it failed or not.
CoUninitialize();
has_terminated_ = true;
return true;
}
bool CpuWindows::UpdateCpuUsage()
{
wbem_refresher_->Refresh(0L);
DWORD number_returned = 0;
HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_,
wbem_enum_access_,&number_returned);
if (FAILED(hr))
{
// wbem_enum_access_ has already been allocated. Unless the number of
// CPUs change runtime this should not happen.
return false;
}
unsigned __int64 cpu_usage = 0;
unsigned __int64 timestamp_100ns = 0;
bool returnValue = true;
for (DWORD i = 0; i < number_returned; i++)
{
hr = wbem_enum_access_[i]->ReadQWORD(cpu_usage_handle_,&cpu_usage);
if (FAILED(hr))
{
returnValue = false;
}
hr = wbem_enum_access_[i]->ReadQWORD(timestamp_sys_100_ns_handle_,
&timestamp_100ns);
if (FAILED(hr))
{
returnValue = false;
}
wbem_enum_access_[i]->Release();
wbem_enum_access_[i] = NULL;
const bool wrapparound =
(previous_processor_timestamp_[i] > cpu_usage) ||
(previous_100ns_timestamp_[i] > timestamp_100ns);
const bool first_time = (previous_processor_timestamp_[i] == 0) ||
(previous_100ns_timestamp_[i] == 0);
if (wrapparound || first_time)
{
previous_processor_timestamp_[i] = cpu_usage;
previous_100ns_timestamp_[i] = timestamp_100ns;
continue;
}
const unsigned __int64 processor_timestamp_delta =
cpu_usage - previous_processor_timestamp_[i];
const unsigned __int64 timestamp_100ns_delta =
timestamp_100ns - previous_100ns_timestamp_[i];
if (processor_timestamp_delta >= timestamp_100ns_delta)
{
cpu_usage_[i] = 0;
} else {
// Quotient must be float since the division is guaranteed to yield
// a value between 0 and 1 which is 0 in integer division.
const float delta_quotient =
static_cast<float>(processor_timestamp_delta) /
static_cast<float>(timestamp_100ns_delta);
cpu_usage_[i] = 100 - static_cast<WebRtc_UWord32>(delta_quotient *
100);
}
previous_processor_timestamp_[i] = cpu_usage;
previous_100ns_timestamp_[i] = timestamp_100ns;
}
return returnValue;
}
} // namespace webrtc

View File

@ -0,0 +1,103 @@
// This file contains a Windows implementation of CpuWrapper.
// Note: Windows XP, Windows Server 2003 are the minimum requirements.
// The requirements are due to the implementation being based on
// WMI.
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_
#include "cpu_wrapper.h"
#include <Wbemidl.h>
namespace webrtc {
class ConditionVariableWrapper;
class CriticalSectionWrapper;
class EventWrapper;
class ThreadWrapper;
class CpuWindows : public CpuWrapper
{
public:
virtual WebRtc_Word32 CpuUsage();
virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/,
WebRtc_UWord32 /*length*/) {return -1;}
virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return -1;}
virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores,
WebRtc_UWord32*& cpu_usage);
virtual void Reset() {}
virtual void Stop() {}
CpuWindows();
virtual ~CpuWindows();
private:
bool AllocateComplexDataTypes();
void DeAllocateComplexDataTypes();
void StartPollingCpu();
bool StopPollingCpu();
static bool Process(void* thread_object);
bool ProcessImpl();
bool CreateWmiConnection();
bool CreatePerfOsRefresher();
bool CreatePerfOsCpuHandles();
bool Initialize();
bool Terminate();
bool UpdateCpuUsage();
ThreadWrapper* cpu_polling_thread;
bool initialize_;
bool has_initialized_;
CriticalSectionWrapper* init_crit_;
ConditionVariableWrapper* init_cond_;
bool terminate_;
bool has_terminated_;
CriticalSectionWrapper* terminate_crit_;
ConditionVariableWrapper* terminate_cond_;
// For sleep with wake-up functionality.
EventWrapper* sleep_event;
// Will be an array. Just care about CPU 0 for now.
WebRtc_UWord32* cpu_usage_;
// One IWbemObjectAccess for each processor and one for the total.
// 0-n-1 is the individual processors.
// n is the total.
IWbemObjectAccess** wbem_enum_access_;
DWORD number_of_objects_;
// Cpu timestamp
long cpu_usage_handle_;
unsigned __int64* previous_processor_timestamp_;
// Timestamp
long timestamp_sys_100_ns_handle_;
unsigned __int64* previous_100ns_timestamp_;
IWbemServices* wbem_service_;
IWbemServices* wbem_service_proxy_;
IWbemRefresher* wbem_refresher_;
IWbemHiPerfEnum* wbem_enum_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "gtest/gtest.h"
#include "system_wrappers/interface/cpu_info.h"
#include "system_wrappers/interface/cpu_wrapper.h"
#include "system_wrappers/interface/event_wrapper.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "system_wrappers/interface/trace.h"
#include "testsupport/fileutils.h"
using webrtc::CpuInfo;
using webrtc::CpuWrapper;
using webrtc::EventWrapper;
using webrtc::scoped_ptr;
using webrtc::Trace;
// This test is flaky on Windows/Release.
// http://code.google.com/p/webrtc/issues/detail?id=290
#ifdef _WIN32
#define MAYBE_Usage DISABLED_Usage
#else
#define MAYBE_Usage Usage
#endif
TEST(CpuWrapperTest, MAYBE_Usage) {
Trace::CreateTrace();
std::string trace_file = webrtc::test::OutputPath() +
"cpu_wrapper_unittest.txt";
Trace::SetTraceFile(trace_file.c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
printf("Number of cores detected:%u\n", CpuInfo::DetectNumberOfCores());
scoped_ptr<CpuWrapper> cpu(CpuWrapper::CreateCpu());
ASSERT_TRUE(cpu.get() != NULL);
scoped_ptr<EventWrapper> sleep_event(EventWrapper::Create());
ASSERT_TRUE(sleep_event.get() != NULL);
int num_iterations = 0;
WebRtc_UWord32 num_cores = 0;
WebRtc_UWord32* cores = NULL;
bool cpu_usage_available = cpu->CpuUsageMultiCore(num_cores, cores) != -1;
// Initializing the CPU measurements may take a couple of seconds on Windows.
// Since the initialization is lazy we need to wait until it is completed.
// Should not take more than 10000 ms.
while (!cpu_usage_available && (++num_iterations < 10000)) {
if (cores != NULL) {
ASSERT_GT(num_cores, 0u);
break;
}
sleep_event->Wait(1);
cpu_usage_available = cpu->CpuUsageMultiCore(num_cores, cores) != -1;
}
ASSERT_TRUE(cpu_usage_available);
const WebRtc_Word32 average = cpu->CpuUsageMultiCore(num_cores, cores);
ASSERT_TRUE(cores != NULL);
EXPECT_GT(num_cores, 0u);
EXPECT_GE(average, 0);
EXPECT_LE(average, 100);
printf("\nNumber of cores:%d\n", num_cores);
printf("Average cpu:%d\n", average);
for (WebRtc_UWord32 i = 0; i < num_cores; i++) {
printf("Core:%u CPU:%u \n", i, cores[i]);
EXPECT_GE(cores[i], 0u);
EXPECT_LE(cores[i], 100u);
}
Trace::ReturnTrace();
};

View File

@ -28,6 +28,7 @@
'../interface/compile_assert.h',
'../interface/condition_variable_wrapper.h',
'../interface/cpu_info.h',
'../interface/cpu_wrapper.h',
'../interface/cpu_features_wrapper.h',
'../interface/critical_section_wrapper.h',
'../interface/data_log.h',
@ -64,7 +65,15 @@
'condition_variable_event_win.h',
'condition_variable_native_win.cc',
'condition_variable_native_win.h',
'cpu.cc',
'cpu_no_op.cc',
'cpu_info.cc',
'cpu_linux.cc',
'cpu_linux.h',
'cpu_mac.cc',
'cpu_mac.h',
'cpu_win.cc',
'cpu_win.h',
'cpu_features.cc',
'critical_section.cc',
'critical_section_posix.cc',
@ -153,6 +162,18 @@
'libraries': [ '-lwinmm.lib', ],
},
}],
['build_with_chromium==1', {
'sources!': [
'cpu.cc',
'cpu_linux.h',
'cpu_mac.h',
'cpu_win.h',
],
}, {
'sources!': [
'cpu_no_op.cc',
],
}],
], # conditions
'target_conditions': [
# We need to do this in a target_conditions block to override the
@ -162,6 +183,7 @@
# by file name rules).
'sources/': [
['include', '^atomic32_mac\\.'],
['include', '^cpu_mac\\.'],
],
'sources!': [
'atomic32_posix.cc',

View File

@ -20,6 +20,9 @@
'sources': [
'aligned_malloc_unittest.cc',
'condition_variable_unittest.cc',
'cpu_wrapper_unittest.cc',
'cpu_measurement_harness.h',
'cpu_measurement_harness.cc',
'critical_section_unittest.cc',
'event_tracer_unittest.cc',
'list_unittest.cc',
@ -33,6 +36,7 @@
'stringize_macros_unittest.cc',
'thread_unittest.cc',
'thread_posix_unittest.cc',
'trace_unittest.cc',
'unittest_utilities_unittest.cc',
],
'conditions': [

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "gtest/gtest.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/source/cpu_measurement_harness.h"
#include "webrtc/test/testsupport/fileutils.h"
using webrtc::CpuMeasurementHarness;
using webrtc::Trace;
using webrtc::kTraceWarning;
using webrtc::kTraceUtility;
class Logger : public webrtc::CpuTarget {
public:
Logger() {
Trace::CreateTrace();
std::string trace_file = webrtc::test::OutputPath() + "trace_unittest.txt";
Trace::SetTraceFile(trace_file.c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
}
virtual ~Logger() {
Trace::ReturnTrace();
}
virtual bool DoWork() {
// Use input paremeters to WEBRTC_TRACE that are not likely to be removed
// in future code. E.g. warnings will likely be kept and this file is in
// utility so it should use kTraceUtility.
WEBRTC_TRACE(kTraceWarning, kTraceUtility, 0, "Log line");
return true;
}
};
// This test is disabled because it measures CPU usage. This is flaky because
// the CPU usage for a machine may spike due to OS or other application.
TEST(TraceTest, DISABLED_CpuUsage) {
Logger logger;
const int periodicity_ms = 1;
const int iterations_per_period = 10;
const int duration_ms = 1000;
CpuMeasurementHarness* cpu_harness =
CpuMeasurementHarness::Create(&logger, periodicity_ms,
iterations_per_period, duration_ms);
cpu_harness->Run();
const int average_cpu = cpu_harness->AverageCpu();
EXPECT_GE(5, average_cpu);
}

View File

@ -93,6 +93,13 @@ public:
// of total CPU availability. [Windows only]
virtual int GetCPULoad(int& loadPercent) = 0;
// Gets the computer's current CPU consumption in terms of the percent
// of the total CPU availability. This method may fail a few times on
// Windows because it needs a certain warm-up time before reporting the
// result. You should check the return value and either try again or
// give up when it fails.
virtual int GetSystemCPULoad(int& loadPercent) = 0;
// Not supported
virtual int ResetAudioDevice() = 0;

View File

@ -51,6 +51,17 @@ TEST_F(HardwareBeforeStreamingTest, ResetsAudioDeviceOnIphone) {
// Tests that only apply to desktop:
#if !defined(WEBRTC_IOS) & !defined(WEBRTC_ANDROID)
TEST_F(HardwareBeforeStreamingTest, GetSystemCpuLoadSucceeds) {
#ifdef _WIN32
// This method needs some warm-up time on Windows. We sleep a good amount
// of time instead of retrying to make the test simpler.
Sleep(2000);
#endif
int load_percent;
EXPECT_EQ(0, voe_hardware_->GetSystemCPULoad(load_percent));
}
TEST_F(HardwareBeforeStreamingTest, GetPlayoutDeviceStatusReturnsTrue) {
bool play_available = false;
EXPECT_EQ(0, voe_hardware_->GetPlayoutDeviceStatus(play_available));

View File

@ -69,6 +69,20 @@ TEST_F(HardwareTest, GetCpuLoadReturnsErrorOnNonWindowsPlatform) {
}
#endif
#if !defined(WEBRTC_MAC) && !defined(WEBRTC_ANDROID)
TEST_F(HardwareTest, GetSystemCpuLoadWorksExceptOnMacAndAndroid) {
#ifdef _WIN32
// This method needs some warm-up time on Windows. We sleep a good amount
// of time instead of retrying to make the test simpler.
Sleep(2000);
#endif
int load = -1;
EXPECT_EQ(0, voe_hardware_->GetSystemCPULoad(load));
EXPECT_GE(load, 0);
TEST_LOG("System CPU load = %d%%\n", load);
}
#endif
TEST_F(HardwareTest, BuiltInWasapiAECWorksForAudioWindowsCoreAudioLayer) {
#ifdef WEBRTC_IOS
// Ensure the sound device is reset on iPhone.

View File

@ -12,6 +12,7 @@
#include <cassert>
#include "cpu_wrapper.h"
#include "critical_section_wrapper.h"
#include "trace.h"
#include "voe_errors.h"
@ -37,16 +38,29 @@ VoEHardware* VoEHardware::GetInterface(VoiceEngine* voiceEngine)
#ifdef WEBRTC_VOICE_ENGINE_HARDWARE_API
VoEHardwareImpl::VoEHardwareImpl(voe::SharedData* shared) : _shared(shared)
VoEHardwareImpl::VoEHardwareImpl(voe::SharedData* shared) :
_cpu(NULL), _shared(shared)
{
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
"VoEHardwareImpl() - ctor");
_cpu = CpuWrapper::CreateCpu();
if (_cpu)
{
_cpu->CpuUsage(); // init cpu usage
}
}
VoEHardwareImpl::~VoEHardwareImpl()
{
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
"~VoEHardwareImpl() - dtor");
if (_cpu)
{
delete _cpu;
_cpu = NULL;
}
}
int VoEHardwareImpl::SetAudioDeviceLayer(AudioLayers audioLayer)
@ -739,6 +753,45 @@ int VoEHardwareImpl::GetCPULoad(int& loadPercent)
return 0;
}
int VoEHardwareImpl::GetSystemCPULoad(int& loadPercent)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetSystemCPULoad(loadPercent=?)");
ANDROID_NOT_SUPPORTED(_shared->statistics());
IPHONE_NOT_SUPPORTED(_shared->statistics());
if (!_shared->statistics().Initialized())
{
_shared->SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
// Check if implemented for this platform
if (!_cpu)
{
_shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
" no support for getting system CPU load");
return -1;
}
// Get CPU load
WebRtc_Word32 load = _cpu->CpuUsage();
if (load < 0)
{
_shared->SetLastError(VE_CPU_INFO_ERROR, kTraceError,
" error getting system CPU load");
return -1;
}
loadPercent = static_cast<int> (load);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -1),
" Output: loadPercent = %d", loadPercent);
return 0;
}
int VoEHardwareImpl::EnableBuiltInAEC(bool enable)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),

View File

@ -17,6 +17,7 @@
namespace webrtc
{
class CpuWrapper;
class VoEHardwareImpl: public VoEHardware
{
@ -49,6 +50,8 @@ public:
virtual int GetCPULoad(int& loadPercent);
virtual int GetSystemCPULoad(int& loadPercent);
virtual int ResetAudioDevice();
virtual int AudioDeviceControl(unsigned int par1,
@ -72,6 +75,7 @@ protected:
virtual ~VoEHardwareImpl();
private:
CpuWrapper* _cpu;
voe::SharedData* _shared;
};