Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/devtools/devtools_cpu_throttler.h" | |
| 6 | |
| 7 #if defined(OS_POSIX) | |
| 8 #include <signal.h> | |
| 9 #define USE_SIGNALS | |
| 10 #endif | |
| 11 | |
| 12 #include "base/atomicops.h" | |
| 13 #include "base/synchronization/cancellation_flag.h" | |
| 14 #include "base/threading/platform_thread.h" | |
| 15 | |
| 16 using base::subtle::Atomic32; | |
| 17 using base::subtle::Acquire_Load; | |
| 18 using base::subtle::Release_Store; | |
| 19 | |
| 20 namespace content { | |
| 21 | |
| 22 class CPUThrottlingThread final : public base::PlatformThread::Delegate { | |
| 23 public: | |
| 24 CPUThrottlingThread(double rate); | |
|
pfeldman
2015/12/12 00:33:18
explicit
| |
| 25 ~CPUThrottlingThread() override; | |
| 26 | |
| 27 void SetThrottlingRate(double rate); | |
| 28 | |
| 29 void ThreadMain() override; | |
| 30 | |
| 31 private: | |
| 32 void Start(); | |
| 33 void Stop(); | |
| 34 void Throttle(); | |
| 35 | |
| 36 static void SuspendThread(base::PlatformThreadHandle thread_handle); | |
| 37 static void ResumeThread(base::PlatformThreadHandle thread_handle); | |
| 38 | |
| 39 #ifdef USE_SIGNALS | |
| 40 void InstallSignalHandler(); | |
| 41 void RestoreSignalHandler(); | |
| 42 static void HandleSignal(int signal); | |
| 43 | |
| 44 static bool signal_handler_installed_; | |
| 45 static struct sigaction old_signal_handler_; | |
| 46 static Atomic32 suspended_; | |
| 47 #endif | |
| 48 static Atomic32 thread_exists_; | |
| 49 | |
| 50 base::PlatformThreadHandle throttled_thread_handle_; | |
| 51 base::PlatformThreadHandle throttling_thread_handle_; | |
| 52 base::CancellationFlag cancellation_flag_; | |
| 53 Atomic32 throttling_rate_percent_; | |
| 54 | |
| 55 DISALLOW_COPY_AND_ASSIGN(CPUThrottlingThread); | |
| 56 }; | |
| 57 | |
| 58 #ifdef USE_SIGNALS | |
| 59 bool CPUThrottlingThread::signal_handler_installed_; | |
| 60 struct sigaction CPUThrottlingThread::old_signal_handler_; | |
| 61 Atomic32 CPUThrottlingThread::suspended_; | |
| 62 #endif | |
| 63 Atomic32 CPUThrottlingThread::thread_exists_; | |
| 64 | |
| 65 CPUThrottlingThread::CPUThrottlingThread(double rate) | |
| 66 : throttled_thread_handle_(base::PlatformThread::CurrentHandle()), | |
| 67 throttling_rate_percent_(static_cast<Atomic32>(rate * 100)) { | |
| 68 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 1) == 0); | |
| 69 Start(); | |
| 70 } | |
| 71 | |
| 72 CPUThrottlingThread::~CPUThrottlingThread() { | |
| 73 Stop(); | |
| 74 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 0) == 1); | |
| 75 } | |
| 76 | |
| 77 void CPUThrottlingThread::SetThrottlingRate(double rate) { | |
| 78 Release_Store(&throttling_rate_percent_, static_cast<Atomic32>(rate * 100)); | |
| 79 } | |
| 80 | |
| 81 void CPUThrottlingThread::ThreadMain() { | |
| 82 base::PlatformThread::SetName("DevToolsCPUThrottlingThread"); | |
| 83 while (!cancellation_flag_.IsSet()) { | |
| 84 Throttle(); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 #ifdef USE_SIGNALS | |
| 89 | |
| 90 // static | |
| 91 void CPUThrottlingThread::InstallSignalHandler() { | |
| 92 // There must be the only one! | |
| 93 DCHECK(!signal_handler_installed_); | |
| 94 struct sigaction sa; | |
| 95 sa.sa_handler = &HandleSignal; | |
| 96 sigemptyset(&sa.sa_mask); | |
| 97 sa.sa_flags = SA_RESTART; | |
| 98 signal_handler_installed_ = | |
| 99 (sigaction(SIGUSR2, &sa, &old_signal_handler_) == 0); | |
| 100 } | |
| 101 | |
| 102 // static | |
| 103 void CPUThrottlingThread::RestoreSignalHandler() { | |
| 104 if (!signal_handler_installed_) | |
| 105 return; | |
| 106 sigaction(SIGUSR2, &old_signal_handler_, 0); | |
| 107 signal_handler_installed_ = false; | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 void CPUThrottlingThread::HandleSignal(int signal) { | |
| 112 if (signal != SIGUSR2) | |
| 113 return; | |
| 114 while (Acquire_Load(&suspended_)) { | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 #endif // USE_SIGNALS | |
| 119 | |
| 120 // static | |
| 121 void CPUThrottlingThread::SuspendThread( | |
| 122 base::PlatformThreadHandle thread_handle) { | |
| 123 #ifdef USE_SIGNALS | |
| 124 Release_Store(&suspended_, 1); | |
| 125 pthread_kill(thread_handle.platform_handle(), SIGUSR2); | |
| 126 #endif | |
| 127 } | |
| 128 | |
| 129 // static | |
| 130 void CPUThrottlingThread::ResumeThread( | |
| 131 base::PlatformThreadHandle thread_handle) { | |
| 132 #ifdef USE_SIGNALS | |
| 133 Release_Store(&suspended_, 0); | |
| 134 #endif | |
| 135 } | |
| 136 | |
| 137 void CPUThrottlingThread::Start() { | |
| 138 #ifdef USE_SIGNALS | |
| 139 InstallSignalHandler(); | |
| 140 #endif | |
| 141 if (!base::PlatformThread::Create(0, this, &throttling_thread_handle_)) { | |
| 142 LOG(ERROR) << "Failed to create throttling thread."; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 void CPUThrottlingThread::Stop() { | |
| 147 cancellation_flag_.Set(); | |
| 148 base::PlatformThread::Join(throttling_thread_handle_); | |
| 149 #ifdef USE_SIGNALS | |
| 150 RestoreSignalHandler(); | |
| 151 #endif | |
| 152 } | |
| 153 | |
| 154 void CPUThrottlingThread::Throttle() { | |
| 155 const int quant_time_us = 200; | |
| 156 double rate = Acquire_Load(&throttling_rate_percent_) / 100.; | |
| 157 base::TimeDelta run_duration = | |
| 158 base::TimeDelta::FromMicroseconds(static_cast<int>(quant_time_us / rate)); | |
| 159 base::TimeDelta sleep_duration = | |
| 160 base::TimeDelta::FromMicroseconds(quant_time_us) - run_duration; | |
| 161 base::PlatformThread::Sleep(run_duration); | |
| 162 SuspendThread(throttled_thread_handle_); | |
| 163 base::PlatformThread::Sleep(sleep_duration); | |
| 164 ResumeThread(throttled_thread_handle_); | |
| 165 } | |
| 166 | |
| 167 DevToolsCPUThrottler::DevToolsCPUThrottler() {} | |
| 168 | |
| 169 DevToolsCPUThrottler::~DevToolsCPUThrottler() {} | |
| 170 | |
| 171 void DevToolsCPUThrottler::SetThrottlingRate(double rate) { | |
| 172 if (rate <= 1) { | |
| 173 if (throttling_thread_) { | |
| 174 throttling_thread_.reset(); | |
| 175 } | |
| 176 return; | |
| 177 } | |
| 178 if (throttling_thread_) { | |
| 179 throttling_thread_->SetThrottlingRate(rate); | |
| 180 } else { | |
| 181 throttling_thread_.reset(new CPUThrottlingThread(rate)); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 } // namespace content | |
| OLD | NEW |