gettimeofday "slow" in RHEL4 guests
I noticed that gettimeofday in RHEL4.6 guests is taking much longer than with RHEL3.8 guests. I wrote a simple program (see below) to call gettimeofday in a loop 1,000,000 times and then used time to measure how long it took.
For the RHEL3.8 guest:
time -p ./timeofday_bench
real 0.99
user 0.12
sys 0.24
For the RHEL4.6 guest with the default clock source (pmtmr):
time -p ./timeofday_bench
real 15.65
user 0.18
sys 15.46
and RHEL4.6 guest with PIT as the clock source (clock=pit kernel parameter):
time -p ./timeofday_bench
real 13.67
user 0.21
sys 13.45
So, basically gettimeofday() takes about 50 times as long on a RHEL4 guest.
Host is a DL380G5, 2 dual-core Xeon 5140 processors, 4 GB of RAM. It's running kvm.git tree as of 11/18/08 with kvm-75 userspace. Guest in both RHEL3 and RHEL4 cases has 4 vcpus, 3.5GB of RAM.
david
----------
timeofday_bench.c:
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int rc = 0, n;
struct timeval tv;
int iter = 1000000; /* number of times to call gettimeofday */
if (argc > 1)
iter = atoi(argv[1]);
if (iter == 0) {
fprintf(stderr, "invalid number of iterations\n");
return 1;
}
printf("starting.... ");
for (n = 0; n < iter; ++n) {
if (gettimeofday(&tv, NULL) != 0) {
fprintf(stderr, "\ngettimeofday failed\n");
rc = 1;
break;
}
}
if (!rc)
printf("done\n");
return rc;
}Some more data on this overhead.
RHEL3 (which is based on the 2.4.21 kernel) gets microsecond resolutions by reading the TSC. Reading the TSC from within a guest is very fast on kvm.
RHEL4 (which is basd on the 2.6.9 kernel) allows multiple time sources:
pmtmr (ACPI power management timer which is the default), pit, hpet and TSC.
The pmtmr and pit both do ioport reads to get microsecond resolutions (see read_pmtmr and get_offset_pit, respectively). For the tsc as the timer source gettimeofday is *very* lightweight, but time drifts very badly and ntpd cannot acquire a sync. I believe someone is working on the HPET for guests and I know from bare metal performance that it is a much lighter weight time source, but with RHEL4 the HPET breaks the ability to use the RTC. So, I'm running out of options for reliable and lightweight time sources.
Any chance the pit or pmtmr options can be optimized a bit?
thanks,
david
PS. yes, I did try the userspace pit and its performance is worse than the in-kernel PIT.
Quoted 73 lines · David S. Ahern
I noticed that gettimeofday in RHEL4.6 guests is taking much longer than with RHEL3.8 guests. I wrote a simple program (see below) to call gettimeofday in a loop 1,000,000 times and then used time to measure how long it took.
For the RHEL3.8 guest:
time -p ./timeofday_bench
real 0.99
user 0.12
sys 0.24For the RHEL4.6 guest with the default clock source (pmtmr):
time -p ./timeofday_bench
real 15.65
user 0.18
sys 15.46and RHEL4.6 guest with PIT as the clock source (clock=pit kernel parameter):
time -p ./timeofday_bench
real 13.67
user 0.21
sys 13.45So, basically
gettimeofday()takes about 50 times as long on a RHEL4 guest.Host is a DL380G5, 2 dual-core Xeon 5140 processors, 4 GB of RAM. It's running kvm.git tree as of 11/18/08 with kvm-75 userspace. Guest in both RHEL3 and RHEL4 cases has 4 vcpus, 3.5GB of RAM.
david
----------
timeofday_bench.c:#include <
sys/time.h>
#include <stdio.h>
#include <stdlib.h>int
main(int argc, char *argv[]){ int rc = 0, n; struct timeval tv; int iter = 1000000; /* number of times to call gettimeofday */ if (argc > 1) iter = atoi(argv[1]); if (iter == 0) { fprintf(stderr, "invalid number of iterations\n"); return 1; } printf("starting.... "); for (n = 0; n < iter; ++n) { if (gettimeofday(&tv, NULL) != 0) { fprintf(stderr, "\ngettimeofday failed\n"); rc = 1; break; } } if (!rc) printf("done\n"); return rc; }--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 2 lines · David S. Ahern
Any chance the pit or pmtmr options can be optimized a bit?
They both will require vmexits and never be really fast. Same for HPET. If you want fast gtod you really need to make TSC work.
-Andi
Signature · 1 line
[email protected]
Quoted 6 lines · Andi Kleen
Quoted 2 lines · David S. Ahern
Any chance the pit or pmtmr options can be optimized a bit?
They both will require vmexits and never be really fast. Same for HPET. If you want fast gtod you really need to make TSC work.
Why does hpet need to be slow? Can't you just 1:1 pass through one of the hpet timers if you only have a limited amount of vms? If done cleverly this might even work if #hpet > #cpu.
Alex
Quoted 10 lines
-Andi
Signature · 5 lines
[email protected] -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 2 lines
Why does hpet need to be slow? Can't you just 1:1 pass through one of the hpet timers if you only have a limited amount of vms?
HPET is not a truly virtualizable device, it's all the counters in one block that cannot be really mapped to different people.
Also most systems have very little counters and Linux typically needs two at least (system timer and /dev/hpet)
Quoted 1 line
If done cleverly this might even work if #hpet > #cpu.
Sure with a device model, but that needs vmexits.
-Andi
Quoted 5 lines · Andi Kleen
Quoted 2 lines
Why does hpet need to be slow? Can't you just 1:1 pass through one of the hpet timers if you only have a limited amount of vms?
HPET is not a truly virtualizable device, it's all the counters in one block that cannot be really mapped to different people.
Right, you'd have to remap stuff on non-page boundaries which is probably pretty hard to do. Otherwise you wouldn't gain anything, since you'd still have exits to reprogram the hpet.
Quoted 2 lines
Also most systems have very little counters and Linux typically needs two at least (system timer and
/dev/hpet)
Well, IIRC 3 is a pretty normal amount and blocking /dev/hpet if the hpet is in use shouldn't be a problem.
But yeah - the remapping of HPET timers to virtual HPET timers sounds pretty tough. I wonder if one could overcome that with a little hardware support though ...
Alex
Quoted 3 lines
But yeah - the remapping of HPET timers to virtual HPET timers sounds pretty tough. I wonder if one could overcome that with a little hardware support though ...
For gettimeofday better make TSC work. Even in the best case (no virtualization) it is much faster than HPET because it sits in the CPU, while HPET is far away on the external south bridge.
For other HPET usages (interval timer etc.) which are less performance critical I suppose vmexits are
not a serious problem so a standard software device model should work.
-Andi
Quoted 11 lines · David S. Ahern
RHEL3 (which is based on the 2.4.21 kernel) gets microsecond resolutions
by reading the TSC. Reading the TSC from within a guest is very fast on kvm.RHEL4 (which is basd on the 2.6.9 kernel) allows multiple time sources:
pmtmr (ACPI power management timer which is the default), pit, hpet and TSC.
Quoted 4 lines
The pmtmr and pit both do ioport reads to get microsecond resolutions (see
read_pmtmrandget_offset_pit, respectively). For the tsc as the timer source gettimeofday is *very* lightweight, but time drifts very badly and ntpd cannot acquire a sync.
Why aren't you seeing severe time drift when using RHEL3 guests with the TSC time source?
Signature · 2 lines
Hollis Blanchard IBM Linux Technology Center
Quoted 11 lines · Hollis Blanchard
Quoted 10 lines · David S. Ahern
RHEL3 (which is based on the 2.4.21 kernel) gets microsecond resolutions
by reading the TSC. Reading the TSC from within a guest is very fast on kvm.RHEL4 (which is basd on the 2.6.9 kernel) allows multiple time sources:
pmtmr (ACPI power management timer which is the default), pit, hpet and TSC.
Quoted 8 lines
Quoted 4 lines
The pmtmr and pit both do ioport reads to get microsecond resolutions (see
read_pmtmrandget_offset_pit, respectively). For the tsc as the timer source gettimeofday is *very* lightweight, but time drifts very badly and ntpd cannot acquire a sync.Why aren't you seeing severe time drift when using RHEL3 guests with the TSC time source?
With RHEL3 it's a PIT time source, and the PIT counter is only read on interrupts. For gettimeofday requests only the tsc is read; the algorithm for microsecond resolution uses the pit count and its tsc timestamp from the last interrupt.
In RHEL4, the PIT counter is read for each gettimeofday request when it is the timer source. That's the cause of the extra overhead, and consequently, worse performance.
david
Quoted 7 lines · Andi Kleen
Quoted 3 lines
But yeah - the remapping of HPET timers to virtual HPET timers sounds pretty tough. I wonder if one could overcome that with a little hardware support though ...
For gettimeofday better make TSC work. Even in the best case (no virtualization) it is much faster than HPET because it sits in the CPU, while HPET is far away on the external south bridge.
The tsc clock on older Linux 2.6 kernels compensates for lost ticks. The algorithm uses the PIT count (latched) to measure the delay between interrupt generation and handling, and sums that value, on the next interrupt, to the TSC delta.
Sheng investigated this problem in the discussions before in-kernel PIT was merged:
http://www.mail-archive.com/[email protected]/msg13873.html
The algorithm overcompensates for lost ticks and the guest time runs faster than the hosts.
There are two issues:
1) A bug in the in-kernel PIT which miscalculates the count value.
2) For the case where more than one interrupt is lost, and later reinjected, the value read from PIT count is meaningless for the purpose of the tsc algorithm. The count is interpreted as the delay until the next interrupt, which is not the case with reinjection.
As Sheng mentioned in the thread above, Xen pulls back the TSC value when reinjecting interrupts. VMWare ESX has a notion of "virtual TSC", which I believe is similar in this context.
For KVM I believe the best immediate solution (for now) is to provide an option to disable reinjection, behaving similarly to real hardware. The advantage is simplicity compared to virtualizing the time sources.
The QEMU PIT emulation has a limit on the rate of interrupt reinjection, perhaps something similar should be investigated in the future.
The following patch (which contains the bugfix for 1) and disabled reinjection) fixes the severe time drift on RHEL4 with "clock=tsc". What I'm proposing is to condition reinjection with an option (-kvm-pit-no-reinject or something).
Comments or better ideas?
arch/x86/kvm/i8254.c +4 -1
@@ -201,13 +201,16 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)if (!atomic_inc_and_test (&pt->pending))set_bit (KVM_REQ_PENDING_TIMER , &vcpu0->requests); +if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +if (vcpu0 &&waitqueue_active (&vcpu0->wq))wake_up_interruptible (&vcpu0->wq);hrtimer_add_expires_ns (&pt->timer, pt->period); pt->scheduled =hrtimer_get_expires_ns (&pt->timer);if (pt->period) - ps->channels[0 ].count_load_time =hrtimer_get_expires (&pt->timer); + ps->channels[0 ].count_load_time =ktime_get ();return (pt->period ==0 ?0 :1 ); }
Quoted 39 lines · On Monday 29 December 2008 02:38:07 Marcelo Tosatti wrote:
Quoted 7 lines · Andi Kleen
Quoted 3 lines
But yeah - the remapping of HPET timers to virtual HPET timers sounds pretty tough. I wonder if one could overcome that with a little hardware support though ...
For gettimeofday better make TSC work. Even in the best case (no virtualization) it is much faster than HPET because it sits in the CPU, while HPET is far away on the external south bridge.
The tsc clock on older Linux 2.6 kernels compensates for lost ticks. The algorithm uses the PIT count (latched) to measure the delay between interrupt generation and handling, and sums that value, on the next interrupt, to the TSC delta.
Sheng investigated this problem in the discussions before in-kernel PIT was merged:
http://www.mail-archive.com/[email protected]/msg13873.html
The algorithm overcompensates for lost ticks and the guest time runs faster than the hosts.
There are two issues:
1) A bug in the in-kernel PIT which miscalculates the count value.
2) For the case where more than one interrupt is lost, and later reinjected, the value read from PIT count is meaningless for the purpose of the tsc algorithm. The count is interpreted as the delay until the next interrupt, which is not the case with reinjection.
As Sheng mentioned in the thread above, Xen pulls back the TSC value when reinjecting interrupts. VMWare ESX has a notion of "virtual TSC", which I believe is similar in this context.
For KVM I believe the best immediate solution (for now) is to provide an option to disable reinjection, behaving similarly to real hardware. The advantage is simplicity compared to virtualizing the time sources.
Quoted 7 lines
The QEMU PIT emulation has a limit on the rate of interrupt reinjection, perhaps something similar should be investigated in the future.
The following patch (which contains the bugfix for 1) and disabled reinjection) fixes the severe time drift on RHEL4 with "clock=tsc". What I'm proposing is to condition reinjection with an option (-kvm-pit-no-reinject or something).
I agree that it should go with a user space option to disable rejection, as it's hard to overcome the problem that we delayed interrupt injection...
Signature · 2 lines
regards Yang, Sheng
Quoted 25 lines
Comments or better ideas?
arch/x86/kvm/i8254.c +4
-1@@ -201,13 +201,16 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)if (!atomic_inc_and_test (&pt->pending))set_bit (KVM_REQ_PENDING_TIMER , &vcpu0->requests); +if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +if (vcpu0 &&waitqueue_active (&vcpu0->wq))wake_up_interruptible (&vcpu0->wq);hrtimer_add_expires_ns (&pt->timer, pt->period); pt->scheduled =hrtimer_get_expires_ns (&pt->timer);if (pt->period) - ps->channels[0 ].count_load_time =hrtimer_get_expires (&pt->timer); + ps->channels[0 ].count_load_time =ktime_get ();return (pt->period ==0 ?0 :1 ); }
Quoted 46 lines · Marcelo Tosatti
The tsc clock on older Linux 2.6 kernels compensates for lost ticks. The algorithm uses the PIT count (latched) to measure the delay between interrupt generation and handling, and sums that value, on the next interrupt, to the TSC delta.
Sheng investigated this problem in the discussions before in-kernel PIT was merged:
http://www.mail-archive.com/[email protected]/msg13873.html
The algorithm overcompensates for lost ticks and the guest time runs faster than the hosts.
There are two issues:
1) A bug in the in-kernel PIT which miscalculates the count value.
2) For the case where more than one interrupt is lost, and later reinjected, the value read from PIT count is meaningless for the purpose of the tsc algorithm. The count is interpreted as the delay until the next interrupt, which is not the case with reinjection.
As Sheng mentioned in the thread above, Xen pulls back the TSC value when reinjecting interrupts. VMWare ESX has a notion of "virtual TSC", which I believe is similar in this context.
For KVM I believe the best immediate solution (for now) is to provide an option to disable reinjection, behaving similarly to real hardware. The advantage is simplicity compared to virtualizing the time sources.
The QEMU PIT emulation has a limit on the rate of interrupt reinjection, perhaps something similar should be investigated in the future.
The following patch (which contains the bugfix for 1) and disabled reinjection) fixes the severe time drift on RHEL4 with "clock=tsc". What I'm proposing is to condition reinjection with an option (-kvm-pit-no-reinject or something).
Comments or better ideas?
arch/x86/kvm/i8254.c +0
-0
arch/x86/kvm/i8254.c static int __pit_timer_fn(struct kvm_kpit_state *ps) · line 207
Quoted 7 lines
arch/x86/kvm/i8254.c +3
-0@@ -201,13 +201,16 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)if (!atomic_inc_and_test (&pt->pending))set_bit (KVM_REQ_PENDING_TIMER , &vcpu0->requests); +if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +
Replace the atomic_inc() with atomic_set(, 1) instead? One less test, and more important, the logic is scattered less around the source.
Quoted 10 lines
arch/x86/kvm/i8254.c +1
-1if (vcpu0 &&waitqueue_active (&vcpu0->wq))wake_up_interruptible (&vcpu0->wq);hrtimer_add_expires_ns (&pt->timer, pt->period); pt->scheduled =hrtimer_get_expires_ns (&pt->timer);if (pt->period) - ps->channels[0 ].count_load_time =hrtimer_get_expires (&pt->timer); + ps->channels[0 ].count_load_time =ktime_get ();return (pt->period ==0 ?0 :1 );
Quoted 2 lines
}
I don't like the idea of punting to the user but looks like we don't have a choice. Hopefully vendors will port kvmclock to these kernels and release them as updates -- time simply doesn't work will with virtualization, especially Linux guests.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 52 lines · Avi Kivity
Quoted 51 lines · Marcelo Tosatti
The tsc clock on older Linux 2.6 kernels compensates for lost ticks. The algorithm uses the PIT count (latched) to measure the delay between interrupt generation and handling, and sums that value, on the next interrupt, to the TSC delta.
Sheng investigated this problem in the discussions before in-kernel PIT was merged:
http://www.mail-archive.com/[email protected]/msg13873.html
The algorithm overcompensates for lost ticks and the guest time runs faster than the hosts.
There are two issues:
1) A bug in the in-kernel PIT which miscalculates the count value.
2) For the case where more than one interrupt is lost, and later reinjected, the value read from PIT count is meaningless for the purpose of the tsc algorithm. The count is interpreted as the delay until the next interrupt, which is not the case with reinjection.
As Sheng mentioned in the thread above, Xen pulls back the TSC value when reinjecting interrupts. VMWare ESX has a notion of "virtual TSC", which I believe is similar in this context.
For KVM I believe the best immediate solution (for now) is to provide an option to disable reinjection, behaving similarly to real hardware. The advantage is simplicity compared to virtualizing the time sources.
The QEMU PIT emulation has a limit on the rate of interrupt reinjection, perhaps something similar should be investigated in the future.
The following patch (which contains the bugfix for 1) and disabled reinjection) fixes the severe time drift on RHEL4 with "clock=tsc". What I'm proposing is to condition reinjection with an option (-kvm-pit-no-reinject or something).
Comments or better ideas?
arch/x86/kvm/i8254.c +0
-0@@ -201,13 +201,16 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)if (!atomic_inc_and_test (&pt->pending))set_bit (KVM_REQ_PENDING_TIMER , &vcpu0->requests);
Quoted 6 lines
arch/x86/kvm/i8254.c static int __pit_timer_fn(struct kvm_kpit_state *ps) · line 209
Quoted 4 lines
arch/x86/kvm/i8254.c +3
-0+if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +Replace the
atomic_inc()withatomic_set(, 1)instead? One less test, and more important, the logic is scattered less around the source.
But having only a pending bit instead of a counter will cause kvm to drop pit irqs on rare high load situations. The disable reinjection option is better.
Quoted 11 lines
Quoted 11 lines
arch/x86/kvm/i8254.c +1
-1if (vcpu0 &&waitqueue_active (&vcpu0->wq))wake_up_interruptible (&vcpu0->wq);hrtimer_add_expires_ns (&pt->timer, pt->period); pt->scheduled =hrtimer_get_expires_ns (&pt->timer);if (pt->period) - ps->channels[0 ].count_load_time =hrtimer_get_expires (&pt->timer); + ps->channels[0 ].count_load_time =ktime_get ();
Quoted 6 lines
Quoted 3 lines
return (pt->period == 0 ? 0 : 1);}
I don't like the idea of punting to the user but looks like we don't have a choice. Hopefully vendors will port kvmclock to these kernels and release them as updates -- time simply doesn't work will with virtualization, especially Linux guests.
Except for these 'tsc compensate' guest, what are the occasions where the guest writes his tsc? If this is the only case we can disable reinjection once we trap tsc writes.
Quoted 9 lines · Dor Laor
Quoted 7 lines
arch/x86/kvm/i8254.c static int __pit_timer_fn(struct kvm_kpit_state *ps) · line 206
Quoted 5 lines
arch/x86/kvm/i8254.c +3
-0+if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +Replace the
atomic_inc()withatomic_set(, 1)instead? One less test, and more important, the logic is scattered less around the source.But having only a pending bit instead of a counter will cause kvm to drop pit irqs on rare high load situations. The disable reinjection option is better.
Both variants disable reinjection. Forcing a counter to 1 every time it exceeds 1 is equivalent to maintaining a bit.
In both variants, there is a missing 'if (disable_reinjection)' (Marcelo mentioned this in the original message).
Quoted 2 lines
Except for these 'tsc compensate' guest, what are the occasions where the guest writes his tsc? If this is the only case we can disable reinjection once we trap tsc writes.
I don't think these guests write to the tsc. Rather, they read the tsc and the pit counters and try to correlate. And fail.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 9 lines · Dor Laor
Quoted 7 lines
arch/x86/kvm/i8254.c static int __pit_timer_fn(struct kvm_kpit_state *ps) · line 206
Quoted 5 lines
arch/x86/kvm/i8254.c +3
-0+if (atomic_read (&pt->pending) >1 ) +atomic_set (&pt->pending,1 ); +Replace the
atomic_inc()withatomic_set(, 1)instead? One less test, and more important, the logic is scattered less around the source.But having only a pending bit instead of a counter will cause kvm to drop pit irqs on rare high load situations. The disable reinjection option is better.
Both variants disable reinjection. Forcing a counter to 1 every time it exceeds 1 is equivalent to maintaining a bit.
In both variants, there is a missing 'if (disable_reinjection)' (Marcelo mentioned this in the original message).
Quoted 2 lines
Except for these 'tsc compensate' guest, what are the occasions where the guest writes his tsc? If this is the only case we can disable reinjection once we trap tsc writes.
I don't think these guests write to the tsc. Rather, they read the tsc and the pit counters and try to correlate. And fail.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.