non-invariant tsc and cputicker
Jung-uk Kim
jkim at FreeBSD.org
Fri Dec 3 20:04:10 UTC 2010
On Friday 03 December 2010 01:14 pm, Andriy Gapon wrote:
> on 03/12/2010 20:05 Jung-uk Kim said the following:
> > On Friday 03 December 2010 12:26 pm, Andriy Gapon wrote:
> >> FreeBSD uses cpu_ticks [function pointer] in a few places for a
> >> few things like process CPU time accounting. On x86 cpu_ticks
> >> always points to rdtsc. If TSC is not invariant that leads to
> >> incorrect accounting of "CPU ticks". The code pretends to try to
> >> handle changing cpufreq levels, but does that incorrectly.
> >
> > Arg... Probably it is my fault. :-(
> >
> >> I think that we could use a selected timecounter instead of
> >> "raw" TSC if the latter is not invariant. In this case
> >> cpu_ticks calls would be slightly costlier, but always correct.
> >>
> >> The change is quite trivial:
> >> http://people.freebsd.org/~avg/tsc-cputicker.diff
> >>
> >> What do you think?
> >
> > Why don't we just fix it properly?
>
> Patch? :-)
Attached.
> It seems that it is not too trivial to do and is prone to error
> accumulation given how the ticks are added up.
> Besides, why using a timecounter would not be a proper fix?
Well, it is not that simple, unfortunately. Because init_TSC() is
called very early, your patch will select dummy timecounter as a CPU
ticker if my memory serves. It is very hard to implement right on
x86 arch. :-(
Jung-uk Kim
> >> P.S. it's probably a good idea to merge i386 and amd64 tsc.c
> >> files into a common x86 version, which would be the same as i386
> >> version, which seems to be generic enough.
> >
> > Agreed.
>
> Cool!
-------------- next part --------------
Index: sys/i386/i386/tsc.c
===================================================================
--- sys/i386/i386/tsc.c (revision 216155)
+++ sys/i386/i386/tsc.c (working copy)
@@ -174,6 +174,9 @@ tsc_levels_changed(void *arg, int unit)
int count, error;
uint64_t max_freq;
+ if (tsc_is_invariant)
+ return;
+
/* Only use values from the first CPU, assuming all are equal. */
if (unit != 0)
return;
Index: sys/amd64/amd64/tsc.c
===================================================================
--- sys/amd64/amd64/tsc.c (revision 216155)
+++ sys/amd64/amd64/tsc.c (working copy)
@@ -146,6 +146,9 @@ tsc_levels_changed(void *arg, int unit)
int count, error;
uint64_t max_freq;
+ if (tsc_is_invariant)
+ return;
+
/* Only use values from the first CPU, assuming all are equal. */
if (unit != 0)
return;
More information about the freebsd-current
mailing list