| 183 | } |
| 184 | |
| 185 | void EmuThread::throttleWait() { |
| 186 | int speed; |
| 187 | bool throttle; |
| 188 | { |
| 189 | std::unique_lock<std::mutex> lockSpeed(m_mutexSpeed); |
| 190 | speed = m_speed; |
| 191 | throttle = m_throttle; |
| 192 | if (!speed && throttle) { |
| 193 | emit sendSpeed(0); |
| 194 | m_cvSpeed.wait(lockSpeed, [this] { return m_speed != 0 || !m_throttle; }); |
| 195 | speed = m_speed; |
| 196 | throttle = m_throttle; |
| 197 | m_lastTime = std::chrono::steady_clock::now(); |
| 198 | } |
| 199 | } |
| 200 | double run_rate = sched_get_clock_rate_precise(CLOCK_RUN); |
| 201 | std::chrono::steady_clock::time_point cur_time = std::chrono::steady_clock::now(); |
| 202 | if (!throttle) { |
| 203 | m_lastTime = cur_time; |
| 204 | std::this_thread::yield(); |
| 205 | } else { |
| 206 | std::chrono::steady_clock::duration interval(std::chrono::duration_cast<std::chrono::steady_clock::duration> |
| 207 | (std::chrono::duration<double>(100 / (speed * run_rate)))); |
| 208 | std::chrono::steady_clock::time_point next_time = m_lastTime + interval; |
| 209 | std::chrono::steady_clock::time_point tolerance_time = m_lastTime + std::chrono::milliseconds(40); |
| 210 | if (cur_time < std::max(next_time, tolerance_time)) { |
| 211 | m_lastTime = next_time; |
| 212 | if (cur_time < next_time) { |
| 213 | std::this_thread::sleep_until(next_time); |
| 214 | } |
| 215 | } else { |
| 216 | m_lastTime = cur_time; |
| 217 | std::this_thread::yield(); |
| 218 | } |
| 219 | } |
| 220 | std::chrono::steady_clock::time_point timeNUnitsAgo = m_perfArray[m_perfIndex]; |
| 221 | m_perfArray[m_perfIndex] = m_lastTime; |
| 222 | if (++m_perfIndex == PerfArraySize) { |
| 223 | m_perfIndex = 0; |
| 224 | } |
| 225 | std::chrono::duration<double> diff = m_lastTime - timeNUnitsAgo; |
| 226 | emit sendSpeed(diff.count() * run_rate * (1.0 / PerfArraySize)); |
| 227 | } |
| 228 | |
| 229 | void EmuThread::unblock() { |
| 230 | m_mutex.lock(); |
nothing calls this directly
no test coverage detected