cpu: Provide vcpu throttling interface
Provide a method to throttle guest cpu execution. CPUState is augmented with timeout controls and throttle start/stop functions. To throttle the guest cpu the caller simply has to call the throttle set function and provide a percentage of throttle time. Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.vnet.ibm.com> Signed-off-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
		
							parent
							
								
									2a6e6e59df
								
							
						
					
					
						commit
						2adcc85d40
					
				
							
								
								
									
										78
									
								
								cpus.c
								
								
								
								
							
							
						
						
									
										78
									
								
								cpus.c
								
								
								
								
							| 
						 | 
				
			
			@ -69,6 +69,14 @@ static CPUState *next_cpu;
 | 
			
		|||
int64_t max_delay;
 | 
			
		||||
int64_t max_advance;
 | 
			
		||||
 | 
			
		||||
/* vcpu throttling controls */
 | 
			
		||||
static QEMUTimer *throttle_timer;
 | 
			
		||||
static unsigned int throttle_percentage;
 | 
			
		||||
 | 
			
		||||
#define CPU_THROTTLE_PCT_MIN 1
 | 
			
		||||
#define CPU_THROTTLE_PCT_MAX 99
 | 
			
		||||
#define CPU_THROTTLE_TIMESLICE_NS 10000000
 | 
			
		||||
 | 
			
		||||
bool cpu_is_stopped(CPUState *cpu)
 | 
			
		||||
{
 | 
			
		||||
    return cpu->stopped || !runstate_is_running();
 | 
			
		||||
| 
						 | 
				
			
			@ -505,10 +513,80 @@ static const VMStateDescription vmstate_timers = {
 | 
			
		|||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void cpu_throttle_thread(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    CPUState *cpu = opaque;
 | 
			
		||||
    double pct;
 | 
			
		||||
    double throttle_ratio;
 | 
			
		||||
    long sleeptime_ns;
 | 
			
		||||
 | 
			
		||||
    if (!cpu_throttle_get_percentage()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pct = (double)cpu_throttle_get_percentage()/100;
 | 
			
		||||
    throttle_ratio = pct / (1 - pct);
 | 
			
		||||
    sleeptime_ns = (long)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS);
 | 
			
		||||
 | 
			
		||||
    qemu_mutex_unlock_iothread();
 | 
			
		||||
    atomic_set(&cpu->throttle_thread_scheduled, 0);
 | 
			
		||||
    g_usleep(sleeptime_ns / 1000); /* Convert ns to us for usleep call */
 | 
			
		||||
    qemu_mutex_lock_iothread();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cpu_throttle_timer_tick(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    CPUState *cpu;
 | 
			
		||||
    double pct;
 | 
			
		||||
 | 
			
		||||
    /* Stop the timer if needed */
 | 
			
		||||
    if (!cpu_throttle_get_percentage()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    CPU_FOREACH(cpu) {
 | 
			
		||||
        if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
 | 
			
		||||
            async_run_on_cpu(cpu, cpu_throttle_thread, cpu);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pct = (double)cpu_throttle_get_percentage()/100;
 | 
			
		||||
    timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) +
 | 
			
		||||
                                   CPU_THROTTLE_TIMESLICE_NS / (1-pct));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_throttle_set(int new_throttle_pct)
 | 
			
		||||
{
 | 
			
		||||
    /* Ensure throttle percentage is within valid range */
 | 
			
		||||
    new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX);
 | 
			
		||||
    new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN);
 | 
			
		||||
 | 
			
		||||
    atomic_set(&throttle_percentage, new_throttle_pct);
 | 
			
		||||
 | 
			
		||||
    timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) +
 | 
			
		||||
                                       CPU_THROTTLE_TIMESLICE_NS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_throttle_stop(void)
 | 
			
		||||
{
 | 
			
		||||
    atomic_set(&throttle_percentage, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cpu_throttle_active(void)
 | 
			
		||||
{
 | 
			
		||||
    return (cpu_throttle_get_percentage() != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cpu_throttle_get_percentage(void)
 | 
			
		||||
{
 | 
			
		||||
    return atomic_read(&throttle_percentage);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_ticks_init(void)
 | 
			
		||||
{
 | 
			
		||||
    seqlock_init(&timers_state.vm_clock_seqlock, NULL);
 | 
			
		||||
    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
 | 
			
		||||
    throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
 | 
			
		||||
                                           cpu_throttle_timer_tick, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void configure_icount(QemuOpts *opts, Error **errp)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -321,6 +321,11 @@ struct CPUState {
 | 
			
		|||
    uint32_t can_do_io;
 | 
			
		||||
    int32_t exception_index; /* used by m68k TCG */
 | 
			
		||||
 | 
			
		||||
    /* Used to keep track of an outstanding cpu throttle thread for migration
 | 
			
		||||
     * autoconverge
 | 
			
		||||
     */
 | 
			
		||||
    bool throttle_thread_scheduled;
 | 
			
		||||
 | 
			
		||||
    /* Note that this is accessed at the start of every TB via a negative
 | 
			
		||||
       offset from AREG0.  Leave this field at the end so as to make the
 | 
			
		||||
       (absolute value) offset as small as possible.  This reduces code
 | 
			
		||||
| 
						 | 
				
			
			@ -565,6 +570,43 @@ CPUState *qemu_get_cpu(int index);
 | 
			
		|||
 */
 | 
			
		||||
bool cpu_exists(int64_t id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * cpu_throttle_set:
 | 
			
		||||
 * @new_throttle_pct: Percent of sleep time. Valid range is 1 to 99.
 | 
			
		||||
 *
 | 
			
		||||
 * Throttles all vcpus by forcing them to sleep for the given percentage of
 | 
			
		||||
 * time. A throttle_percentage of 25 corresponds to a 75% duty cycle roughly.
 | 
			
		||||
 * (example: 10ms sleep for every 30ms awake).
 | 
			
		||||
 *
 | 
			
		||||
 * cpu_throttle_set can be called as needed to adjust new_throttle_pct.
 | 
			
		||||
 * Once the throttling starts, it will remain in effect until cpu_throttle_stop
 | 
			
		||||
 * is called.
 | 
			
		||||
 */
 | 
			
		||||
void cpu_throttle_set(int new_throttle_pct);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * cpu_throttle_stop:
 | 
			
		||||
 *
 | 
			
		||||
 * Stops the vcpu throttling started by cpu_throttle_set.
 | 
			
		||||
 */
 | 
			
		||||
void cpu_throttle_stop(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * cpu_throttle_active:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %true if the vcpus are currently being throttled, %false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
bool cpu_throttle_active(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * cpu_throttle_get_percentage:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the vcpu throttle percentage. See cpu_throttle_set for details.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: The throttle percentage in range 1 to 99.
 | 
			
		||||
 */
 | 
			
		||||
int cpu_throttle_get_percentage(void);
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_USER_ONLY
 | 
			
		||||
 | 
			
		||||
typedef void (*CPUInterruptHandler)(CPUState *, int);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue