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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jason J. Herne
						Jason J. Herne