Re: Accurate timers in rumpkernels on Xen / minios

  • From: George Dunlap <dunlapg@xxxxxxxxx>
  • To: pooka@xxxxxx
  • Date: Fri, 27 May 2016 11:57:09 +0100

On Fri, May 27, 2016 at 11:23 AM, Antti Kantee <pooka@xxxxxx> wrote:

On 27/05/16 09:32, George Dunlap wrote:

The problem I'm having is that the "nsleep()" seems to be quantizing
on 10ms, which is a *lot* less fine-grained than I wanted; the
"max_delta" for each reporting period is almost always a bit over 10ms
(i.e., the maximum amount of time it "overslept").  Below are reports
that happen every 1s; "now" is the time of reporting, "mops" is the
*cumulative* number of operations done (in millions); and max_delta is
the max_delta *for this period* (i.e., it gets reset every second):

{ "now":2033655690, "mops":60, "max_delta":10014214 }
{ "now":3061713795, "mops":118, "max_delta":10015144 }
{ "now":4089251608, "mops":176, "max_delta":10036716 }
{ "now":5117213014, "mops":234, "max_delta":10056997 }
{ "now":6144605339, "mops":292, "max_delta":10041393 }
{ "now":7171986432, "mops":350, "max_delta":10042572 }
{ "now":8199335304, "mops":408, "max_delta":10017662 }
{ "now":9226821190, "mops":466, "max_delta":10060509 }

This may be due to the default timer being set to 10ms; from the
skrool of the rumprun kernel at start-up:

---
timecounter: Timecounters tick every 10.000 msec
timecounter: Timecounter "clockinterrupt" frequency 100 Hz quality 0
cpu0 at thinair0: rump virtual cpu
root file system type: rumpfs
kern.module.path=/stand/amd64/7.99.21/modules
mainbus0 (root)
timecounter: Timecounter "bmktc" frequency 1000000000 Hz quality 100
---

I haven't yet traced the actual execution time to know whether it's
the nsleep() that's on a 10ms granularity, or the clock_gettime(), but
either way I need something more accurate.

So my question is, is there a good way to get a sleep timer that will
be more accurate -- sub-millisecond at least, but closer to a
microsecond -- either by using different parts of the POSIX interface,
or by changing the timer interrupt frequency?  (Or perhaps managing to
get it to default to that bmktc timecounter rather than the
clockinterrupt timecounter?)


The better clock should be used automatically since it's of higher quality.
The fact that your max_delta is not a multiple of 10ms supports this
suspicion.

Thanks for the quick response.  What do you mean it's not a multiple
of 10ms?  It's almost exactly 10ms + a few tens of microseconds.  The
tens of microseconds is easily the result of the time going through
the kernel + hypervisor sleep+wakeup path.

That clock directly uses
platform/xen/xen/arch/x86/time.c::bmk_platform_cpu_clock_monotonic(). The
domain is put to sleep with block_domain() in the same file.

Based on your email address, I'm sure you know Xen better than I do, but are
you sure Xen itself can provide time and sleep with such an accuracy? I'd
expect that sort of skew especially with the sleeps in a virtualized
environment.  If you can produce better accuracy with pure MiniOS, then
there's a bug in Rumprun (or in the Rumprun copy of MiniOS in platform/xen).

It certainly should be able to set a timer shorter than 10ms.  I
actually have the same "worker" code set to compile both as a normal
Linux process and a rumprun image (in part for ease of development, in
part so that the benchmark could be used for OSes or KVM as well as
Xen).  If I take the "worker-proc" binary and run it in an
unprivileged Linux domU, I get the following:

{ "Now":757641512629922, "Mops":0, "MaxDelta":0 }
{ "Now":757642625697453, "Mops":160, "MaxDelta":93439 }
{ "Now":757643756428905, "Mops":320, "MaxDelta":104451 }
{ "Now":757644887239972, "Mops":480, "MaxDelta":128225 }
{ "Now":757646023603159, "Mops":640, "MaxDelta":105891 }
{ "Now":757647156308278, "Mops":800, "MaxDelta":164396 }

That's in nanoseconds, so closer to 100 microseconds.  Not sure if the
limiting factor on the granularity is because of Xen or Linux, but it
should certainly be able to deliver better than 10ms.

(Actually, the above is measured from a Linux dom0 running inside of
Xen running inside an HVM guest -- nested virtualization -- so it's
actually going through two levels of Xen *and* Linux to get that
granularity.)

I'll take a quick look at the codepath you pointed out to see if
there's anything obvious.

 -George

Other related posts: