Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Crystal::System::Time.ticks #14620

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/crystal/system/time.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ module Crystal::System::Time
# since `0001-01-01 00:00:00`.
# def self.compute_utc_seconds_and_nanoseconds : {Int64, Int32}

# Returns the current time from the monotonic clock in `{seconds,
# nanoseconds}`.
# def self.monotonic : {Int64, Int32}

# Returns the current time from the monotonic clock in nanoseconds.
# Doesn't raise nor allocates GC HEAP memory.
# def self.ticks : UInt64

# Returns a list of paths where time zone data should be looked up.
# def self.zone_sources : Enumerable(String)

Expand Down
21 changes: 16 additions & 5 deletions src/crystal/system/unix/time.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,27 @@ require "c/time"
{% end %}

module Crystal::System::Time
UnixEpochInSeconds = 62135596800_i64
UNIX_EPOCH_IN_SECONDS = 62135596800_i64
NANOSECONDS_PER_SECOND = 1_000_000_000

def self.compute_utc_seconds_and_nanoseconds : {Int64, Int32}
{% if LibC.has_method?("clock_gettime") %}
ret = LibC.clock_gettime(LibC::CLOCK_REALTIME, out timespec)
raise RuntimeError.from_errno("clock_gettime") unless ret == 0
{timespec.tv_sec.to_i64 + UnixEpochInSeconds, timespec.tv_nsec.to_i}
{timespec.tv_sec.to_i64 + UNIX_EPOCH_IN_SECONDS, timespec.tv_nsec.to_i}
{% else %}
ret = LibC.gettimeofday(out timeval, nil)
raise RuntimeError.from_errno("gettimeofday") unless ret == 0
{timeval.tv_sec.to_i64 + UnixEpochInSeconds, timeval.tv_usec.to_i * 1_000}
{timeval.tv_sec.to_i64 + UNIX_EPOCH_IN_SECONDS, timeval.tv_usec.to_i * 1_000}
{% end %}
end

def self.monotonic : {Int64, Int32}
{% if flag?(:darwin) %}
info = mach_timebase_info
total_nanoseconds = LibC.mach_absolute_time * info.numer // info.denom
seconds = total_nanoseconds // 1_000_000_000
nanoseconds = total_nanoseconds.remainder(1_000_000_000)
seconds = total_nanoseconds // NANOSECONDS_PER_SECOND
nanoseconds = total_nanoseconds.remainder(NANOSECONDS_PER_SECOND)
{seconds.to_i64, nanoseconds.to_i32}
{% else %}
if LibC.clock_gettime(LibC::CLOCK_MONOTONIC, out tp) == 1
Expand All @@ -45,6 +46,16 @@ module Crystal::System::Time
{% end %}
end

def self.ticks : UInt64
{% if flag?(:darwin) %}
info = mach_timebase_info
LibC.mach_absolute_time &* info.numer // info.denom
{% else %}
LibC.clock_gettime(LibC::CLOCK_MONOTONIC, out tp)
tp.tv_sec.to_u64! &* NANOSECONDS_PER_SECOND &+ tp.tv_nsec.to_u64!
{% end %}
end

def self.to_timespec(time : ::Time)
t = uninitialized LibC::Timespec
t.tv_sec = typeof(t.tv_sec).new(time.to_unix)
Expand Down
19 changes: 9 additions & 10 deletions src/crystal/system/win32/time.cr
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,20 @@ module Crystal::System::Time
((filetime.dwHighDateTime.to_u64 << 32) | filetime.dwLowDateTime.to_u64).to_f64 / FILETIME_TICKS_PER_SECOND.to_f64
end

@@performance_frequency : Int64 = begin
ret = LibC.QueryPerformanceFrequency(out frequency)
if ret == 0
raise RuntimeError.from_winerror("QueryPerformanceFrequency")
end

private class_getter performance_frequency : Int64 do
LibC.QueryPerformanceFrequency(out frequency)
frequency
end

def self.monotonic : {Int64, Int32}
if LibC.QueryPerformanceCounter(out ticks) == 0
raise RuntimeError.from_winerror("QueryPerformanceCounter")
end
LibC.QueryPerformanceCounter(out ticks)
frequency = performance_frequency
{ticks // frequency, (ticks.remainder(frequency) * NANOSECONDS_PER_SECOND / frequency).to_i32}
end

{ticks // @@performance_frequency, (ticks.remainder(@@performance_frequency) * NANOSECONDS_PER_SECOND / @@performance_frequency).to_i32}
def self.ticks : UInt64
LibC.QueryPerformanceCounter(out ticks)
ticks.to_u64! &* (NANOSECONDS_PER_SECOND // performance_frequency)
end

def self.load_localtime : ::Time::Location?
Expand Down
Loading