Re: do_fast_gettimeoffset(void) buggy?

Linus Torvalds (torvalds@cs.helsinki.fi)
Fri, 26 Apr 1996 14:43:40 +0300 (EET DST)


On Fri, 26 Apr 1996, Ulrich Windl wrote:
>
> I have a question about the routine below. The routine is a Pentium
> specific microtime() routine. I'm afraid it is not correct. See my
> "???" tag at the beginning of a line. If someone can tell me, if I'm
> wrong, I'd like to hear it!

I think you're wrong, but feel free to double-check..

> /* .. relative to previous jiffy (32 bits is enough) */
> time_low -= (unsigned long) last_timer_cc;
> ??? We have two 64 bit quantities, and we are interested in the least
> ??? significant 32 bit. Currently just the "low longwords" are
> ??? subtracted, yielding a possible overflow (result in unsigned).
> ??? Usually you would need some carry processing.

Carry makes a difference only for the high 32 bits, and as we're going to
ignore the high bits in the result anyway, we don't care. Essentially,
what we're doing is a 64-bit subtract, and then extracting the low bits,
so the expression we're looking for is actually

(t2 - t1) mod 2^32

but that is mathematically equivalent to what we're doing:

((t2 mod 2^32) - (t1 mod 2^32)) mod 2^32

Remember, C defines unsigned integer arithmetic to work this way
(although the "32" part is implementation defined), so we're not even
depending on any special behaviour here - this is just how the addition
operator works in C.

I guess anybody who wants to be _really_ sure needs to take a course
in algebra, and think about what the operator "+" really means in different
circumstances.

Btw, linux depends on this property of unsigned arithmetic in C in other
places too - take a look at the "before()" and "after()" functions that
define the incomplete order of TCP sequence numbers in the same "modulus
2^32" mathematical world ;-)

> if (quotient >= 1000000/HZ)
> quotient = 1000000/HZ-1;
>
> ??? Is this the correction for the missed carry?

No, that's just correcting for the fact that the way we do calculations
we can't really depend on everything being exact: if we have lost a few
timer ticks along the way we should make sure that we don't let the
"correction factor" grow too large (otherwise we might end up with a
struct timeval that is not monotonically growing after the next timer
tick).

Linus