option -no-tsc for i386 with speedstep
PATCH 1/1 option -no-tsc for i386 with speedstep
When qemu runs on an i386 cpu with speedstep enabled the clock of the guest os is not in sync with the clock on the host os because the vm_timer used for irq 0 generates interrupts at wrong rate when the host cpu frequency changes.
The problem is that the vm_timer uses the rdtsc instruction and the value of ticks_per_sec, computed at start time, for calculating the expire time of vm_timers. While ticks_per_sec is constant the values returned by rdtsc are dependent on the current cpu clock, which is not constant if speedstep is used.
The problem can be cleary observed by running "xclock -update 1" in the guest os and observing how the clock speed varies with the cpu freqency.
The following patch fixes the problem by adding a new option -no-tsc for the i386 architecture which can be used to disable rdtsc when running on a cpu with speedstep enabled.
The patch works for me but I don't know if this is the best way of fixing this bug. If anyone has a better suggestion it is welcome.
Signature · 1 line
Massimo Dal Zotto <[email protected]>
vl.c +19 -0
@@ -135,6 +135,10 @@int prep_enabled =0 ;int rtc_utc =1 ;int cirrus_vga_enabled =1 ; +#ifdef __i386__ +static int notsc =0 ; +extern int64_t get_clock (void ); +#endif #ifdef TARGET_SPARC int graphic_width =1024 ;int graphic_height =768 ;
@@ -502,6 +506,9 @@int64_t cpu_get_real_ticks (void ) {int64_t val; +if (notsc) { +return get_clock (); + } asmvolatile ("rdtsc" :"=A" (val));return val; }
@@ -2792,6 +2799,9 @@#ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n"#endif +#ifdef __i386__ + "-no-tsc disable tsc as clock source\n" +#endif #ifdef TARGET_I386 "-isa simulate an ISA-only system (default is PCI system)\n" "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
@@ -2863,6 +2873,7 @@ QEMU_OPTION_hdachs,QEMU_OPTION_L , QEMU_OPTION_no_code_copy, + QEMU_OPTION_no_tsc, QEMU_OPTION_pci, QEMU_OPTION_isa, QEMU_OPTION_prep,
@@ -2931,6 +2942,9 @@ #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, #endif +#ifdef __i386__ + { "no-tsc", 0, QEMU_OPTION_no_tsc }, +#endif #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif
@@ -3216,6 +3230,11 @@case QEMU_OPTION_no_code_copy: code_copy_enabled =0 ;break ; +#ifdef __i386__ +case QEMU_OPTION_no_tsc: + notsc =1 ; +break ; +#endif case QEMU_OPTION_nics: nb_nics =atoi (optarg);if (nb_nics <0 || nb_nics >MAX_NICS ) {
Quoted 8 lines · Massimo Dal Zotto
When qemu runs on an i386 cpu with speedstep enabled the clock of the guest os is not in sync with the clock on the host os because the
vm_timerused for irq 0 generates interrupts at wrong rate when the host cpu frequency changes.The following patch fixes the problem by adding a new option -no-tsc for the i386 architecture which can be used to disable rdtsc when running on a cpu with speedstep enabled.
Unfortunately this patch, effectively replacing a single assembly instruction by a gettimeofday() call, slows some operations down to a degree that makes a WinXP guest on GNU/Linux host nearly unusable at network and file system operations (at least here).
- Heike
Quoted 5 lines · Massimo Dal Zotto
The patch works for me but I don't know if this is the best way of fixing this bug. If anyone has a better suggestion it is welcome.
Signature · 1 line
Massimo Dal Zotto <[email protected]>
I just want to point out that your patches break qemu for almost every platform other than i386.
Quoted 6 lines
vl.c +4
-0+#ifdef __i386__ +static int notsc =0 ; +extern int64_t get_clock (void ); +#endif
vl.c line 514
Quoted 9 lines
vl.c +3
-0@@ -502,6 +506,9 @@int64_t cpu_get_real_ticks (void ) {int64_t val; +if (notsc) { +return get_clock (); + } asmvolatile ("rdtsc" :"=A" (val));return val; }
You probably want to do this, because notsc is only declared for the i386 platform.
int64_t cpu_get_real_ticks(void)
{
int64_t val;+#ifdef __i386__
+ if (notsc) {
+ return get_clock();
+ }
+#endif
asm volatile ("rdtsc" : "=A" (val));
return val;}
Signature · 2 lines
Infinite complexity begets infinite beauty. Infinite precision begets infinite perfection.
Quoted 9 lines · Jim C. Brown
Quoted 5 lines · Massimo Dal Zotto
The patch works for me but I don't know if this is the best way of fixing this bug. If anyone has a better suggestion it is welcome.
--
Massimo Dal Zotto <[email protected]>I just want to point out that your patches break qemu for almost every platform other than i386.
Rubbish.
<snip>
Quoted 6 lines
You probably want to do this, because notsc is only declared for the i386 platform.
int64_tcpu_get_real_ticks(void){ int64_t val;
vl.c line 514
Quoted 8 lines
vl.c +5
-0+#ifdef __i386__ +if (notsc) { +return get_clock (); + } +#endif asmvolatile ("rdtsc" :"=A" (val));return val; }
This is already inside a #if defined(__i386__) block
Paul
Quoted 11 lines · Jim C. Brown
I just want to point out that your patches break qemu for almost every platform other than i386.
You probably want to do this, because notsc is only declared for the i386 platform.
int64_tcpu_get_real_ticks(void){ int64_t val;
vl.c line 514
Quoted 8 lines
vl.c +5
-0+#ifdef __i386__ +if (notsc) { +return get_clock (); + } +#endif asmvolatile ("rdtsc" :"=A" (val));return val; }
Correct, I forgot the #ifdef inside that function.
I made also some more tests and it turned out that my patch works but not as expected. The clock now runs at constant rate at any speedstep frequency, which is what I wanted, but unfortunately it is always ~20% slower than wall clock.
I tried also to force different values of ticks_per_sec but it seems that it has no effects on irq frequency, so there must be something that I don't understand in the timer code.
Any idea on how to fix this bug?
Signature · 1 line
Massimo Dal Zotto <[email protected]>
Quoted 9 lines · Jim C. Brown
I just want to point out that your patches break qemu for almost every platform other than i386.
[..]
You probably want to do this, because notsc is only declared for the i386 platform.
int64_tcpu_get_real_ticks(void){ int64_t val;
vl.c line 514
Quoted 8 lines
vl.c +5
-0+#ifdef __i386__ +if (notsc) { +return get_clock (); + } +#endif asmvolatile ("rdtsc" :"=A" (val));return val; }
His patch gets inserted after an '#elif defined(__i386__)' directive (at least the part cited above).
- Heike
Quoted 14 lines · Massimo Dal Zotto
When qemu runs on an i386 cpu with speedstep enabled the clock of the guest os is not in sync with the clock on the host os because the
vm_timerused for irq 0 generates interrupts at wrong rate when the host cpu frequency changes.The problem is that the
vm_timeruses the rdtsc instruction and the value ofticks_per_sec, computed at start time, for calculating the expire time ofvm_timers. Whileticks_per_secis constant the values returned by rdtsc are dependent on the current cpu clock, which is not constant if speedstep is used.The problem can be cleary observed by running "xclock -update 1" in the guest os and observing how the clock speed varies with the cpu freqency.
Quoted 6 lines
The following patch fixes the problem by adding a new option -no-tsc for the i386 architecture which can be used to disable rdtsc when running on a cpu with speedstep enabled.
The patch works for me but I don't know if this is the best way of fixing this bug. If anyone has a better suggestion it is welcome.
This is not the best way to fix the bug. I see 4 solutions:
- Compute ticks_per_sec every n seconds and update the timers accordingly.
- Use a virtual cycle counter and update ticks_per_sec dynamically. This solution has the advantage of not needing any precise host timer (= very portable), but it will slow down QEMU a bit.
- Use a specific driver to get the time efficiently (= without system call) or to know when the host frequency changes
- Disable speedstep or use a CPU for which the rdtsc period does not vary even if the CPU frequency changes (the P4 has this feature if I remember correctly and all well designed CPUs should have such a feature !).
Fabrice.
Quoted 4 lines · Fabrice Bellard
This is not the best way to fix the bug. I see 4 solutions:
- Compute
ticks_per_secevery n seconds and update the timers accordingly.
This won't work well if an userpace scaling governor is continuously changing the cpu frequency depending on system load (which is often generated by qemu itself) as happens on my laptop.
Quoted 3 lines
- Use a virtual cycle counter and update
ticks_per_secdynamically. This solution has the advantage of not needing any precise host timer (= very portable), but it will slow down QEMU a bit.
How could a virtual cycle counter measure real time with accuracy?
Quoted 6 lines
- Use a specific driver to get the time efficiently (= without system call) or to know when the host frequency changes
- Disable speedstep or use a CPU for which the rdtsc period does not vary even if the CPU frequency changes (the P4 has this feature if I remember correctly and all well designed CPUs should have such a feature !).
Speedstep is needed to save battery charge and my cpu, which is a recent centrino, returns a variable rdtsc result. We are condemned to use whichever cpu laptop makers decide to put in our laptops.
The tsc timer code in kernel 2.6 has an algorithm to compute a constant clock rate from a variable tsc but I don't know how this could be ported in user space. Could this code be reused, maybe with the help of kqemu?
In the meantime until we find a better solution could you give us some explanation on why using a microseconds clock from gettimeofday instead of rdtsc the guest os clock runs always 20% slower?
Having an almost precise system clock is a normal requirement and I believe than even a sub-optimal solution would be better than a constantly wrong clock like many of us are experiencing.
Signature · 1 line
Massimo Dal Zotto
Quoted 3 lines · Massimo Dal Zotto
In the meantime until we find a better solution could you give us some explanation on why using a microseconds clock from gettimeofday instead of rdtsc the guest os clock runs always 20% slower?
Because a system call (which gettimeofday is) is very slow (two context switches).
Jonas
Quoted 7 lines · Jonas Maebe
Quoted 3 lines · Massimo Dal Zotto
In the meantime until we find a better solution could you give us some explanation on why using a microseconds clock from gettimeofday instead of rdtsc the guest os clock runs always 20% slower?
Because a system call (which gettimeofday is) is very slow (two context switches).
I remember there was a Linux patch which changed the gettimeofday function to read the info from user mode shared page (which is updated by the kernel) and thus avoided the syscall overhead. Not sure if/when it was integrated into the official sources...
(Once again Windows NT were ahead of time with this idea implemented way earlier ;-)
- Filip
Quoted 2 lines · Filip Navara
(Once again Windows NT were ahead of time with this idea implemented way earlier ;-)
Strange, I got report from people testing stuff in Wine (about the same RTDSC problem with laptops) finding out that 'gettimeofday' was taking less time than 'QueryPerformanceCounter' in Windows (ie more calls per seconds).
Lionel
Signature · 1 line
Lionel Ulmer - http://www.bbrox.org/
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Quoted 14 lines · Filip Navara
Quoted 10 lines · Jonas Maebe
Quoted 4 lines · Massimo Dal Zotto
In the meantime until we find a better solution could you give us some explanation on why using a microseconds clock from gettimeofday instead of rdtsc the guest os clock runs always 20% slower?
Because a system call (which gettimeofday is) is very slow (two context switches).
Quoted 7 lines
I remember there was a Linux patch which changed the gettimeofday function to read the info from user mode shared page (which is updated by the kernel) and thus avoided the syscall overhead. Not sure if/when it was integrated into the official sources...
(Once again Windows NT were ahead of time with this idea implemented way earlier ;-)
Another *solution* is to use kernel mode linux =). See
http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/
It makes already low Linux syscall overhead much lower.
Tara
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFCbXMfmzwUPloTW30RAg+7AKCh0jGnYhvRp0/qtwm36wXDrCxd2ACgpdMi LBQsxo56m98yPvkAPFJ0PAQ=
=jpKR
-----END PGP SIGNATURE-----
Re: [Qemu-devel] [patch] option -no-tsc for i386 with speedstep (solved)
In reply to Jonas MaebeQuoted 10 lines · Jonas Maebe
Quoted 3 lines · Massimo Dal Zotto
In the meantime until we find a better solution could you give us some explanation on why using a microseconds clock from gettimeofday instead of rdtsc the guest os clock runs always 20% slower?
Because a system call (which gettimeofday is) is very slow (two context switches).
No, it has nothing to do with the speed of gettimeofday, which on my pc takes only a few microsecons to execute.
The problem seems in (rounding?) errors in computations of ticks_per_sec and/or next_transition_time and was solved (om my 600/1800 laptop) by replacing the following instruction in my previous patch
return get_clock();
with
return get_clock()<<12;
It seems that simply changing the scale of ticks values reduces the computation errors in the timer code, which must be somewhere even if I haven't been able to find them.
The clock in the guest os is now running at the correct speed and the sleep(1) command takes the exact real time to execute at any cpu speed.
The following patch should be then the correct one.
Signature · 1 line
Massimo Dal Zotto
vl.c +20 -0
@@ -135,6 +135,10 @@int prep_enabled =0 ;int rtc_utc =1 ;int cirrus_vga_enabled =1 ; +#ifdef __i386__ +static int notsc =0 ; +extern int64_t get_clock (void ); +#endif #ifdef TARGET_SPARC int graphic_width =1024 ;int graphic_height =768 ;
@@ -502,6 +506,9 @@int64_t cpu_get_real_ticks (void ) {int64_t val; +if (notsc) { +return get_clock ()<<12 ; + } asmvolatile ("rdtsc" :"=A" (val));return val; }
@@ -590,6 +597,7 @@ usec =get_clock () - usec; ticks =cpu_get_real_ticks () - ticks; ticks_per_sec = (ticks *1000000LL + (usec >>1 )) / usec; +//printf("ticks_per_sec=%lld\n",ticks_per_sec); }/* compute with 96 bit intermediate result: (a*b)/c */
@@ -2792,6 +2800,9 @@#ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n"#endif +#ifdef __i386__ + "-no-tsc disable tsc as clock source\n" +#endif #ifdef TARGET_I386 "-isa simulate an ISA-only system (default is PCI system)\n" "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
@@ -2863,6 +2874,7 @@ QEMU_OPTION_hdachs,QEMU_OPTION_L , QEMU_OPTION_no_code_copy, + QEMU_OPTION_no_tsc, QEMU_OPTION_pci, QEMU_OPTION_isa, QEMU_OPTION_prep,
@@ -2931,6 +2943,9 @@ #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, #endif +#ifdef __i386__ + { "no-tsc", 0, QEMU_OPTION_no_tsc }, +#endif #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif
@@ -3216,6 +3231,11 @@case QEMU_OPTION_no_code_copy: code_copy_enabled =0 ;break ; +#ifdef __i386__ +case QEMU_OPTION_no_tsc: + notsc =1 ; +break ; +#endif case QEMU_OPTION_nics: nb_nics =atoi (optarg);if (nb_nics <0 || nb_nics >MAX_NICS ) {
Re: [Qemu-devel] [patch] option -no-tsc for i386 with speedstep (solved)
Quoted 2 lines · Massimo Dal Zotto
No, it has nothing to do with the speed of gettimeofday, which on my pc takes only a few microsecons to execute.
Sorry, I had misread the original remark: I thought it was asking why qemu suddenly ran (supposedly) 20% slower when calling gettimeofday all the time, not that it was asking why the clock got skewed.
Jonas
Quoted 10 lines · Massimo Dal Zotto
When qemu runs on an i386 cpu with speedstep enabled the clock of the guest os is not in sync with the clock on the host os because the
vm_timerused for irq 0 generates interrupts at wrong rate when the host cpu frequency changes.The problem is that the
vm_timeruses the rdtsc instruction and the value ofticks_per_sec, computed at start time, for calculating the expire time ofvm_timers. Whileticks_per_secis constant the values returned by rdtsc are dependent on the current cpu clock, which is not constant if speedstep is used.
There is a discussion about this problem on either x86-secret.com or Sudhian. I can't remember which :-( In the latest series of P4 chips (both Xeon and desktop I think), the counter used for the rdtsc instruction stays at the same frequency while the rest of the CPU changes. This led to some "interesting" results with programs like CPU-Z.
Intel's response was that they now hold the counter at a stable frequency so that this works. Unfortunately, there are years of processors which do not do that, so other workarounds must be done.
Best,
Kyle