2
0

cpu-throttle.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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. #include "qemu/osdep.h"
  25. #include "qemu/thread.h"
  26. #include "hw/core/cpu.h"
  27. #include "qemu/main-loop.h"
  28. #include "system/cpus.h"
  29. #include "system/cpu-throttle.h"
  30. #include "migration.h"
  31. #include "migration-stats.h"
  32. #include "trace.h"
  33. /* vcpu throttling controls */
  34. static QEMUTimer *throttle_timer, *throttle_dirty_sync_timer;
  35. static unsigned int throttle_percentage;
  36. static bool throttle_dirty_sync_timer_active;
  37. static uint64_t throttle_dirty_sync_count_prev;
  38. #define CPU_THROTTLE_PCT_MIN 1
  39. #define CPU_THROTTLE_PCT_MAX 99
  40. #define CPU_THROTTLE_TIMESLICE_NS 10000000
  41. /* Making sure RAMBlock dirty bitmap is synchronized every five seconds */
  42. #define CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS 5000
  43. static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque)
  44. {
  45. double pct;
  46. double throttle_ratio;
  47. int64_t sleeptime_ns, endtime_ns;
  48. if (!cpu_throttle_get_percentage()) {
  49. return;
  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_bql(cpu->halt_cond,
  59. sleeptime_ns / SCALE_MS);
  60. } else {
  61. bql_unlock();
  62. g_usleep(sleeptime_ns / SCALE_US);
  63. bql_lock();
  64. }
  65. sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
  66. }
  67. qatomic_set(&cpu->throttle_thread_scheduled, 0);
  68. }
  69. static void cpu_throttle_timer_tick(void *opaque)
  70. {
  71. CPUState *cpu;
  72. double pct;
  73. /* Stop the timer if needed */
  74. if (!cpu_throttle_get_percentage()) {
  75. return;
  76. }
  77. CPU_FOREACH(cpu) {
  78. if (!qatomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
  79. async_run_on_cpu(cpu, cpu_throttle_thread,
  80. RUN_ON_CPU_NULL);
  81. }
  82. }
  83. pct = (double)cpu_throttle_get_percentage() / 100;
  84. timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) +
  85. CPU_THROTTLE_TIMESLICE_NS / (1 - pct));
  86. }
  87. void cpu_throttle_set(int new_throttle_pct)
  88. {
  89. /*
  90. * boolean to store whether throttle is already active or not,
  91. * before modifying throttle_percentage
  92. */
  93. bool throttle_active = cpu_throttle_active();
  94. trace_cpu_throttle_set(new_throttle_pct);
  95. /* Ensure throttle percentage is within valid range */
  96. new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX);
  97. new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN);
  98. qatomic_set(&throttle_percentage, new_throttle_pct);
  99. if (!throttle_active) {
  100. cpu_throttle_timer_tick(NULL);
  101. }
  102. }
  103. void cpu_throttle_stop(void)
  104. {
  105. qatomic_set(&throttle_percentage, 0);
  106. cpu_throttle_dirty_sync_timer(false);
  107. }
  108. bool cpu_throttle_active(void)
  109. {
  110. return (cpu_throttle_get_percentage() != 0);
  111. }
  112. int cpu_throttle_get_percentage(void)
  113. {
  114. return qatomic_read(&throttle_percentage);
  115. }
  116. void cpu_throttle_dirty_sync_timer_tick(void *opaque)
  117. {
  118. uint64_t sync_cnt = stat64_get(&mig_stats.dirty_sync_count);
  119. /*
  120. * The first iteration copies all memory anyhow and has no
  121. * effect on guest performance, therefore omit it to avoid
  122. * paying extra for the sync penalty.
  123. */
  124. if (sync_cnt <= 1) {
  125. goto end;
  126. }
  127. if (sync_cnt == throttle_dirty_sync_count_prev) {
  128. trace_cpu_throttle_dirty_sync();
  129. WITH_RCU_READ_LOCK_GUARD() {
  130. migration_bitmap_sync_precopy(false);
  131. }
  132. }
  133. end:
  134. throttle_dirty_sync_count_prev = stat64_get(&mig_stats.dirty_sync_count);
  135. timer_mod(throttle_dirty_sync_timer,
  136. qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) +
  137. CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS);
  138. }
  139. static bool cpu_throttle_dirty_sync_active(void)
  140. {
  141. return qatomic_read(&throttle_dirty_sync_timer_active);
  142. }
  143. void cpu_throttle_dirty_sync_timer(bool enable)
  144. {
  145. assert(throttle_dirty_sync_timer);
  146. if (enable) {
  147. if (!cpu_throttle_dirty_sync_active()) {
  148. /*
  149. * Always reset the dirty sync count cache, in case migration
  150. * was cancelled once.
  151. */
  152. throttle_dirty_sync_count_prev = 0;
  153. timer_mod(throttle_dirty_sync_timer,
  154. qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) +
  155. CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS);
  156. qatomic_set(&throttle_dirty_sync_timer_active, 1);
  157. }
  158. } else {
  159. if (cpu_throttle_dirty_sync_active()) {
  160. timer_del(throttle_dirty_sync_timer);
  161. qatomic_set(&throttle_dirty_sync_timer_active, 0);
  162. }
  163. }
  164. }
  165. void cpu_throttle_init(void)
  166. {
  167. throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
  168. cpu_throttle_timer_tick, NULL);
  169. throttle_dirty_sync_timer =
  170. timer_new_ms(QEMU_CLOCK_VIRTUAL_RT,
  171. cpu_throttle_dirty_sync_timer_tick, NULL);
  172. }