Accurate timers in rumpkernels on Xen / minios

  • From: George Dunlap <george.dunlap@xxxxxxxxxx>
  • To: rumpkernel-users <rumpkernel-users@xxxxxxxxxxxxx>
  • Date: Fri, 27 May 2016 10:32:39 +0100

I'm trying to write a "scheduler micro-benchmark", primarily for Xen,
which can spin up thousands of individual VMs, each of which will
according to certain parameters switch between sleeping and doing some
"work" (cpu / memory-bound).  The main event loop looks like this:

while(/* Something on the queue */) {
  /* Take it off the queue */

  int64_t delta_ns = event->start_ns - now();

  if (delta_ns > 0) {
    nsleep(delta_ns);
  }

  delta_ns = now() - event->start_ns;

  if ( delta_ns > max_delta )
    max_delta = delta_ns;

  /* Do the work */
}

And now() is implemented with clock_gettime(CLOCK_MONOTONIC, &tp).

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?)

Thanks in advance -- I really appreciate the ease with which I was
able to get a lot of this stuff just working out of the box.

 -George

Other related posts: