Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Bad sleep time resolution of nanosleep(2)



In the context of the machine simulator simh, which needs some accurate
timing now and then, I have come across an example of rather bad time
resolution of the nanosleep() system call.  The minimal sleep time seems
to be 20 ms, even if you ask for just 1 ms delay. If you ask for longer
sleeps, the discrepancy becomes relatively less but remains substantial:
20 ms becomes 30 ms, and 40 ms becomes 50.

For the standard HZ=100, one would expect the worst resolution to be
1000/100 = 10 ms.

As an experiment, I built a kernel with "options HZ=1000" for NetBSD 7,
and even there a 1 ms sleep still takes 2 ms. For other times, the
actual time seems systematically 1 ms too long.

This seems to indicate that the actual time is rounded up to whole ticks
and then another whole tick is added. I'd expect the former, but not the
latter; this seems rather unnecessarily inaccurate.

I have measured times in us (microseconds) using the following program,
which is derived from the simh sources.

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#define NANOS_PER_MILLI     1000000
#define MILLIS_PER_SEC      1000
#define sleep1Samples       100


uint64_t sim_os_usec (void)
{
    struct timeval cur;

    gettimeofday (&cur, NULL);
    return cur.tv_sec * 1000000L + cur.tv_usec;
}

/* returns the time actually slept in microseconds */
uint32_t sim_os_ms_sleep (unsigned int milliseconds)
{
    uint64_t stime = sim_os_usec ();
    struct timespec treq;

    treq.tv_sec = milliseconds / MILLIS_PER_SEC;
    treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
    (void) nanosleep (&treq, NULL);
    return sim_os_usec () - stime;
}

void sim_os_ms_sleep_init (int milliseconds)
{
    uint32_t i, tot, tim;
    uint64_t t1, t2;

    sim_os_ms_sleep (1);                  /* Start sampling on a tick boundary */
    for (i = 0, tot = 0; i < sleep1Samples; i++) {
        t1 = sim_os_usec ();
        sim_os_ms_sleep (milliseconds);
        t2 = sim_os_usec ();
        tot += (t2 - t1);
    }
    tim = (tot + (sleep1Samples - 1)) / sleep1Samples;
    printf("precision of %d ms sleep: %d microsec (should be %d microsec)\n", milliseconds, tim, milliseconds * 1000);
}

int main(int argc, char **argv)
{
    int ms = 1;

    if (argc > 1) {
        ms = atoi(argv[1]);
    }

    sim_os_ms_sleep_init(ms);

    return 0;
}

-Olaf.
-- 
___ Olaf 'Rhialto' Seibert  -- The Doctor: No, 'eureka' is Greek for
\X/ rhialto/at/xs4all.nl    -- 'this bath is too hot.'

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index