| Index: content/renderer/devtools/devtools_cpu_throttler.cc
|
| diff --git a/content/renderer/devtools/devtools_cpu_throttler.cc b/content/renderer/devtools/devtools_cpu_throttler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9aa56dc424260f442931429af3ed406a3028b651
|
| --- /dev/null
|
| +++ b/content/renderer/devtools/devtools_cpu_throttler.cc
|
| @@ -0,0 +1,185 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/renderer/devtools/devtools_cpu_throttler.h"
|
| +
|
| +#if defined(OS_POSIX)
|
| +#include <signal.h>
|
| +#define USE_SIGNALS
|
| +#endif
|
| +
|
| +#include "base/atomicops.h"
|
| +#include "base/synchronization/cancellation_flag.h"
|
| +#include "base/threading/platform_thread.h"
|
| +
|
| +using base::subtle::Atomic32;
|
| +using base::subtle::Acquire_Load;
|
| +using base::subtle::Release_Store;
|
| +
|
| +namespace content {
|
| +
|
| +class CPUThrottlingThread final : public base::PlatformThread::Delegate {
|
| + public:
|
| + explicit CPUThrottlingThread(double rate);
|
| + ~CPUThrottlingThread() override;
|
| +
|
| + void SetThrottlingRate(double rate);
|
| +
|
| + private:
|
| + void ThreadMain() override;
|
| +
|
| + void Start();
|
| + void Stop();
|
| + void Throttle();
|
| +
|
| + static void SuspendThread(base::PlatformThreadHandle thread_handle);
|
| + static void ResumeThread(base::PlatformThreadHandle thread_handle);
|
| +
|
| +#ifdef USE_SIGNALS
|
| + void InstallSignalHandler();
|
| + void RestoreSignalHandler();
|
| + static void HandleSignal(int signal);
|
| +
|
| + static bool signal_handler_installed_;
|
| + static struct sigaction old_signal_handler_;
|
| + static Atomic32 suspended_;
|
| +#endif
|
| + static Atomic32 thread_exists_;
|
| +
|
| + base::PlatformThreadHandle throttled_thread_handle_;
|
| + base::PlatformThreadHandle throttling_thread_handle_;
|
| + base::CancellationFlag cancellation_flag_;
|
| + Atomic32 throttling_rate_percent_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CPUThrottlingThread);
|
| +};
|
| +
|
| +#ifdef USE_SIGNALS
|
| +bool CPUThrottlingThread::signal_handler_installed_;
|
| +struct sigaction CPUThrottlingThread::old_signal_handler_;
|
| +Atomic32 CPUThrottlingThread::suspended_;
|
| +#endif
|
| +Atomic32 CPUThrottlingThread::thread_exists_;
|
| +
|
| +CPUThrottlingThread::CPUThrottlingThread(double rate)
|
| + : throttled_thread_handle_(base::PlatformThread::CurrentHandle()),
|
| + throttling_rate_percent_(static_cast<Atomic32>(rate * 100)) {
|
| + CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 1) == 0);
|
| + Start();
|
| +}
|
| +
|
| +CPUThrottlingThread::~CPUThrottlingThread() {
|
| + Stop();
|
| + CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 0) == 1);
|
| +}
|
| +
|
| +void CPUThrottlingThread::SetThrottlingRate(double rate) {
|
| + Release_Store(&throttling_rate_percent_, static_cast<Atomic32>(rate * 100));
|
| +}
|
| +
|
| +void CPUThrottlingThread::ThreadMain() {
|
| + base::PlatformThread::SetName("DevToolsCPUThrottlingThread");
|
| + while (!cancellation_flag_.IsSet()) {
|
| + Throttle();
|
| + }
|
| +}
|
| +
|
| +#ifdef USE_SIGNALS
|
| +
|
| +// static
|
| +void CPUThrottlingThread::InstallSignalHandler() {
|
| + // There must be the only one!
|
| + DCHECK(!signal_handler_installed_);
|
| + struct sigaction sa;
|
| + sa.sa_handler = &HandleSignal;
|
| + sigemptyset(&sa.sa_mask);
|
| + sa.sa_flags = SA_RESTART;
|
| + signal_handler_installed_ =
|
| + (sigaction(SIGUSR2, &sa, &old_signal_handler_) == 0);
|
| +}
|
| +
|
| +// static
|
| +void CPUThrottlingThread::RestoreSignalHandler() {
|
| + if (!signal_handler_installed_)
|
| + return;
|
| + sigaction(SIGUSR2, &old_signal_handler_, 0);
|
| + signal_handler_installed_ = false;
|
| +}
|
| +
|
| +// static
|
| +void CPUThrottlingThread::HandleSignal(int signal) {
|
| + if (signal != SIGUSR2)
|
| + return;
|
| + while (Acquire_Load(&suspended_)) {
|
| + }
|
| +}
|
| +
|
| +#endif // USE_SIGNALS
|
| +
|
| +// static
|
| +void CPUThrottlingThread::SuspendThread(
|
| + base::PlatformThreadHandle thread_handle) {
|
| +#ifdef USE_SIGNALS
|
| + Release_Store(&suspended_, 1);
|
| + pthread_kill(thread_handle.platform_handle(), SIGUSR2);
|
| +#endif
|
| +}
|
| +
|
| +// static
|
| +void CPUThrottlingThread::ResumeThread(
|
| + base::PlatformThreadHandle thread_handle) {
|
| +#ifdef USE_SIGNALS
|
| + Release_Store(&suspended_, 0);
|
| +#endif
|
| +}
|
| +
|
| +void CPUThrottlingThread::Start() {
|
| +#ifdef USE_SIGNALS
|
| + InstallSignalHandler();
|
| +#endif
|
| + if (!base::PlatformThread::Create(0, this, &throttling_thread_handle_)) {
|
| + LOG(ERROR) << "Failed to create throttling thread.";
|
| + }
|
| +}
|
| +
|
| +void CPUThrottlingThread::Stop() {
|
| + cancellation_flag_.Set();
|
| + base::PlatformThread::Join(throttling_thread_handle_);
|
| +#ifdef USE_SIGNALS
|
| + RestoreSignalHandler();
|
| +#endif
|
| +}
|
| +
|
| +void CPUThrottlingThread::Throttle() {
|
| + const int quant_time_us = 200;
|
| + double rate = Acquire_Load(&throttling_rate_percent_) / 100.;
|
| + base::TimeDelta run_duration =
|
| + base::TimeDelta::FromMicroseconds(static_cast<int>(quant_time_us / rate));
|
| + base::TimeDelta sleep_duration =
|
| + base::TimeDelta::FromMicroseconds(quant_time_us) - run_duration;
|
| + base::PlatformThread::Sleep(run_duration);
|
| + SuspendThread(throttled_thread_handle_);
|
| + base::PlatformThread::Sleep(sleep_duration);
|
| + ResumeThread(throttled_thread_handle_);
|
| +}
|
| +
|
| +DevToolsCPUThrottler::DevToolsCPUThrottler() {}
|
| +
|
| +DevToolsCPUThrottler::~DevToolsCPUThrottler() {}
|
| +
|
| +void DevToolsCPUThrottler::SetThrottlingRate(double rate) {
|
| + if (rate <= 1) {
|
| + if (throttling_thread_) {
|
| + throttling_thread_.reset();
|
| + }
|
| + return;
|
| + }
|
| + if (throttling_thread_) {
|
| + throttling_thread_->SetThrottlingRate(rate);
|
| + } else {
|
| + throttling_thread_.reset(new CPUThrottlingThread(rate));
|
| + }
|
| +}
|
| +
|
| +} // namespace content
|
|
|