RTC suupppeeerrrr slow in QEMU with KVM
RTC suupppeeerrrr slow in QEMU with KVM
I'm having trouble reading the time from the RTC twice in one second when using QEMU with KVM enabled, it's no problem using TCG, but it can take ~30s to get two consecutive reads in before it changes on me again. I'm having similar issues when handling my RTC interrupts, it takes ~500us or so to read status register C, which means with my 7ms or so interval I've just wasted ~7% of my CPU time. You'd think I just wrote slow inefficient code, but I can see that when I'm trying to get the real time I'm only spending <12% of my time actually in guest execution, <16% in QEMU itself, and the remaining >72% of the time in my host Linux kernel (probably IPC?). The problem does not go away (surprisingly) when I add the "-rtc clock=rt" or "-rtc clock=vm" flags. But, Linux guests seem to be able to get the time within the first couple millis after Grub hands execution off. To read a register from the CMOS I just send outb twice (once to the RTC, once to port 80h to wait for IO completion) and inb once to fetch the byte itself. What am I doing wrong?
Re: RTC suupppeeerrrr slow in QEMU with KVM
Changed my mind, it's slow with TCG too (just sometimes it doesn't take that long?) Should reading from the CMOS really be *this* slow?
Re: RTC suupppeeerrrr slow in QEMU with KVM
Hi,
Typically in the RTC IRQ handler you'd read from Status Register C (and ignore the value you read because you only enabled one cause and therefore know what caused the IRQ before you read Status Register C), then either:
Also note that you can make sure that all of your code always leaves IO port 0x70 left set to 0x0C (Status Register C); and in this case your IRQ handler would only ever need to do one "in al,0x71" per IRQ. This means that to access any other location/s in the CMOS you'd disable IRQs ("CLI" instruction) to ensure that the RTC's IRQ can't occur at the wrong time, then read/write the CMOS location/s you want, then set IO port 0x70 back to 0x0C, then enable IRQs. This will make any code that accesses CMOS locations slower, but in practice the only code that accesses CMOS locations is the code that initialises the RTC once during boot (and reads the time/date once during boot and initialises the "time since the epoch" variable, and sets up the RTC's IRQ) which can do whatever it likes because the RTC IRQ isn't enabled/setup yet, and code that corrects the RTC's time and date after boot (which typically only needs to happen when the OS is shut down or rebooted, if the OS detected that the RTC's time and date was wrong before the OS was shut down or rebooted).
Cheers,
Brendan
Without seeing any of the code, nobody can do anything other than take random guesses. My random guess is that there's a bug on line 14 of "rtc.c".Izzette wrote:What am I doing wrong?
Typically in the RTC IRQ handler you'd read from Status Register C (and ignore the value you read because you only enabled one cause and therefore know what caused the IRQ before you read Status Register C), then either:
- If the cause you enabled was the "(once per second) time/date update"; increment some kind of "seconds since the epoch" variable without touching any other RTC registers
- If the cause you enabled was the was the "RTC periodic interrupt", add a pre-calculated "time between periodic IRQs" value to some kind of "nano-seconds since the epoch" variable without touching any other RTC registers
Also note that you can make sure that all of your code always leaves IO port 0x70 left set to 0x0C (Status Register C); and in this case your IRQ handler would only ever need to do one "in al,0x71" per IRQ. This means that to access any other location/s in the CMOS you'd disable IRQs ("CLI" instruction) to ensure that the RTC's IRQ can't occur at the wrong time, then read/write the CMOS location/s you want, then set IO port 0x70 back to 0x0C, then enable IRQs. This will make any code that accesses CMOS locations slower, but in practice the only code that accesses CMOS locations is the code that initialises the RTC once during boot (and reads the time/date once during boot and initialises the "time since the epoch" variable, and sets up the RTC's IRQ) which can do whatever it likes because the RTC IRQ isn't enabled/setup yet, and code that corrects the RTC's time and date after boot (which typically only needs to happen when the OS is shut down or rebooted, if the OS detected that the RTC's time and date was wrong before the OS was shut down or rebooted).
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: RTC suupppeeerrrr slow in QEMU with KVM
Oh, I thought reading from CMOS RAM reset the command/mode register, and it needed to be set every time. I am however only obtaining the date/time from the RTC once and using the periodic interrupts to keep the time relative to that first date/time read (but no Unix Epoch time yet, I'm gonna have to whip out some calendar code for that, leap years, leap seconds, ugh). I have tried disabling interrupts during my RTC clock read, but do you think that the RTC periodic interrupts that aren't being handled could slow the RTC down considerably or setting the in progress flag? Regardless, I don't know why I'm not reading the clock before enabling RTC periodic interrupts (silly me). I'll switch to obtaining the time before enabling interrupts altogether, and then set the command register to status C and only read from port 71h once in my interrupt handler. We'll see how it goes ...
Next time I'll point to my code, I just felt like this problem could lay anywhere within 100s and 100s of lines and didn't expect anyone to dig that deep. Although, you have been able to help regardless.
Next time I'll point to my code, I just felt like this problem could lay anywhere within 100s and 100s of lines and didn't expect anyone to dig that deep. Although, you have been able to help regardless.
Re: RTC suupppeeerrrr slow in QEMU with KVM
Oops, found it ... *embarrassed*. Should have stared harder before coming here for the slowness of my RTC read:
https://github.com/Izzette/izix/blob/5a ... rtc.c#L230
Reading status C still seems very slow though, I even trimmed it down to:
https://github.com/Izzette/izix/blob/5a ... rtc.c#L230
Reading status C still seems very slow though, I even trimmed it down to:
Code: Select all
isr_irq8:
push %ax
in $0x71, %al
mov $0x20, %al
out %al, $0xa0
out %al, $0x20
pop %ax
iret