Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 Mar 2012 16:42:13 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        arch@FreeBSD.org
Subject:   Re: select/poll/usleep precision on FreeBSD vs Linux vs OSX
Message-ID:  <20120301161011.A2654@besplex.bde.org>
In-Reply-To: <20120301143042.F2406@besplex.bde.org>
References:  <20120229194042.GA10921@onelab2.iet.unipi.it> <20120301071145.O879@besplex.bde.org> <20120301012315.GB14508@onelab2.iet.unipi.it> <20120301132806.O2255@besplex.bde.org> <20120301143042.F2406@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 1 Mar 2012, Bruce Evans wrote:

> On Thu, 1 Mar 2012, Bruce Evans wrote:
>
>> ...
>> Bakul Shah confirmed that Linux now reprograms the timer.  It has to,
>> for a tickless kernel.  FreeBSD reprograms timers too.  I think you
>> can set HZ large and only get timeout interrupts at that frequency if
>> there are active timeouts that need them.  Timeout granularity is still
>> 1/HZ.
>
> I tried this in -current and in a 2008 -current with hz=10000.  It worked
> mediocrely:
> - the 2008 version gave lapic cpuN: timer interrupts on all CPUs at
>  frequency of almost exactly 10 kHz.  This is the behaviour before
>  FreeBSD reprogrammed timers (except the frequency is often off by
>  as much as 10% due to calibration bugs).  There were many anomolies
>  in the results from the test program (like select() adding 199 usec
>  and usleep() adding 999 usec).
> - [... no surprises in -current]

I tried this in -current with hz=100000.  This gives (some not very
surprising) behaviour:
- systat claims ~100% idle, but the ~100k interrupts on 1 CPU actually
   reduces performance by 33% (two CPUs take 30 seconds user time to
   do what can be done in 20 seconds user time with hz=100).  This is
   a normal problem with fast interrupt handlers.  They need a faster
   interrupt handler to account for them properly.
- ./prog 1 select works reasonably.  It reports timeouts of 29-30 us.
   I expected 19-20.
- ./prog 1 poll is broken as we know.  It asks for timeouts of 0 and
   takes 3 us.
- ./prog 1 usleep shows brokenness.  It reports timeouts of 999 us.
   I think this is due to getnanouptime()'s brokenness.
   $(sysctl kern.timecounter.tick) is 100.  This reduces getnanouptime()'s
   accuracy back to to 1 msec, which explains the 999 us.  But why doesn't
   select() have the same problem?  select() uses getmicrouptime(), but
   it has the same brokenness.  The sysctl is r/o, so I couldn't use
   it easily.  I have changed tc_tick using ddb before, but don't want
   to risk reducing it by a factor of 100.  The timecounter update
   algorithm depends on the timehands not being recycled too fast, and
   probably couldn't copy with recycling 100 times faster.
- ./prog 1000 select and ./prog 1000 poll take 20 us extra.  I expected
   9-10 extra.
- ./prog 1000 usleep takes 619-693 us extra.  Not the full extra 100
   ticks from getnanouptime() fuzziness now.
- ./prog 500000 usleep takes 500026-500885 us.  Even higher variance
   which agrees with the fuzziness better.  select and poll with this
   timeout still have accuracy and low variance (21-26 us extra).

The fuzzy versions are actually useful for optimization after all:
- for long timeouts, use the fuzzy versions and accept their inaccuracies.
   Sleep longer by the amount fuzziness so that sleeps are never too
   short.
- for short timeouts, it seems necessary for the initial timestamp to
   be accuarate.  When checking if the timeout has expired, first try a
   fuzzy check.  This is sufficent if the current fuzzy time is far from
   the expiry time.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120301161011.A2654>