xref: /openbmc/qemu/migration/cpu-throttle.c (revision d481cec7)
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