Ticket UUID: | 2905784 | |||
Title: | Sync [after] works too hard | |||
Type: | Bug | Version: | None | |
Submitter: | ferrieux | Created on: | 2009-11-30 00:16:17 | |
Subsystem: | 03. Timer Events | Assigned To: | kennykb | |
Priority: | 7 High | Severity: | ||
Status: | Closed | Last Modified: | 2010-10-29 23:42:26 | |
Resolution: | Fixed | Closed By: | ferrieux | |
Closed on: | 2010-10-29 16:42:26 | |||
Description: |
Synchronous [after] makes many calls to the underlying OS's getttimeofday() or equivalent. This is due to an ill-defined responsibility boundary between AfterDelay() and Tcl_Sleep(). Indeed, Tcl_Sleep() already has the logic to repeatedly check the current time and wait, not trusting the OS's time, and also taking car of virtual time. However, AfterDelay repeats this logic one level up, calling Tcl_Sleep in a loop until endTime is reached. The existence of the loop in itself has good reasons, namely respecting a reasonable granularity for limits or Async stuff. But in the degenerate, but important, case of "small" delays below those limits, a very simple optimization (patch attached) lets AfterDelay call Tcl_Sleep exactly once, essentially "trusting" it on the accuracy of the resulting wait. Additionally, one trivial move of the Tcl_GetTime in the loop removes one unwanted extra gettimeofday(). The bottom line: this patch makes a small [after] generate only 3 gettimeofday()s: one on entry, to compute the endTime, and two inside Tcl_Sleep. Squeezing one more out would need a change in the Tcl_Sleep() API; I'm not attempting that. | |||
User Comments: |
ferrieux added on 2010-10-29 23:42:26:
Committed to HEAD. ferrieux added on 2010-10-29 23:36:39: Attaching the final patch. Care is taken to never undershoot, using a ceiling() approach when rounding usecs do msecs in time differences. Now a loop of {after 1} consumes < 0.1% CPU instead of 50%. Also, the total syscall budget is much reduced: one select() and three gettimeofday() only for a small [after]. Cost in accuracy: % time {after 1} 1000 1060.089 microseconds per iteration % time {after 2} 1000 2061.111 microseconds per iteration % time {after 3} 1000 3062.367 microseconds per iteration % time {after 100} 10 100235.0 microseconds per iteration % time {after 10000} 1 10002067 microseconds per iteration ferrieux added on 2010-10-29 23:31:58: File Added - 391655: afteropt2.patch ferrieux added on 2009-11-30 07:19:53: The attached patch includes the 2904418 fix, which removes the bulk of the unneeded gettimeofday()s. ferrieux added on 2009-11-30 07:18:21: File Added - 353060: afteropt.patch |