Skip to content

Commit

Permalink
Merge pull request #38 from ChaelCodes/hyper-accurate-timing
Browse files Browse the repository at this point in the history
Hyper Accurate Timing for Slow Systems
  • Loading branch information
jhawthorn authored Nov 13, 2023
2 parents fefcfbe + 56e3af1 commit 8e4bc96
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 10 deletions.
17 changes: 10 additions & 7 deletions ext/vernier/vernier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,17 @@ class TimeStamp {
return TimeStamp(0);
}

static void Sleep(const TimeStamp &time) {
struct timespec ts = time.timespec();
// SleepUntil a specified timestamp
// Highly accurate manual sleep time
static void SleepUntil(const TimeStamp &target_time) {
if (target_time.zero()) return;
struct timespec ts = target_time.timespec();

int res;
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
// do nothing until it's time :)
sleep(0);
} while (target_time > TimeStamp::Now());
}

static TimeStamp from_microseconds(uint64_t us) {
Expand Down Expand Up @@ -1252,13 +1256,12 @@ class TimeCollector : public BaseCollector {

next_sample_schedule += interval;

// If sampling falls behind, restart, and check in another interval
if (next_sample_schedule < sample_complete) {
//fprintf(stderr, "fell behind by %ius\n", (sample_complete - next_sample_schedule).microseconds());
next_sample_schedule = sample_complete + interval;
}

TimeStamp sleep_time = next_sample_schedule - sample_complete;
TimeStamp::Sleep(sleep_time);
TimeStamp::SleepUntil(next_sample_schedule);
}

thread_stopped.post();
Expand Down
11 changes: 8 additions & 3 deletions test/test_time_collector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
require "test_helper"

class TestTimeCollector < Minitest::Test
SLEEP_SCALE = ENV.fetch("TEST_SLEEP_SCALE", 0.1).to_f # seconds/100ms
SAMPLE_SCALE_INTERVAL = 10_000 * SLEEP_SCALE # Microseconds

def bar
sleep 0.1
sleep SLEEP_SCALE
end

def foo
Expand All @@ -28,7 +31,7 @@ def test_receives_gc_events
end

def test_time_collector
collector = Vernier::Collector.new(:wall, interval: 1000)
collector = Vernier::Collector.new(:wall, interval: SAMPLE_SCALE_INTERVAL)
collector.start
foo
result = collector.stop
Expand All @@ -45,7 +48,7 @@ def test_time_collector
end

def test_sleeping_threads
collector = Vernier::Collector.new(:wall, interval: 1000)
collector = Vernier::Collector.new(:wall, interval: SAMPLE_SCALE_INTERVAL)
th1 = Thread.new { foo; Thread.current.native_thread_id }
th2 = Thread.new { foo; Thread.current.native_thread_id }
collector.start
Expand All @@ -54,8 +57,10 @@ def test_sleeping_threads
result = collector.stop

tally = result.threads.transform_values do |thread|
# Number of samples
thread[:weights].sum
end.to_h

assert_in_epsilon 200, tally[Thread.current.native_thread_id], generous_epsilon
assert_in_epsilon 200, tally[th1id], generous_epsilon
assert_in_epsilon 200, tally[th2id], generous_epsilon
Expand Down

0 comments on commit 8e4bc96

Please sign in to comment.