qemu/softmmu/cpu-throttle.c
<<
>>
Prefs
   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}
 130