| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/devtools/devtools_cpu_throttler.h" | 5 #include "content/renderer/devtools/devtools_cpu_throttler.h" |
| 6 | 6 |
| 7 #include "base/atomicops.h" | 7 #include "base/atomicops.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/synchronization/cancellation_flag.h" | 9 #include "base/synchronization/cancellation_flag.h" |
| 10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 static void ResumeThread(base::PlatformThreadHandle thread_handle); | 39 static void ResumeThread(base::PlatformThreadHandle thread_handle); |
| 40 static void Sleep(base::TimeDelta duration); | 40 static void Sleep(base::TimeDelta duration); |
| 41 | 41 |
| 42 #ifdef USE_SIGNALS | 42 #ifdef USE_SIGNALS |
| 43 void InstallSignalHandler(); | 43 void InstallSignalHandler(); |
| 44 void RestoreSignalHandler(); | 44 void RestoreSignalHandler(); |
| 45 static void HandleSignal(int signal); | 45 static void HandleSignal(int signal); |
| 46 | 46 |
| 47 static bool signal_handler_installed_; | 47 static bool signal_handler_installed_; |
| 48 static struct sigaction old_signal_handler_; | 48 static struct sigaction old_signal_handler_; |
| 49 static Atomic32 suspended_; | |
| 50 #endif | 49 #endif |
| 51 static Atomic32 thread_exists_; | 50 static Atomic32 thread_exists_; |
| 51 static Atomic32 throttling_rate_percent_; |
| 52 | 52 |
| 53 base::PlatformThreadHandle throttled_thread_handle_; | 53 base::PlatformThreadHandle throttled_thread_handle_; |
| 54 base::PlatformThreadHandle throttling_thread_handle_; | 54 base::PlatformThreadHandle throttling_thread_handle_; |
| 55 base::CancellationFlag cancellation_flag_; | 55 base::CancellationFlag cancellation_flag_; |
| 56 Atomic32 throttling_rate_percent_; | |
| 57 | 56 |
| 58 DISALLOW_COPY_AND_ASSIGN(CPUThrottlingThread); | 57 DISALLOW_COPY_AND_ASSIGN(CPUThrottlingThread); |
| 59 }; | 58 }; |
| 60 | 59 |
| 61 #ifdef USE_SIGNALS | 60 #ifdef USE_SIGNALS |
| 62 bool CPUThrottlingThread::signal_handler_installed_; | 61 bool CPUThrottlingThread::signal_handler_installed_; |
| 63 struct sigaction CPUThrottlingThread::old_signal_handler_; | 62 struct sigaction CPUThrottlingThread::old_signal_handler_; |
| 64 Atomic32 CPUThrottlingThread::suspended_; | |
| 65 #endif | 63 #endif |
| 64 Atomic32 CPUThrottlingThread::throttling_rate_percent_; |
| 66 Atomic32 CPUThrottlingThread::thread_exists_; | 65 Atomic32 CPUThrottlingThread::thread_exists_; |
| 67 | 66 |
| 68 CPUThrottlingThread::CPUThrottlingThread(double rate) | 67 CPUThrottlingThread::CPUThrottlingThread(double rate) |
| 69 #ifdef OS_WIN | 68 #ifdef OS_WIN |
| 70 : throttled_thread_handle_( | 69 : throttled_thread_handle_( |
| 71 ::OpenThread(THREAD_SUSPEND_RESUME, false, ::GetCurrentThreadId())), | 70 ::OpenThread(THREAD_SUSPEND_RESUME, false, ::GetCurrentThreadId())) { |
| 72 #else | 71 #else |
| 73 : throttled_thread_handle_(base::PlatformThread::CurrentHandle()), | 72 : throttled_thread_handle_(base::PlatformThread::CurrentHandle()) { |
| 74 #endif | 73 #endif |
| 75 throttling_rate_percent_(static_cast<Atomic32>(rate * 100)) { | 74 SetThrottlingRate(rate); |
| 76 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 1) == 0); | 75 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 1) == 0); |
| 77 Start(); | 76 Start(); |
| 78 } | 77 } |
| 79 | 78 |
| 80 CPUThrottlingThread::~CPUThrottlingThread() { | 79 CPUThrottlingThread::~CPUThrottlingThread() { |
| 81 Stop(); | 80 Stop(); |
| 82 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 0) == 1); | 81 CHECK(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 0) == 1); |
| 83 } | 82 } |
| 84 | 83 |
| 85 void CPUThrottlingThread::SetThrottlingRate(double rate) { | 84 void CPUThrottlingThread::SetThrottlingRate(double rate) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 112 if (!signal_handler_installed_) | 111 if (!signal_handler_installed_) |
| 113 return; | 112 return; |
| 114 sigaction(SIGUSR2, &old_signal_handler_, 0); | 113 sigaction(SIGUSR2, &old_signal_handler_, 0); |
| 115 signal_handler_installed_ = false; | 114 signal_handler_installed_ = false; |
| 116 } | 115 } |
| 117 | 116 |
| 118 // static | 117 // static |
| 119 void CPUThrottlingThread::HandleSignal(int signal) { | 118 void CPUThrottlingThread::HandleSignal(int signal) { |
| 120 if (signal != SIGUSR2) | 119 if (signal != SIGUSR2) |
| 121 return; | 120 return; |
| 122 while (Acquire_Load(&suspended_)) { | 121 static base::TimeTicks lastResumeTime; |
| 123 } | 122 base::TimeTicks now = base::TimeTicks::Now(); |
| 123 base::TimeDelta run_duration = now - lastResumeTime; |
| 124 uint32_t throttling_rate_percent = Acquire_Load(&throttling_rate_percent_); |
| 125 // Limit the observed run duration to 1000μs to deal with the first entrance |
| 126 // to the signal handler. |
| 127 uint32_t run_duration_us = static_cast<uint32_t>( |
| 128 std::min(run_duration.InMicroseconds(), static_cast<int64_t>(1000))); |
| 129 uint32_t sleep_duration_us = |
| 130 run_duration_us * throttling_rate_percent / 100 - run_duration_us; |
| 131 base::TimeTicks wake_up_time = |
| 132 now + base::TimeDelta::FromMicroseconds(sleep_duration_us); |
| 133 do { |
| 134 now = base::TimeTicks::Now(); |
| 135 } while (now < wake_up_time); |
| 136 lastResumeTime = now; |
| 124 } | 137 } |
| 125 | 138 |
| 126 #endif // USE_SIGNALS | 139 #endif // USE_SIGNALS |
| 127 | 140 |
| 128 // static | 141 void CPUThrottlingThread::Throttle() { |
| 129 void CPUThrottlingThread::SuspendThread( | 142 const int quant_time_us = 200; |
| 130 base::PlatformThreadHandle thread_handle) { | 143 #if defined(OS_WIN) |
| 131 #if defined(USE_SIGNALS) | 144 double rate = Acquire_Load(&throttling_rate_percent_) / 100.; |
| 132 Release_Store(&suspended_, 1); | 145 base::TimeDelta run_duration = |
| 133 pthread_kill(thread_handle.platform_handle(), SIGUSR2); | 146 base::TimeDelta::FromMicroseconds(static_cast<int>(quant_time_us / rate)); |
| 134 #elif defined(OS_WIN) | 147 base::TimeDelta sleep_duration = |
| 135 ::SuspendThread(thread_handle.platform_handle()); | 148 base::TimeDelta::FromMicroseconds(quant_time_us) - run_duration; |
| 149 Sleep(run_duration); |
| 150 ::SuspendThread(throttled_thread_handle_.platform_handle()); |
| 151 Sleep(sleep_duration); |
| 152 ::ResumeThread(throttled_thread_handle_.platform_handle()); |
| 153 #else |
| 154 pthread_kill(throttled_thread_handle_.platform_handle(), SIGUSR2); |
| 155 Sleep(base::TimeDelta::FromMicroseconds(quant_time_us)); |
| 136 #endif | 156 #endif |
| 137 } | 157 } |
| 138 | 158 |
| 139 // static | |
| 140 void CPUThrottlingThread::ResumeThread( | |
| 141 base::PlatformThreadHandle thread_handle) { | |
| 142 #if defined(USE_SIGNALS) | |
| 143 Release_Store(&suspended_, 0); | |
| 144 #elif defined(OS_WIN) | |
| 145 ::ResumeThread(thread_handle.platform_handle()); | |
| 146 #endif | |
| 147 } | |
| 148 | |
| 149 void CPUThrottlingThread::Start() { | 159 void CPUThrottlingThread::Start() { |
| 150 #ifdef USE_SIGNALS | 160 #ifdef USE_SIGNALS |
| 151 InstallSignalHandler(); | 161 InstallSignalHandler(); |
| 152 #elif !defined(OS_WIN) | 162 #elif !defined(OS_WIN) |
| 153 LOG(ERROR) << "CPU throttling is not supported." | 163 LOG(ERROR) << "CPU throttling is not supported." |
| 154 #endif | 164 #endif |
| 155 if (!base::PlatformThread::Create(0, this, &throttling_thread_handle_)) { | 165 if (!base::PlatformThread::Create(0, this, &throttling_thread_handle_)) { |
| 156 LOG(ERROR) << "Failed to create throttling thread."; | 166 LOG(ERROR) << "Failed to create throttling thread."; |
| 157 } | 167 } |
| 158 } | 168 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 169 } | 179 } |
| 170 | 180 |
| 171 void CPUThrottlingThread::Stop() { | 181 void CPUThrottlingThread::Stop() { |
| 172 cancellation_flag_.Set(); | 182 cancellation_flag_.Set(); |
| 173 base::PlatformThread::Join(throttling_thread_handle_); | 183 base::PlatformThread::Join(throttling_thread_handle_); |
| 174 #ifdef USE_SIGNALS | 184 #ifdef USE_SIGNALS |
| 175 RestoreSignalHandler(); | 185 RestoreSignalHandler(); |
| 176 #endif | 186 #endif |
| 177 } | 187 } |
| 178 | 188 |
| 179 void CPUThrottlingThread::Throttle() { | |
| 180 const int quant_time_us = 200; | |
| 181 double rate = Acquire_Load(&throttling_rate_percent_) / 100.; | |
| 182 base::TimeDelta run_duration = | |
| 183 base::TimeDelta::FromMicroseconds(static_cast<int>(quant_time_us / rate)); | |
| 184 base::TimeDelta sleep_duration = | |
| 185 base::TimeDelta::FromMicroseconds(quant_time_us) - run_duration; | |
| 186 Sleep(run_duration); | |
| 187 SuspendThread(throttled_thread_handle_); | |
| 188 Sleep(sleep_duration); | |
| 189 ResumeThread(throttled_thread_handle_); | |
| 190 } | |
| 191 | |
| 192 DevToolsCPUThrottler::DevToolsCPUThrottler() {} | 189 DevToolsCPUThrottler::DevToolsCPUThrottler() {} |
| 193 | 190 |
| 194 DevToolsCPUThrottler::~DevToolsCPUThrottler() {} | 191 DevToolsCPUThrottler::~DevToolsCPUThrottler() {} |
| 195 | 192 |
| 196 void DevToolsCPUThrottler::SetThrottlingRate(double rate) { | 193 void DevToolsCPUThrottler::SetThrottlingRate(double rate) { |
| 197 if (rate <= 1) { | 194 if (rate <= 1) { |
| 198 if (throttling_thread_) { | 195 if (throttling_thread_) { |
| 199 throttling_thread_.reset(); | 196 throttling_thread_.reset(); |
| 200 } | 197 } |
| 201 return; | 198 return; |
| 202 } | 199 } |
| 203 if (throttling_thread_) { | 200 if (throttling_thread_) { |
| 204 throttling_thread_->SetThrottlingRate(rate); | 201 throttling_thread_->SetThrottlingRate(rate); |
| 205 } else { | 202 } else { |
| 206 throttling_thread_.reset(new CPUThrottlingThread(rate)); | 203 throttling_thread_.reset(new CPUThrottlingThread(rate)); |
| 207 } | 204 } |
| 208 } | 205 } |
| 209 | 206 |
| 210 } // namespace content | 207 } // namespace content |
| OLD | NEW |