cpu-throttle.c (4147B)
1/* 2 * QEMU System Emulator 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26#include "qemu-common.h" 27#include "qemu/thread.h" 28#include "hw/core/cpu.h" 29#include "qemu/main-loop.h" 30#include "sysemu/cpus.h" 31#include "sysemu/cpu-throttle.h" 32 33/* vcpu throttling controls */ 34static QEMUTimer *throttle_timer; 35static unsigned int throttle_percentage; 36 37#define CPU_THROTTLE_PCT_MIN 1 38#define CPU_THROTTLE_PCT_MAX 99 39#define CPU_THROTTLE_TIMESLICE_NS 10000000 40 41static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) 42{ 43 double pct; 44 double throttle_ratio; 45 int64_t sleeptime_ns, endtime_ns; 46 47 if (!cpu_throttle_get_percentage()) { 48 return; 49 } 50 51 pct = (double)cpu_throttle_get_percentage() / 100; 52 throttle_ratio = pct / (1 - pct); 53 /* Add 1ns to fix double's rounding error (like 0.9999999...) */ 54 sleeptime_ns = (int64_t)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS + 1); 55 endtime_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + sleeptime_ns; 56 while (sleeptime_ns > 0 && !cpu->stop) { 57 if (sleeptime_ns > SCALE_MS) { 58 qemu_cond_timedwait_iothread(cpu->halt_cond, 59 sleeptime_ns / SCALE_MS); 60 } else { 61 qemu_mutex_unlock_iothread(); 62 g_usleep(sleeptime_ns / SCALE_US); 63 qemu_mutex_lock_iothread(); 64 } 65 sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); 66 } 67 qatomic_set(&cpu->throttle_thread_scheduled, 0); 68} 69 70static void cpu_throttle_timer_tick(void *opaque) 71{ 72 CPUState *cpu; 73 double pct; 74 75 /* Stop the timer if needed */ 76 if (!cpu_throttle_get_percentage()) { 77 return; 78 } 79 CPU_FOREACH(cpu) { 80 if (!qatomic_xchg(&cpu->throttle_thread_scheduled, 1)) { 81 async_run_on_cpu(cpu, cpu_throttle_thread, 82 RUN_ON_CPU_NULL); 83 } 84 } 85 86 pct = (double)cpu_throttle_get_percentage() / 100; 87 timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + 88 CPU_THROTTLE_TIMESLICE_NS / (1 - pct)); 89} 90 91void cpu_throttle_set(int new_throttle_pct) 92{ 93 /* 94 * boolean to store whether throttle is already active or not, 95 * before modifying throttle_percentage 96 */ 97 bool throttle_active = cpu_throttle_active(); 98 99 /* Ensure throttle percentage is within valid range */ 100 new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); 101 new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); 102 103 qatomic_set(&throttle_percentage, new_throttle_pct); 104 105 if (!throttle_active) { 106 cpu_throttle_timer_tick(NULL); 107 } 108} 109 110void cpu_throttle_stop(void) 111{ 112 qatomic_set(&throttle_percentage, 0); 113} 114 115bool cpu_throttle_active(void) 116{ 117 return (cpu_throttle_get_percentage() != 0); 118} 119 120int cpu_throttle_get_percentage(void) 121{ 122 return qatomic_read(&throttle_percentage); 123} 124 125void cpu_throttle_init(void) 126{ 127 throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, 128 cpu_throttle_timer_tick, NULL); 129}