[PATCH 0/3] remove the periodic RTC update timer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



	Recently, I did some work for power optimization w/ KVM and I found there was a periodic timer from qemu which stop the platform from staying deep C state for a long period. After looking into the qemu code, there was a periodic RTC update timer which is the culprit. In current RTC emulation logic, it use a periodic timer(1 per second) to update RTC clock. Though 1 second is long enough, when run more guests(for example 32, 64 ), you will see the impaction is more than expected. In my case, I run 64 VMs and all of them are idle. When enable the RTC update timer, the package C6 residency decreased about 7% which means 2 watts in my case. So it would be better to stop the periodic RTC update timer.
	The following patch remove the periodic RTC update timer and use host time with offset to calculate the RTC clock instead:
PATCH 1: use int64 when compare two time.
	int32 only represent only 136 years when comparing two times based on second. It would be better to use int64.

PATCH 2: use gettimeofday() instead of time(). 
	Though the two functions both give the number of seconds since Epoch, I found they will return different value on some rare occasion. For example, I saw the getimeofday gives the number of seconds as A, but the time() function still gives the (A-1). And this happen at the begin of every second. After checking the implementation of the two functions in kernel, I found the time() return the wall_time_sec directly and gettimeofday() will do a double check w/ TSC or HPET if available to get more accurate time. For example, if now is 99.999s, and an event happen which update wall_time_sec to 99s. After 0.001s, userspace call gettimeofday() and time() at same time. For gettimeofday(), it will read wall_time_sec and check w/ TSC. Then he will found now is 100s and return 100s. But for time(), it return 99s directly even now is 100s. 
In current QEMU, the timer logic is based on gettimeofday(), but the qemu_get_timedate is using time() to get time. As mentioned before, this will cause problems at some time.
For example:
The following code is to emulation a RTC alarm logic in the third patch:
static void rtc_alarm_interrupt(void *opaque)
{
     qemu_get_timedate(&tm, s->offset);

    /* check alarm */
    if (((rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == tm.tm_sec) &&
        rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == tm.tm_min) &&
        rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == tm.tm_hour)
           qemu_irq_raise(s->irq);
        
    s->next_alarm_time += get_ticks_per_sec();
    qemu_mod_timer(s->alarm_timer, s->next_alarm_time);
}
Suppose that now is 12:00:0, set an alarm at 12:00:10 and start a timer that expired at 12:00:10. At the begin of 12:00:10, the timer(which base on gettimeofday()) is fired and the callback function will call qemu_get_timedate(based on time()) to get current time. As mentioned before, the value returned by time() may slower than real time at the beginning of every second. And the alarm will not be triggered. Then the guest will disable the alarm and the alarm will have no chance to be fired.

PATCH 3: change the RTC update logic to use host time with offset to calculate RTC clock.
	There have no need to use two periodic timers to maintain an internal timer for RTC clock update and alarm check. Instead, we calculate the real RTC time by the host time with an offset. For alarm and updated-end interrupt, if guest enabled it, then we setup a timer, or else, stop it.

best regards
yang


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux