Re: kqueue periodic timer confusion
on 19/07/2012 18:11 Davide Italiano said the following: > On Thu, Jul 19, 2012 at 5:06 PM, Paul Albrecht wrote: >> On Fri, 2012-07-13 at 07:22 -0500, Davide Italiano wrote: >>> On Thu, Jul 12, 2012 at 5:25 PM, John Baldwin wrote: On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: > On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: >> On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: >>> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: >> Hi, >> >> Sorry about this repost but I'm confused about the responses I >> received >> in my last post so I'm looking for some clarification. >> >> Specifically, I though I could use the kqueue timer as essentially a >> "drop in" replacement for linuxfd_create/read, but was surprised that >> the accuracy of the kqueue timer is much less than what I need for my >> application. >> >> So my confusion at this point is whether this is consider to be a >> bug or >> "feature"? >> >> Here's some test code if you want to verify the problem: >> >> #include >> #include >> #include >> #include >> #include >> #include >> #include >> #include >> >> int >> main(void) >> { >> int i,msec; >> int kq,nev; >> struct kevent inqueue; >> struct kevent outqueue; >> struct timeval start,end; >> >> if ((kq = kqueue()) == -1) { >> fprintf(stderr, "kqueue error!? errno = %s", strerror(errno)); >> exit(EXIT_FAILURE); >> } >> EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, >> 0); >> >> gettimeofday(&start, 0); >> for (i = 0; i < 50; i++) { >> if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, >> NULL)) == -1) { >> fprintf(stderr, "kevent error!? errno = %s", strerror(errno)); >> exit(EXIT_FAILURE); >> } else if (outqueue.flags & EV_ERROR) { >> fprintf(stderr, "EV_ERROR: %s\n", strerror(outqueue.data)); >> exit(EXIT_FAILURE); >> } >> } >> gettimeofday(&end, 0); >> >> msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + end.tv_usec - start.tv_usec) / 1000) - 1000); >> >> printf("msec = %d\n", msec); >> >> close(kq); >> return EXIT_SUCCESS; >> } >> >> > > What you are seeing is "just the way FreeBSD currently works." > > Sleeping (in most all of its various forms, and I've just looked at > the > kevent code to verify this is true there) is handled by converting the > amount of time to sleep (usually specified in a timeval or timespec > struct) to a count of timer ticks, using an internal routine called > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > account for the current tick. Whether that's a good idea or not (it > probably was once, and probably not anymore) it's how things currently > work, and could explain the fairly consistant +1ms you're seeing. This is all true, but mostly irrelevant for his case. EVFILT_TIMER installs a periodic callout that executes KNOTE() and then resets itself (via callout_reset()) each time it runs. This should generally be closer to regulary spaced intervals than something that does: >>> >>> In what way is it irrelevant? That is, what did I miss? It appears to >>> me that the next callout is scheduled by calling timertoticks() passing >>> a count of milliseconds, that count is converted to a struct timeval and >>> passed to tvtohz() which is where the +1 adjustment happens. If you ask >>> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. >>> There is some time, likely a small number of microseconds, that you've >>> consumed of the current tick, and that's what the +1 in tvtohz() is >>> supposed to account for according to the comments. >>> >>> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick >>> and then adds one tick on top of that. That seems not quite right to >>> me, except that it is a way to g'tee that you don't return early, and >>>
Re: kqueue periodic timer confusion
On Thu, Jul 19, 2012 at 5:06 PM, Paul Albrecht wrote: > On Fri, 2012-07-13 at 07:22 -0500, Davide Italiano wrote: >> On Thu, Jul 12, 2012 at 5:25 PM, John Baldwin wrote: >> > On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: >> >> On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: >> >> > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: >> >> >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: >> >> >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: >> >> >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: >> >> >> > > > Hi, >> >> >> > > > >> >> >> > > > Sorry about this repost but I'm confused about the responses I >> >> >> > > > received >> >> >> > > > in my last post so I'm looking for some clarification. >> >> >> > > > >> >> >> > > > Specifically, I though I could use the kqueue timer as >> >> >> > > > essentially a >> >> >> > > > "drop in" replacement for linuxfd_create/read, but was surprised >> >> >> > > > that >> >> >> > > > the accuracy of the kqueue timer is much less than what I need >> >> >> > > > for my >> >> >> > > > application. >> >> >> > > > >> >> >> > > > So my confusion at this point is whether this is consider to be >> >> >> > > > a bug or >> >> >> > > > "feature"? >> >> >> > > > >> >> >> > > > Here's some test code if you want to verify the problem: >> >> >> > > > >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > #include >> >> >> > > > >> >> >> > > > int >> >> >> > > > main(void) >> >> >> > > > { >> >> >> > > > int i,msec; >> >> >> > > > int kq,nev; >> >> >> > > > struct kevent inqueue; >> >> >> > > > struct kevent outqueue; >> >> >> > > > struct timeval start,end; >> >> >> > > > >> >> >> > > > if ((kq = kqueue()) == -1) { >> >> >> > > > fprintf(stderr, "kqueue error!? errno = %s", >> >> >> > strerror(errno)); >> >> >> > > > exit(EXIT_FAILURE); >> >> >> > > > } >> >> >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, >> >> >> > > > 20, 0); >> >> >> > > > >> >> >> > > > gettimeofday(&start, 0); >> >> >> > > > for (i = 0; i < 50; i++) { >> >> >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, >> >> >> > > > NULL)) == >> >> >> > -1) { >> >> >> > > > fprintf(stderr, "kevent error!? errno = >> >> >> > > > %s", >> >> >> > strerror(errno)); >> >> >> > > > exit(EXIT_FAILURE); >> >> >> > > > } else if (outqueue.flags & EV_ERROR) { >> >> >> > > > fprintf(stderr, "EV_ERROR: %s\n", >> >> >> > strerror(outqueue.data)); >> >> >> > > > exit(EXIT_FAILURE); >> >> >> > > > } >> >> >> > > > } >> >> >> > > > gettimeofday(&end, 0); >> >> >> > > > >> >> >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 >> >> >> > > > + >> >> >> > end.tv_usec - start.tv_usec) / 1000) - 1000); >> >> >> > > > >> >> >> > > > printf("msec = %d\n", msec); >> >> >> > > > >> >> >> > > > close(kq); >> >> >> > > > return EXIT_SUCCESS; >> >> >> > > > } >> >> >> > > > >> >> >> > > > >> >> >> > > >> >> >> > > What you are seeing is "just the way FreeBSD currently works." >> >> >> > > >> >> >> > > Sleeping (in most all of its various forms, and I've just looked >> >> >> > > at the >> >> >> > > kevent code to verify this is true there) is handled by converting >> >> >> > > the >> >> >> > > amount of time to sleep (usually specified in a timeval or timespec >> >> >> > > struct) to a count of timer ticks, using an internal routine called >> >> >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick >> >> >> > > to >> >> >> > > account for the current tick. Whether that's a good idea or not >> >> >> > > (it >> >> >> > > probably was once, and probably not anymore) it's how things >> >> >> > > currently >> >> >> > > work, and could explain the fairly consistant +1ms you're seeing. >> >> >> > >> >> >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER >> >> >> > installs a periodic callout that executes KNOTE() and then resets >> >> >> > itself (via >> >> >> > callout_reset()) each time it runs. This should generally be closer >> >> >> > to >> >> >> > regulary spaced intervals than something that does: >> >> >> > >> >> >> >> >> >> In what way is it irrelevant? That is, what did I miss? It appears to >> >> >> me that the next callout is scheduled by calling timertoticks() passing >> >> >> a count of milliseconds, that count is converted to a struct timeval >> >> >> and >> >> >> passed to tvtohz() which is where the +1 adjustment happens. If you >> >> >> ask >> >> >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. >> >> >> There is some ti
Re: kqueue periodic timer confusion
On Fri, 2012-07-13 at 07:22 -0500, Davide Italiano wrote: > On Thu, Jul 12, 2012 at 5:25 PM, John Baldwin wrote: > > On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: > >> On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > >> > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > >> >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > >> >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > >> >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > >> >> > > > Hi, > >> >> > > > > >> >> > > > Sorry about this repost but I'm confused about the responses I > >> >> > > > received > >> >> > > > in my last post so I'm looking for some clarification. > >> >> > > > > >> >> > > > Specifically, I though I could use the kqueue timer as > >> >> > > > essentially a > >> >> > > > "drop in" replacement for linuxfd_create/read, but was surprised > >> >> > > > that > >> >> > > > the accuracy of the kqueue timer is much less than what I need > >> >> > > > for my > >> >> > > > application. > >> >> > > > > >> >> > > > So my confusion at this point is whether this is consider to be a > >> >> > > > bug or > >> >> > > > "feature"? > >> >> > > > > >> >> > > > Here's some test code if you want to verify the problem: > >> >> > > > > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > > >> >> > > > int > >> >> > > > main(void) > >> >> > > > { > >> >> > > > int i,msec; > >> >> > > > int kq,nev; > >> >> > > > struct kevent inqueue; > >> >> > > > struct kevent outqueue; > >> >> > > > struct timeval start,end; > >> >> > > > > >> >> > > > if ((kq = kqueue()) == -1) { > >> >> > > > fprintf(stderr, "kqueue error!? errno = %s", > >> >> > strerror(errno)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } > >> >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, > >> >> > > > 20, 0); > >> >> > > > > >> >> > > > gettimeofday(&start, 0); > >> >> > > > for (i = 0; i < 50; i++) { > >> >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, > >> >> > > > NULL)) == > >> >> > -1) { > >> >> > > > fprintf(stderr, "kevent error!? errno = > >> >> > > > %s", > >> >> > strerror(errno)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } else if (outqueue.flags & EV_ERROR) { > >> >> > > > fprintf(stderr, "EV_ERROR: %s\n", > >> >> > strerror(outqueue.data)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } > >> >> > > > } > >> >> > > > gettimeofday(&end, 0); > >> >> > > > > >> >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > >> >> > end.tv_usec - start.tv_usec) / 1000) - 1000); > >> >> > > > > >> >> > > > printf("msec = %d\n", msec); > >> >> > > > > >> >> > > > close(kq); > >> >> > > > return EXIT_SUCCESS; > >> >> > > > } > >> >> > > > > >> >> > > > > >> >> > > > >> >> > > What you are seeing is "just the way FreeBSD currently works." > >> >> > > > >> >> > > Sleeping (in most all of its various forms, and I've just looked at > >> >> > > the > >> >> > > kevent code to verify this is true there) is handled by converting > >> >> > > the > >> >> > > amount of time to sleep (usually specified in a timeval or timespec > >> >> > > struct) to a count of timer ticks, using an internal routine called > >> >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > >> >> > > account for the current tick. Whether that's a good idea or not (it > >> >> > > probably was once, and probably not anymore) it's how things > >> >> > > currently > >> >> > > work, and could explain the fairly consistant +1ms you're seeing. > >> >> > > >> >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > >> >> > installs a periodic callout that executes KNOTE() and then resets > >> >> > itself (via > >> >> > callout_reset()) each time it runs. This should generally be closer > >> >> > to > >> >> > regulary spaced intervals than something that does: > >> >> > > >> >> > >> >> In what way is it irrelevant? That is, what did I miss? It appears to > >> >> me that the next callout is scheduled by calling timertoticks() passing > >> >> a count of milliseconds, that count is converted to a struct timeval and > >> >> passed to tvtohz() which is where the +1 adjustment happens. If you ask > >> >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > >> >> There is some time, likely a small number of microseconds, that you've > >> >> consumed of the current tick, and that's what the +1 in tvtohz() is > >> >> supposed to account for according to the comments. > >> >> > >> >> The tvtohz() routine bot
Re: kqueue periodic timer confusion
On Friday, July 13, 2012 8:22:13 am Davide Italiano wrote: > On Thu, Jul 12, 2012 at 5:25 PM, John Baldwin wrote: > > On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: > >> On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > >> > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > >> >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > >> >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > >> >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > >> >> > > > Hi, > >> >> > > > > >> >> > > > Sorry about this repost but I'm confused about the responses I received > >> >> > > > in my last post so I'm looking for some clarification. > >> >> > > > > >> >> > > > Specifically, I though I could use the kqueue timer as essentially a > >> >> > > > "drop in" replacement for linuxfd_create/read, but was surprised that > >> >> > > > the accuracy of the kqueue timer is much less than what I need for my > >> >> > > > application. > >> >> > > > > >> >> > > > So my confusion at this point is whether this is consider to be a bug or > >> >> > > > "feature"? > >> >> > > > > >> >> > > > Here's some test code if you want to verify the problem: > >> >> > > > > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > #include > >> >> > > > > >> >> > > > int > >> >> > > > main(void) > >> >> > > > { > >> >> > > > int i,msec; > >> >> > > > int kq,nev; > >> >> > > > struct kevent inqueue; > >> >> > > > struct kevent outqueue; > >> >> > > > struct timeval start,end; > >> >> > > > > >> >> > > > if ((kq = kqueue()) == -1) { > >> >> > > > fprintf(stderr, "kqueue error!? errno = %s", > >> >> > strerror(errno)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } > >> >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > >> >> > > > > >> >> > > > gettimeofday(&start, 0); > >> >> > > > for (i = 0; i < 50; i++) { > >> >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) == > >> >> > -1) { > >> >> > > > fprintf(stderr, "kevent error!? errno = %s", > >> >> > strerror(errno)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } else if (outqueue.flags & EV_ERROR) { > >> >> > > > fprintf(stderr, "EV_ERROR: %s\n", > >> >> > strerror(outqueue.data)); > >> >> > > > exit(EXIT_FAILURE); > >> >> > > > } > >> >> > > > } > >> >> > > > gettimeofday(&end, 0); > >> >> > > > > >> >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > >> >> > end.tv_usec - start.tv_usec) / 1000) - 1000); > >> >> > > > > >> >> > > > printf("msec = %d\n", msec); > >> >> > > > > >> >> > > > close(kq); > >> >> > > > return EXIT_SUCCESS; > >> >> > > > } > >> >> > > > > >> >> > > > > >> >> > > > >> >> > > What you are seeing is "just the way FreeBSD currently works." > >> >> > > > >> >> > > Sleeping (in most all of its various forms, and I've just looked at the > >> >> > > kevent code to verify this is true there) is handled by converting the > >> >> > > amount of time to sleep (usually specified in a timeval or timespec > >> >> > > struct) to a count of timer ticks, using an internal routine called > >> >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > >> >> > > account for the current tick. Whether that's a good idea or not (it > >> >> > > probably was once, and probably not anymore) it's how things currently > >> >> > > work, and could explain the fairly consistant +1ms you're seeing. > >> >> > > >> >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > >> >> > installs a periodic callout that executes KNOTE() and then resets itself (via > >> >> > callout_reset()) each time it runs. This should generally be closer to > >> >> > regulary spaced intervals than something that does: > >> >> > > >> >> > >> >> In what way is it irrelevant? That is, what did I miss? It appears to > >> >> me that the next callout is scheduled by calling timertoticks() passing > >> >> a count of milliseconds, that count is converted to a struct timeval and > >> >> passed to tvtohz() which is where the +1 adjustment happens. If you ask > >> >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > >> >> There is some time, likely a small number of microseconds, that you've > >> >> consumed of the current tick, and that's what the +1 in tvtohz() is > >> >> supposed to account for according to the comments. > >> >> > >> >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > >> >> and then adds one tick on top of that. That seems not quite right to > >> >> me, except that it is
Re: kqueue periodic timer confusion
On Thu, Jul 12, 2012 at 5:25 PM, John Baldwin wrote: > On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: >> On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: >> > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: >> >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: >> >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: >> >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: >> >> > > > Hi, >> >> > > > >> >> > > > Sorry about this repost but I'm confused about the responses I >> >> > > > received >> >> > > > in my last post so I'm looking for some clarification. >> >> > > > >> >> > > > Specifically, I though I could use the kqueue timer as essentially a >> >> > > > "drop in" replacement for linuxfd_create/read, but was surprised >> >> > > > that >> >> > > > the accuracy of the kqueue timer is much less than what I need for >> >> > > > my >> >> > > > application. >> >> > > > >> >> > > > So my confusion at this point is whether this is consider to be a >> >> > > > bug or >> >> > > > "feature"? >> >> > > > >> >> > > > Here's some test code if you want to verify the problem: >> >> > > > >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > #include >> >> > > > >> >> > > > int >> >> > > > main(void) >> >> > > > { >> >> > > > int i,msec; >> >> > > > int kq,nev; >> >> > > > struct kevent inqueue; >> >> > > > struct kevent outqueue; >> >> > > > struct timeval start,end; >> >> > > > >> >> > > > if ((kq = kqueue()) == -1) { >> >> > > > fprintf(stderr, "kqueue error!? errno = %s", >> >> > strerror(errno)); >> >> > > > exit(EXIT_FAILURE); >> >> > > > } >> >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, >> >> > > > 20, 0); >> >> > > > >> >> > > > gettimeofday(&start, 0); >> >> > > > for (i = 0; i < 50; i++) { >> >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, >> >> > > > NULL)) == >> >> > -1) { >> >> > > > fprintf(stderr, "kevent error!? errno = %s", >> >> > strerror(errno)); >> >> > > > exit(EXIT_FAILURE); >> >> > > > } else if (outqueue.flags & EV_ERROR) { >> >> > > > fprintf(stderr, "EV_ERROR: %s\n", >> >> > strerror(outqueue.data)); >> >> > > > exit(EXIT_FAILURE); >> >> > > > } >> >> > > > } >> >> > > > gettimeofday(&end, 0); >> >> > > > >> >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + >> >> > end.tv_usec - start.tv_usec) / 1000) - 1000); >> >> > > > >> >> > > > printf("msec = %d\n", msec); >> >> > > > >> >> > > > close(kq); >> >> > > > return EXIT_SUCCESS; >> >> > > > } >> >> > > > >> >> > > > >> >> > > >> >> > > What you are seeing is "just the way FreeBSD currently works." >> >> > > >> >> > > Sleeping (in most all of its various forms, and I've just looked at >> >> > > the >> >> > > kevent code to verify this is true there) is handled by converting the >> >> > > amount of time to sleep (usually specified in a timeval or timespec >> >> > > struct) to a count of timer ticks, using an internal routine called >> >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to >> >> > > account for the current tick. Whether that's a good idea or not (it >> >> > > probably was once, and probably not anymore) it's how things currently >> >> > > work, and could explain the fairly consistant +1ms you're seeing. >> >> > >> >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER >> >> > installs a periodic callout that executes KNOTE() and then resets >> >> > itself (via >> >> > callout_reset()) each time it runs. This should generally be closer to >> >> > regulary spaced intervals than something that does: >> >> > >> >> >> >> In what way is it irrelevant? That is, what did I miss? It appears to >> >> me that the next callout is scheduled by calling timertoticks() passing >> >> a count of milliseconds, that count is converted to a struct timeval and >> >> passed to tvtohz() which is where the +1 adjustment happens. If you ask >> >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. >> >> There is some time, likely a small number of microseconds, that you've >> >> consumed of the current tick, and that's what the +1 in tvtohz() is >> >> supposed to account for according to the comments. >> >> >> >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick >> >> and then adds one tick on top of that. That seems not quite right to >> >> me, except that it is a way to g'tee that you don't return early, and >> >> that is the one promise made by sleep routines on any OS; those magical >> >> "at least" words always appear in the docs. >> >> >> >>
Re: kqueue periodic timer confusion
On Thu, 2012-07-12 at 10:40 -0500, Ian Lepore wrote: > On Thu, 2012-07-12 at 17:08 +0200, Davide Italiano wrote: > > On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > > > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > > >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > > >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > > >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > > >> > > > Hi, > > >> > > > > > >> > > > Sorry about this repost but I'm confused about the responses I > > >> > > > received > > >> > > > in my last post so I'm looking for some clarification. > > >> > > > > > >> > > > Specifically, I though I could use the kqueue timer as essentially > > >> > > > a > > >> > > > "drop in" replacement for linuxfd_create/read, but was surprised > > >> > > > that > > >> > > > the accuracy of the kqueue timer is much less than what I need for > > >> > > > my > > >> > > > application. > > >> > > > > > >> > > > So my confusion at this point is whether this is consider to be a > > >> > > > bug or > > >> > > > "feature"? > > >> > > > > > >> > > > Here's some test code if you want to verify the problem: > > >> > > > > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > #include > > >> > > > > > >> > > > int > > >> > > > main(void) > > >> > > > { > > >> > > > int i,msec; > > >> > > > int kq,nev; > > >> > > > struct kevent inqueue; > > >> > > > struct kevent outqueue; > > >> > > > struct timeval start,end; > > >> > > > > > >> > > > if ((kq = kqueue()) == -1) { > > >> > > > fprintf(stderr, "kqueue error!? errno = %s", > > >> > strerror(errno)); > > >> > > > exit(EXIT_FAILURE); > > >> > > > } > > >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, > > >> > > > 20, 0); > > >> > > > > > >> > > > gettimeofday(&start, 0); > > >> > > > for (i = 0; i < 50; i++) { > > >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, > > >> > > > NULL)) == > > >> > -1) { > > >> > > > fprintf(stderr, "kevent error!? errno = > > >> > > > %s", > > >> > strerror(errno)); > > >> > > > exit(EXIT_FAILURE); > > >> > > > } else if (outqueue.flags & EV_ERROR) { > > >> > > > fprintf(stderr, "EV_ERROR: %s\n", > > >> > strerror(outqueue.data)); > > >> > > > exit(EXIT_FAILURE); > > >> > > > } > > >> > > > } > > >> > > > gettimeofday(&end, 0); > > >> > > > > > >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > > >> > end.tv_usec - start.tv_usec) / 1000) - 1000); > > >> > > > > > >> > > > printf("msec = %d\n", msec); > > >> > > > > > >> > > > close(kq); > > >> > > > return EXIT_SUCCESS; > > >> > > > } > > >> > > > > > >> > > > > > >> > > > > >> > > What you are seeing is "just the way FreeBSD currently works." > > >> > > > > >> > > Sleeping (in most all of its various forms, and I've just looked at > > >> > > the > > >> > > kevent code to verify this is true there) is handled by converting > > >> > > the > > >> > > amount of time to sleep (usually specified in a timeval or timespec > > >> > > struct) to a count of timer ticks, using an internal routine called > > >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > > >> > > account for the current tick. Whether that's a good idea or not (it > > >> > > probably was once, and probably not anymore) it's how things > > >> > > currently > > >> > > work, and could explain the fairly consistant +1ms you're seeing. > > >> > > > >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > > >> > installs a periodic callout that executes KNOTE() and then resets > > >> > itself (via > > >> > callout_reset()) each time it runs. This should generally be closer to > > >> > regulary spaced intervals than something that does: > > >> > > > >> > > >> In what way is it irrelevant? That is, what did I miss? It appears to > > >> me that the next callout is scheduled by calling timertoticks() passing > > >> a count of milliseconds, that count is converted to a struct timeval and > > >> passed to tvtohz() which is where the +1 adjustment happens. If you ask > > >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > > >> There is some time, likely a small number of microseconds, that you've > > >> consumed of the current tick, and that's what the +1 in tvtohz() is > > >> supposed to account for according to the comments. > > >> > > >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > > >> and then adds one tick on top of that. That seems not quite right to > > >> me, except that it is a way to g'tee that you don't ret
Re: kqueue periodic timer confusion
On Thu, 2012-07-12 at 09:26 -0500, John Baldwin wrote: > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > > On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > > > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > > > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > > > > > Hi, > > > > > > > > > > Sorry about this repost but I'm confused about the responses I > > > > > received > > > > > in my last post so I'm looking for some clarification. > > > > > > > > > > Specifically, I though I could use the kqueue timer as essentially a > > > > > "drop in" replacement for linuxfd_create/read, but was surprised that > > > > > the accuracy of the kqueue timer is much less than what I need for my > > > > > application. > > > > > > > > > > So my confusion at this point is whether this is consider to be a bug > > > > > or > > > > > "feature"? > > > > > > > > > > Here's some test code if you want to verify the problem: > > > > > > > > > > #include > > > > > #include > > > > > #include > > > > > #include > > > > > #include > > > > > #include > > > > > #include > > > > > #include > > > > > > > > > > int > > > > > main(void) > > > > > { > > > > > int i,msec; > > > > > int kq,nev; > > > > > struct kevent inqueue; > > > > > struct kevent outqueue; > > > > > struct timeval start,end; > > > > > > > > > > if ((kq = kqueue()) == -1) { > > > > > fprintf(stderr, "kqueue error!? errno = %s", > > > strerror(errno)); > > > > > exit(EXIT_FAILURE); > > > > > } > > > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, > > > > > 0); > > > > > > > > > > gettimeofday(&start, 0); > > > > > for (i = 0; i < 50; i++) { > > > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, > > > > > NULL)) == > > > -1) { > > > > > fprintf(stderr, "kevent error!? errno = %s", > > > strerror(errno)); > > > > > exit(EXIT_FAILURE); > > > > > } else if (outqueue.flags & EV_ERROR) { > > > > > fprintf(stderr, "EV_ERROR: %s\n", > > > strerror(outqueue.data)); > > > > > exit(EXIT_FAILURE); > > > > > } > > > > > } > > > > > gettimeofday(&end, 0); > > > > > > > > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > > > end.tv_usec - start.tv_usec) / 1000) - 1000); > > > > > > > > > > printf("msec = %d\n", msec); > > > > > > > > > > close(kq); > > > > > return EXIT_SUCCESS; > > > > > } > > > > > > > > > > > > > > > > > > What you are seeing is "just the way FreeBSD currently works." > > > > > > > > Sleeping (in most all of its various forms, and I've just looked at the > > > > kevent code to verify this is true there) is handled by converting the > > > > amount of time to sleep (usually specified in a timeval or timespec > > > > struct) to a count of timer ticks, using an internal routine called > > > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > > > > account for the current tick. Whether that's a good idea or not (it > > > > probably was once, and probably not anymore) it's how things currently > > > > work, and could explain the fairly consistant +1ms you're seeing. > > > > > > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > > > installs a periodic callout that executes KNOTE() and then resets itself > > > (via > > > callout_reset()) each time it runs. This should generally be closer to > > > regulary spaced intervals than something that does: > > > > > > > In what way is it irrelevant? That is, what did I miss? It appears to > > me that the next callout is scheduled by calling timertoticks() passing > > a count of milliseconds, that count is converted to a struct timeval and > > passed to tvtohz() which is where the +1 adjustment happens. If you ask > > for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > > There is some time, likely a small number of microseconds, that you've > > consumed of the current tick, and that's what the +1 in tvtohz() is > > supposed to account for according to the comments. > > > > The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > > and then adds one tick on top of that. That seems not quite right to > > me, except that it is a way to g'tee that you don't return early, and > > that is the one promise made by sleep routines on any OS; those magical > > "at least" words always appear in the docs. > > > > Actually what I'm missing (that I know of) is how the scheduler works. > > Maybe the +1 adjustment to account for the fraction of the current tick > > you've already consumed is the right thing to do, even when that > > fraction is 1uS or less of a 1mS tick. That would depend on scheduler > > behavior that I know nothing about. > > Oh. M
Re: kqueue periodic timer confusion
On Thu, 2012-07-12 at 17:08 +0200, Davide Italiano wrote: > On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > >> > > > Hi, > >> > > > > >> > > > Sorry about this repost but I'm confused about the responses I > >> > > > received > >> > > > in my last post so I'm looking for some clarification. > >> > > > > >> > > > Specifically, I though I could use the kqueue timer as essentially a > >> > > > "drop in" replacement for linuxfd_create/read, but was surprised that > >> > > > the accuracy of the kqueue timer is much less than what I need for my > >> > > > application. > >> > > > > >> > > > So my confusion at this point is whether this is consider to be a > >> > > > bug or > >> > > > "feature"? > >> > > > > >> > > > Here's some test code if you want to verify the problem: > >> > > > > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > > >> > > > int > >> > > > main(void) > >> > > > { > >> > > > int i,msec; > >> > > > int kq,nev; > >> > > > struct kevent inqueue; > >> > > > struct kevent outqueue; > >> > > > struct timeval start,end; > >> > > > > >> > > > if ((kq = kqueue()) == -1) { > >> > > > fprintf(stderr, "kqueue error!? errno = %s", > >> > strerror(errno)); > >> > > > exit(EXIT_FAILURE); > >> > > > } > >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, > >> > > > 0); > >> > > > > >> > > > gettimeofday(&start, 0); > >> > > > for (i = 0; i < 50; i++) { > >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, > >> > > > NULL)) == > >> > -1) { > >> > > > fprintf(stderr, "kevent error!? errno = %s", > >> > strerror(errno)); > >> > > > exit(EXIT_FAILURE); > >> > > > } else if (outqueue.flags & EV_ERROR) { > >> > > > fprintf(stderr, "EV_ERROR: %s\n", > >> > strerror(outqueue.data)); > >> > > > exit(EXIT_FAILURE); > >> > > > } > >> > > > } > >> > > > gettimeofday(&end, 0); > >> > > > > >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > >> > end.tv_usec - start.tv_usec) / 1000) - 1000); > >> > > > > >> > > > printf("msec = %d\n", msec); > >> > > > > >> > > > close(kq); > >> > > > return EXIT_SUCCESS; > >> > > > } > >> > > > > >> > > > > >> > > > >> > > What you are seeing is "just the way FreeBSD currently works." > >> > > > >> > > Sleeping (in most all of its various forms, and I've just looked at the > >> > > kevent code to verify this is true there) is handled by converting the > >> > > amount of time to sleep (usually specified in a timeval or timespec > >> > > struct) to a count of timer ticks, using an internal routine called > >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > >> > > account for the current tick. Whether that's a good idea or not (it > >> > > probably was once, and probably not anymore) it's how things currently > >> > > work, and could explain the fairly consistant +1ms you're seeing. > >> > > >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > >> > installs a periodic callout that executes KNOTE() and then resets itself > >> > (via > >> > callout_reset()) each time it runs. This should generally be closer to > >> > regulary spaced intervals than something that does: > >> > > >> > >> In what way is it irrelevant? That is, what did I miss? It appears to > >> me that the next callout is scheduled by calling timertoticks() passing > >> a count of milliseconds, that count is converted to a struct timeval and > >> passed to tvtohz() which is where the +1 adjustment happens. If you ask > >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > >> There is some time, likely a small number of microseconds, that you've > >> consumed of the current tick, and that's what the +1 in tvtohz() is > >> supposed to account for according to the comments. > >> > >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > >> and then adds one tick on top of that. That seems not quite right to > >> me, except that it is a way to g'tee that you don't return early, and > >> that is the one promise made by sleep routines on any OS; those magical > >> "at least" words always appear in the docs. > >> > >> Actually what I'm missing (that I know of) is how the scheduler works. > >> Maybe the +1 adjustment to account for the fraction of the current tick > >> you've already consumed is the right thing to do, eve
Re: kqueue periodic timer confusion
On Thursday, July 12, 2012 11:08:47 am Davide Italiano wrote: > On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > >> > > > Hi, > >> > > > > >> > > > Sorry about this repost but I'm confused about the responses I > >> > > > received > >> > > > in my last post so I'm looking for some clarification. > >> > > > > >> > > > Specifically, I though I could use the kqueue timer as essentially a > >> > > > "drop in" replacement for linuxfd_create/read, but was surprised that > >> > > > the accuracy of the kqueue timer is much less than what I need for my > >> > > > application. > >> > > > > >> > > > So my confusion at this point is whether this is consider to be a > >> > > > bug or > >> > > > "feature"? > >> > > > > >> > > > Here's some test code if you want to verify the problem: > >> > > > > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > #include > >> > > > > >> > > > int > >> > > > main(void) > >> > > > { > >> > > > int i,msec; > >> > > > int kq,nev; > >> > > > struct kevent inqueue; > >> > > > struct kevent outqueue; > >> > > > struct timeval start,end; > >> > > > > >> > > > if ((kq = kqueue()) == -1) { > >> > > > fprintf(stderr, "kqueue error!? errno = %s", > >> > strerror(errno)); > >> > > > exit(EXIT_FAILURE); > >> > > > } > >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, > >> > > > 0); > >> > > > > >> > > > gettimeofday(&start, 0); > >> > > > for (i = 0; i < 50; i++) { > >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, > >> > > > NULL)) == > >> > -1) { > >> > > > fprintf(stderr, "kevent error!? errno = %s", > >> > strerror(errno)); > >> > > > exit(EXIT_FAILURE); > >> > > > } else if (outqueue.flags & EV_ERROR) { > >> > > > fprintf(stderr, "EV_ERROR: %s\n", > >> > strerror(outqueue.data)); > >> > > > exit(EXIT_FAILURE); > >> > > > } > >> > > > } > >> > > > gettimeofday(&end, 0); > >> > > > > >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > >> > end.tv_usec - start.tv_usec) / 1000) - 1000); > >> > > > > >> > > > printf("msec = %d\n", msec); > >> > > > > >> > > > close(kq); > >> > > > return EXIT_SUCCESS; > >> > > > } > >> > > > > >> > > > > >> > > > >> > > What you are seeing is "just the way FreeBSD currently works." > >> > > > >> > > Sleeping (in most all of its various forms, and I've just looked at the > >> > > kevent code to verify this is true there) is handled by converting the > >> > > amount of time to sleep (usually specified in a timeval or timespec > >> > > struct) to a count of timer ticks, using an internal routine called > >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > >> > > account for the current tick. Whether that's a good idea or not (it > >> > > probably was once, and probably not anymore) it's how things currently > >> > > work, and could explain the fairly consistant +1ms you're seeing. > >> > > >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > >> > installs a periodic callout that executes KNOTE() and then resets itself > >> > (via > >> > callout_reset()) each time it runs. This should generally be closer to > >> > regulary spaced intervals than something that does: > >> > > >> > >> In what way is it irrelevant? That is, what did I miss? It appears to > >> me that the next callout is scheduled by calling timertoticks() passing > >> a count of milliseconds, that count is converted to a struct timeval and > >> passed to tvtohz() which is where the +1 adjustment happens. If you ask > >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > >> There is some time, likely a small number of microseconds, that you've > >> consumed of the current tick, and that's what the +1 in tvtohz() is > >> supposed to account for according to the comments. > >> > >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > >> and then adds one tick on top of that. That seems not quite right to > >> me, except that it is a way to g'tee that you don't return early, and > >> that is the one promise made by sleep routines on any OS; those magical > >> "at least" words always appear in the docs. > >> > >> Actually what I'm missing (that I know of) is how the scheduler works. > >> Maybe the +1 adjustment to account for the fraction of the current tick > >> you've already consumed is the right thing to do,
Re: kqueue periodic timer confusion
On Thu, Jul 12, 2012 at 4:26 PM, John Baldwin wrote: > On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: >> On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: >> > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: >> > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: >> > > > Hi, >> > > > >> > > > Sorry about this repost but I'm confused about the responses I received >> > > > in my last post so I'm looking for some clarification. >> > > > >> > > > Specifically, I though I could use the kqueue timer as essentially a >> > > > "drop in" replacement for linuxfd_create/read, but was surprised that >> > > > the accuracy of the kqueue timer is much less than what I need for my >> > > > application. >> > > > >> > > > So my confusion at this point is whether this is consider to be a bug >> > > > or >> > > > "feature"? >> > > > >> > > > Here's some test code if you want to verify the problem: >> > > > >> > > > #include >> > > > #include >> > > > #include >> > > > #include >> > > > #include >> > > > #include >> > > > #include >> > > > #include >> > > > >> > > > int >> > > > main(void) >> > > > { >> > > > int i,msec; >> > > > int kq,nev; >> > > > struct kevent inqueue; >> > > > struct kevent outqueue; >> > > > struct timeval start,end; >> > > > >> > > > if ((kq = kqueue()) == -1) { >> > > > fprintf(stderr, "kqueue error!? errno = %s", >> > strerror(errno)); >> > > > exit(EXIT_FAILURE); >> > > > } >> > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, >> > > > 0); >> > > > >> > > > gettimeofday(&start, 0); >> > > > for (i = 0; i < 50; i++) { >> > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, >> > > > NULL)) == >> > -1) { >> > > > fprintf(stderr, "kevent error!? errno = %s", >> > strerror(errno)); >> > > > exit(EXIT_FAILURE); >> > > > } else if (outqueue.flags & EV_ERROR) { >> > > > fprintf(stderr, "EV_ERROR: %s\n", >> > strerror(outqueue.data)); >> > > > exit(EXIT_FAILURE); >> > > > } >> > > > } >> > > > gettimeofday(&end, 0); >> > > > >> > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + >> > end.tv_usec - start.tv_usec) / 1000) - 1000); >> > > > >> > > > printf("msec = %d\n", msec); >> > > > >> > > > close(kq); >> > > > return EXIT_SUCCESS; >> > > > } >> > > > >> > > > >> > > >> > > What you are seeing is "just the way FreeBSD currently works." >> > > >> > > Sleeping (in most all of its various forms, and I've just looked at the >> > > kevent code to verify this is true there) is handled by converting the >> > > amount of time to sleep (usually specified in a timeval or timespec >> > > struct) to a count of timer ticks, using an internal routine called >> > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to >> > > account for the current tick. Whether that's a good idea or not (it >> > > probably was once, and probably not anymore) it's how things currently >> > > work, and could explain the fairly consistant +1ms you're seeing. >> > >> > This is all true, but mostly irrelevant for his case. EVFILT_TIMER >> > installs a periodic callout that executes KNOTE() and then resets itself >> > (via >> > callout_reset()) each time it runs. This should generally be closer to >> > regulary spaced intervals than something that does: >> > >> >> In what way is it irrelevant? That is, what did I miss? It appears to >> me that the next callout is scheduled by calling timertoticks() passing >> a count of milliseconds, that count is converted to a struct timeval and >> passed to tvtohz() which is where the +1 adjustment happens. If you ask >> for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. >> There is some time, likely a small number of microseconds, that you've >> consumed of the current tick, and that's what the +1 in tvtohz() is >> supposed to account for according to the comments. >> >> The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick >> and then adds one tick on top of that. That seems not quite right to >> me, except that it is a way to g'tee that you don't return early, and >> that is the one promise made by sleep routines on any OS; those magical >> "at least" words always appear in the docs. >> >> Actually what I'm missing (that I know of) is how the scheduler works. >> Maybe the +1 adjustment to account for the fraction of the current tick >> you've already consumed is the right thing to do, even when that >> fraction is 1uS or less of a 1mS tick. That would depend on scheduler >> behavior that I know nothing about. > > Oh. My bad, sorry. You are correct. It is a bug to use +1 in this > case. That is, the +1 makes sense when you are computing a one-time delta > for thing
Re: kqueue periodic timer confusion
On Thursday, July 12, 2012 9:57:16 am Ian Lepore wrote: > On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > > > > Hi, > > > > > > > > Sorry about this repost but I'm confused about the responses I received > > > > in my last post so I'm looking for some clarification. > > > > > > > > Specifically, I though I could use the kqueue timer as essentially a > > > > "drop in" replacement for linuxfd_create/read, but was surprised that > > > > the accuracy of the kqueue timer is much less than what I need for my > > > > application. > > > > > > > > So my confusion at this point is whether this is consider to be a bug or > > > > "feature"? > > > > > > > > Here's some test code if you want to verify the problem: > > > > > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > > > > > int > > > > main(void) > > > > { > > > > int i,msec; > > > > int kq,nev; > > > > struct kevent inqueue; > > > > struct kevent outqueue; > > > > struct timeval start,end; > > > > > > > > if ((kq = kqueue()) == -1) { > > > > fprintf(stderr, "kqueue error!? errno = %s", > > strerror(errno)); > > > > exit(EXIT_FAILURE); > > > > } > > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > > > > > > > > gettimeofday(&start, 0); > > > > for (i = 0; i < 50; i++) { > > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) > > > > == > > -1) { > > > > fprintf(stderr, "kevent error!? errno = %s", > > strerror(errno)); > > > > exit(EXIT_FAILURE); > > > > } else if (outqueue.flags & EV_ERROR) { > > > > fprintf(stderr, "EV_ERROR: %s\n", > > strerror(outqueue.data)); > > > > exit(EXIT_FAILURE); > > > > } > > > > } > > > > gettimeofday(&end, 0); > > > > > > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > > end.tv_usec - start.tv_usec) / 1000) - 1000); > > > > > > > > printf("msec = %d\n", msec); > > > > > > > > close(kq); > > > > return EXIT_SUCCESS; > > > > } > > > > > > > > > > > > > > What you are seeing is "just the way FreeBSD currently works." > > > > > > Sleeping (in most all of its various forms, and I've just looked at the > > > kevent code to verify this is true there) is handled by converting the > > > amount of time to sleep (usually specified in a timeval or timespec > > > struct) to a count of timer ticks, using an internal routine called > > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > > > account for the current tick. Whether that's a good idea or not (it > > > probably was once, and probably not anymore) it's how things currently > > > work, and could explain the fairly consistant +1ms you're seeing. > > > > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > > installs a periodic callout that executes KNOTE() and then resets itself > > (via > > callout_reset()) each time it runs. This should generally be closer to > > regulary spaced intervals than something that does: > > > > In what way is it irrelevant? That is, what did I miss? It appears to > me that the next callout is scheduled by calling timertoticks() passing > a count of milliseconds, that count is converted to a struct timeval and > passed to tvtohz() which is where the +1 adjustment happens. If you ask > for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. > There is some time, likely a small number of microseconds, that you've > consumed of the current tick, and that's what the +1 in tvtohz() is > supposed to account for according to the comments. > > The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick > and then adds one tick on top of that. That seems not quite right to > me, except that it is a way to g'tee that you don't return early, and > that is the one promise made by sleep routines on any OS; those magical > "at least" words always appear in the docs. > > Actually what I'm missing (that I know of) is how the scheduler works. > Maybe the +1 adjustment to account for the fraction of the current tick > you've already consumed is the right thing to do, even when that > fraction is 1uS or less of a 1mS tick. That would depend on scheduler > behavior that I know nothing about. Oh. My bad, sorry. You are correct. It is a bug to use +1 in this case. That is, the +1 makes sense when you are computing a one-time delta for things like nanosleep(). It is incorrect when computing a periodic delta such as for computing the interval for an itimer (setitimer) or EVFILT_TIMER(). Hah, setitime
Re: kqueue periodic timer confusion
On Thu, 2012-07-12 at 08:34 -0400, John Baldwin wrote: > On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > > > Hi, > > > > > > Sorry about this repost but I'm confused about the responses I received > > > in my last post so I'm looking for some clarification. > > > > > > Specifically, I though I could use the kqueue timer as essentially a > > > "drop in" replacement for linuxfd_create/read, but was surprised that > > > the accuracy of the kqueue timer is much less than what I need for my > > > application. > > > > > > So my confusion at this point is whether this is consider to be a bug or > > > "feature"? > > > > > > Here's some test code if you want to verify the problem: > > > > > > #include > > > #include > > > #include > > > #include > > > #include > > > #include > > > #include > > > #include > > > > > > int > > > main(void) > > > { > > > int i,msec; > > > int kq,nev; > > > struct kevent inqueue; > > > struct kevent outqueue; > > > struct timeval start,end; > > > > > > if ((kq = kqueue()) == -1) { > > > fprintf(stderr, "kqueue error!? errno = %s", > strerror(errno)); > > > exit(EXIT_FAILURE); > > > } > > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > > > > > > gettimeofday(&start, 0); > > > for (i = 0; i < 50; i++) { > > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) > > > == > -1) { > > > fprintf(stderr, "kevent error!? errno = %s", > strerror(errno)); > > > exit(EXIT_FAILURE); > > > } else if (outqueue.flags & EV_ERROR) { > > > fprintf(stderr, "EV_ERROR: %s\n", > strerror(outqueue.data)); > > > exit(EXIT_FAILURE); > > > } > > > } > > > gettimeofday(&end, 0); > > > > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > end.tv_usec - start.tv_usec) / 1000) - 1000); > > > > > > printf("msec = %d\n", msec); > > > > > > close(kq); > > > return EXIT_SUCCESS; > > > } > > > > > > > > > > What you are seeing is "just the way FreeBSD currently works." > > > > Sleeping (in most all of its various forms, and I've just looked at the > > kevent code to verify this is true there) is handled by converting the > > amount of time to sleep (usually specified in a timeval or timespec > > struct) to a count of timer ticks, using an internal routine called > > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > > account for the current tick. Whether that's a good idea or not (it > > probably was once, and probably not anymore) it's how things currently > > work, and could explain the fairly consistant +1ms you're seeing. > > This is all true, but mostly irrelevant for his case. EVFILT_TIMER > installs a periodic callout that executes KNOTE() and then resets itself (via > callout_reset()) each time it runs. This should generally be closer to > regulary spaced intervals than something that does: > In what way is it irrelevant? That is, what did I miss? It appears to me that the next callout is scheduled by calling timertoticks() passing a count of milliseconds, that count is converted to a struct timeval and passed to tvtohz() which is where the +1 adjustment happens. If you ask for 20ms and each tick is 1ms, then you'd get regular spacing of 21ms. There is some time, likely a small number of microseconds, that you've consumed of the current tick, and that's what the +1 in tvtohz() is supposed to account for according to the comments. The tvtohz() routine both rounds up in the usual way (value+tick-1)/tick and then adds one tick on top of that. That seems not quite right to me, except that it is a way to g'tee that you don't return early, and that is the one promise made by sleep routines on any OS; those magical "at least" words always appear in the docs. Actually what I'm missing (that I know of) is how the scheduler works. Maybe the +1 adjustment to account for the fraction of the current tick you've already consumed is the right thing to do, even when that fraction is 1uS or less of a 1mS tick. That would depend on scheduler behavior that I know nothing about. -- Ian ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: kqueue periodic timer confusion
On Wednesday, July 11, 2012 5:00:47 pm Ian Lepore wrote: > On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > > Hi, > > > > Sorry about this repost but I'm confused about the responses I received > > in my last post so I'm looking for some clarification. > > > > Specifically, I though I could use the kqueue timer as essentially a > > "drop in" replacement for linuxfd_create/read, but was surprised that > > the accuracy of the kqueue timer is much less than what I need for my > > application. > > > > So my confusion at this point is whether this is consider to be a bug or > > "feature"? > > > > Here's some test code if you want to verify the problem: > > > > #include > > #include > > #include > > #include > > #include > > #include > > #include > > #include > > > > int > > main(void) > > { > > int i,msec; > > int kq,nev; > > struct kevent inqueue; > > struct kevent outqueue; > > struct timeval start,end; > > > > if ((kq = kqueue()) == -1) { > > fprintf(stderr, "kqueue error!? errno = %s", strerror(errno)); > > exit(EXIT_FAILURE); > > } > > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > > > > gettimeofday(&start, 0); > > for (i = 0; i < 50; i++) { > > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) == -1) { > > fprintf(stderr, "kevent error!? errno = %s", strerror(errno)); > > exit(EXIT_FAILURE); > > } else if (outqueue.flags & EV_ERROR) { > > fprintf(stderr, "EV_ERROR: %s\n", strerror(outqueue.data)); > > exit(EXIT_FAILURE); > > } > > } > > gettimeofday(&end, 0); > > > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + end.tv_usec - start.tv_usec) / 1000) - 1000); > > > > printf("msec = %d\n", msec); > > > > close(kq); > > return EXIT_SUCCESS; > > } > > > > > > What you are seeing is "just the way FreeBSD currently works." > > Sleeping (in most all of its various forms, and I've just looked at the > kevent code to verify this is true there) is handled by converting the > amount of time to sleep (usually specified in a timeval or timespec > struct) to a count of timer ticks, using an internal routine called > tvtohz() in kern/kern_time.c. That routine rounds up by one tick to > account for the current tick. Whether that's a good idea or not (it > probably was once, and probably not anymore) it's how things currently > work, and could explain the fairly consistant +1ms you're seeing. This is all true, but mostly irrelevant for his case. EVFILT_TIMER installs a periodic callout that executes KNOTE() and then resets itself (via callout_reset()) each time it runs. This should generally be closer to regulary spaced intervals than something that does: for (;;) { usleep(20 * 1000); } Which should be subject to the problem you are describing. It would be interesting to see if the callout routine itself is running at the right interval or if it is being delayed. If the latter, then that should be fixed if at all possible. You could investigate that by adding KTR traces to the relevant callout routine (so recording the TSC timestamp each time the callout runs), and then parsing the ktrdump output to compute TSC deltas and examining that distribution to see if it is noisy or incorrect, etc. -- John Baldwin ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: kqueue periodic timer confusion
On Wed, Jul 11, 2012 at 9:52 PM, Paul Albrecht wrote: > > Hi, > > Sorry about this repost but I'm confused about the responses I received > in my last post so I'm looking for some clarification. > > Specifically, I though I could use the kqueue timer as essentially a > "drop in" replacement for linuxfd_create/read, but was surprised that > the accuracy of the kqueue timer is much less than what I need for my > application. > > So my confusion at this point is whether this is consider to be a bug or > "feature"? > > Here's some test code if you want to verify the problem: > > #include > #include > #include > #include > #include > #include > #include > #include > > int > main(void) > { > int i,msec; > int kq,nev; > struct kevent inqueue; > struct kevent outqueue; > struct timeval start,end; > > if ((kq = kqueue()) == -1) { > fprintf(stderr, "kqueue error!? errno = %s", strerror(errno)); > exit(EXIT_FAILURE); > } > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > > gettimeofday(&start, 0); > for (i = 0; i < 50; i++) { > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) == > -1) { > fprintf(stderr, "kevent error!? errno = %s", > strerror(errno)); > exit(EXIT_FAILURE); > } else if (outqueue.flags & EV_ERROR) { > fprintf(stderr, "EV_ERROR: %s\n", > strerror(outqueue.data)); > exit(EXIT_FAILURE); > } > } > gettimeofday(&end, 0); > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > end.tv_usec - start.tv_usec) / 1000) - 1000); > > printf("msec = %d\n", msec); > > close(kq); > return EXIT_SUCCESS; > } > > > -- > Paul Albrecht > > ___ > freebsd-hackers@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-hackers > To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org" Hi. As I told you before I'm currently working on this problem. I wrote a testcase myself, you can find it here: http://people.freebsd.org/~davide/kqueue/kevent_test.c As part of my callout(9) rewriting work I've recently converted kqueue(9) in order to exploit the precision allowed by the new backend and exposed to consumers via the new interface (callout_reset_bt_on()). I ran my testcase and these are the results over 100 iterations: http://people.freebsd.org/~davide/kqueue/kqueue_res.png (red line-> old, green line -> new). It seems there's some improvement, at least for now. If you want to give it a try checkout the projects/calloutng branch and apply the following patch http://people.freebsd.org/~davide/kqueue/kqueue_calloutng.diff (still in an early stage, if there are some issues, feel free to report them). Davide ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: kqueue periodic timer confusion
On Wed, 2012-07-11 at 14:52 -0500, Paul Albrecht wrote: > Hi, > > Sorry about this repost but I'm confused about the responses I received > in my last post so I'm looking for some clarification. > > Specifically, I though I could use the kqueue timer as essentially a > "drop in" replacement for linuxfd_create/read, but was surprised that > the accuracy of the kqueue timer is much less than what I need for my > application. > > So my confusion at this point is whether this is consider to be a bug or > "feature"? > > Here's some test code if you want to verify the problem: > > #include > #include > #include > #include > #include > #include > #include > #include > > int > main(void) > { > int i,msec; > int kq,nev; > struct kevent inqueue; > struct kevent outqueue; > struct timeval start,end; > > if ((kq = kqueue()) == -1) { > fprintf(stderr, "kqueue error!? errno = %s", strerror(errno)); > exit(EXIT_FAILURE); > } > EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); > > gettimeofday(&start, 0); > for (i = 0; i < 50; i++) { > if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) == > -1) { > fprintf(stderr, "kevent error!? errno = %s", > strerror(errno)); > exit(EXIT_FAILURE); > } else if (outqueue.flags & EV_ERROR) { > fprintf(stderr, "EV_ERROR: %s\n", > strerror(outqueue.data)); > exit(EXIT_FAILURE); > } > } > gettimeofday(&end, 0); > > msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + > end.tv_usec - start.tv_usec) / 1000) - 1000); > > printf("msec = %d\n", msec); > > close(kq); > return EXIT_SUCCESS; > } > > What you are seeing is "just the way FreeBSD currently works." Sleeping (in most all of its various forms, and I've just looked at the kevent code to verify this is true there) is handled by converting the amount of time to sleep (usually specified in a timeval or timespec struct) to a count of timer ticks, using an internal routine called tvtohz() in kern/kern_time.c. That routine rounds up by one tick to account for the current tick. Whether that's a good idea or not (it probably was once, and probably not anymore) it's how things currently work, and could explain the fairly consistant +1ms you're seeing. Another source of oversleeping is that the length of a tick in microseconds is simplisticly calculated as 100 / hz on most hardware, so for HZ=1000, tick=1000. Unless the clock producing the tick interrupts is running at a frequency exactly divisible by 1000, that tick-length calculation has some rounding error in it, and it results in systematic oversleeping. On modern hardware with high-frequency clocks it's typically less than 1%. The routines for sleeping in the kernel take a count of ticks for how long to sleep, so when tvtohz() converts some number of microseconds to the corresponding number of ticks, any rounding error in the value for the length of a tick results in oversleeping by some small percentage of the time you wanted to sleep. Note that this rounding error in calculating the length of a tick does not result in a systematic skew in system timekeeping, because when each tick interrupt happens, the system reads a clock counter register that may or may not be related to the clock producing tick interrupts; the value in the register is full precision without the rounding error you get when counting ticks. It might be an interesting experiment to add kern.hz=1 to your /boot/loader.conf and see how that affects your test. -- Ian ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
kqueue periodic timer confusion
Hi, Sorry about this repost but I'm confused about the responses I received in my last post so I'm looking for some clarification. Specifically, I though I could use the kqueue timer as essentially a "drop in" replacement for linuxfd_create/read, but was surprised that the accuracy of the kqueue timer is much less than what I need for my application. So my confusion at this point is whether this is consider to be a bug or "feature"? Here's some test code if you want to verify the problem: #include #include #include #include #include #include #include #include int main(void) { int i,msec; int kq,nev; struct kevent inqueue; struct kevent outqueue; struct timeval start,end; if ((kq = kqueue()) == -1) { fprintf(stderr, "kqueue error!? errno = %s", strerror(errno)); exit(EXIT_FAILURE); } EV_SET(&inqueue, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 20, 0); gettimeofday(&start, 0); for (i = 0; i < 50; i++) { if ((nev = kevent(kq, &inqueue, 1, &outqueue, 1, NULL)) == -1) { fprintf(stderr, "kevent error!? errno = %s", strerror(errno)); exit(EXIT_FAILURE); } else if (outqueue.flags & EV_ERROR) { fprintf(stderr, "EV_ERROR: %s\n", strerror(outqueue.data)); exit(EXIT_FAILURE); } } gettimeofday(&end, 0); msec = ((end.tv_sec - start.tv_sec) * 1000) + (((100 + end.tv_usec - start.tv_usec) / 1000) - 1000); printf("msec = %d\n", msec); close(kq); return EXIT_SUCCESS; } -- Paul Albrecht ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"