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