Skip to content

Commit

Permalink
common-dylan/timers.dylan: new function microsecond-counter
Browse files Browse the repository at this point in the history
I needed some kind of low-level system counter to implement a clock() built-in
while writing the interpreter in Crafting Interpreters and common-dylan:timers
has almost the right thing and seems a natural place to add one.
  • Loading branch information
cgay committed Nov 6, 2024
1 parent d10a340 commit ef0857f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 1 deletion.
3 changes: 2 additions & 1 deletion sources/common-dylan/library.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ define module simple-timers
timer-start,
timer-stop,
timer-accumulated-time,
timer-running?;
timer-running?,
microsecond-counter;
end module simple-timers;

define module byte-vector
Expand Down
1 change: 1 addition & 0 deletions sources/common-dylan/tests/common-dylan-test-suite.lid
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Files: library
streams
byte-vector
machine-words
timers-tests
transcendentals
regressions
threads/simple-locks
Expand Down
1 change: 1 addition & 0 deletions sources/common-dylan/tests/library.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ define module common-dylan-test-suite
use simple-format;
use simple-random;
use simple-profiling;
use simple-timers;
use file-system,
import: { file-exists? };
use operating-system,
Expand Down
14 changes: 14 additions & 0 deletions sources/common-dylan/tests/timers-tests.dylan
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Module: common-dylan-test-suite


define test test-microsecond-counter ()
let t1 = microsecond-counter();
sleep(0.1);
let t2 = microsecond-counter();
let diff = t2 - t1;
// I need slop to be at least 5200 on my macOS M3 Pro. Be more generous than
// that since the main point is simply to exercise the function at all. --cgay
let slop = 50_000;
assert-true(diff >= (100_000 - slop) & diff < (100_000 + slop),
diff);
end test;
15 changes: 15 additions & 0 deletions sources/common-dylan/timers.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,18 @@ define inline function %timer-diff-times
values(seconds, microseconds)
end if
end;

// We use a microsecond counter rather than nanoseconds because implementations
// may legitimately return a time since some arbitrary epoch rather than, say,
// the machine uptime, and that could easily overflow given only 61 usable
// bits. Ex: In 2024, the nanos since 1970-01-01 already uses 61 bits.
define function microsecond-counter () => (microseconds :: <integer>)
let (sec :: <machine-word>, nano :: <machine-word>)
= %timer-current-time();
// I think coerce...(u%-(sec, 0)) is faster than as-unsigned(<integer>, sec)
// due to the latter causing a fully dynamic gf method dispatch. Is there a
// better way?
let seconds :: <integer> = coerce-machine-word-to-integer(u%-(sec, 0));
let microseconds :: <integer> = coerce-machine-word-to-integer(u%divide(nano, 1000));
seconds * 1_000_000 + microseconds
end function;

0 comments on commit ef0857f

Please sign in to comment.