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