Skip to content

Commit 3e41724

Browse files
committed
Add the Timers module to measure real-time and cpu-time
This code is based on the `google/benchmarks` repository. - `realtime` is a monotonic high-resolution clock provided by the kernel. In most cases this is equivalent to `time_ns` in `Base`. - `cputime` is the time that the process was actually running on a processor. This excludes time spend in the kernel and time spend descheduled. The `Timers` module includes a fair-amount of platform specific code so the implementation is split between a generic *unix* implementation based on the high-resoltion clocked provided through `clock_gettime`. On *darwin* prior to 10.12.0 the kernel only provides `CLOCK_MONOTONIC` making it less useful and we have to fallback onto `getRUsage`. We intentional don't do error handling for the timer calls. Which may or may not be a wise choice.
1 parent ef5bc08 commit 3e41724

File tree

5 files changed

+161
-1
lines changed

5 files changed

+161
-1
lines changed

src/BenchmarkTools.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ end
1212

1313
const BENCHMARKTOOLS_VERSION = v"0.2.2"
1414

15+
##########
16+
# Timers #
17+
##########
18+
19+
include("timers/timers.jl")
20+
1521
##############
1622
# Parameters #
1723
##############
@@ -26,7 +32,9 @@ export loadparams!
2632

2733
include("trials.jl")
2834

29-
export gctime,
35+
export realtime,
36+
cputime,
37+
gctime,
3038
memory,
3139
allocs,
3240
params,

src/timers/darwin.jl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const RUSAGE_SELF = Cint(0)
2+
const RUSAGE_CHILDREN = Cint(-1)
3+
4+
struct TimeVal
5+
tv_sec::Clong
6+
tv_usec::Clong
7+
end
8+
9+
struct RUsage
10+
ru_utime::TimeVal
11+
ru_stime::TimeVal
12+
ru_maxrss::Clong
13+
ru_ixrss::Clong
14+
ru_idrss::Clong
15+
ru_isrss::Clong
16+
ru_minflt::Clong
17+
ru_majflt::Clong
18+
ru_nswap::Clong
19+
ru_inblock::Clong
20+
ru_outblock::Clong
21+
ru_msgsnd::Clong
22+
ru_msgrcv::Clong
23+
ru_nsignals::Clong
24+
ru_nvcsw::Clong
25+
ru_nivcsw::Clong
26+
end
27+
28+
@inline function maketime(ru::RUsage)
29+
user = ru.ru_utime.tv_sec * 1e9 + ru.ru_utime.tv_usec *1e3
30+
kernel = ru.ru_stime.tv_sec * 1e9 + ru.ru_stime.tv_usec *1e3
31+
return user+kernel
32+
end
33+
34+
@inline function realtime()
35+
Float64(Base.time_ns())
36+
end
37+
38+
@inline function cputime()
39+
ru = Ref{RUsage}()
40+
ccall(:getRUsage, Cint, (Cint, Ref{RUsage}), RUSAGE_SELF, ru)
41+
return maketime(ru[])
42+
end

src/timers/timers.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#=
2+
Based upon https://github.com/google/benchmark
3+
=#
4+
5+
module Timers
6+
import Compat
7+
8+
"""
9+
realtime()
10+
11+
Monotonic runtime counter
12+
13+
Returns time in ns as Float64.
14+
"""
15+
function realtime end
16+
17+
"""
18+
cputime()
19+
20+
Process specific CPU time clock.
21+
22+
Returns time in ns as Float64.
23+
"""
24+
function cputime end
25+
26+
function _applever()
27+
return VersionNumber(readchomp(`sw_vers -productVersion`))
28+
end
29+
30+
if Compat.Sys.isapple() && _applever() < v"10.12.0"
31+
include("darwin.jl")
32+
elseif Compat.Sys.isunix()
33+
include("unix.jl")
34+
elseif Compat.Sys.iswindows()
35+
include("windows.jl")
36+
else
37+
error("$(Sys.KERNEL) is not supported please file an issue")
38+
end
39+
end # module

src/timers/unix.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
struct TimeSpec
2+
tv_sec :: UInt64 # time_t
3+
tv_nsec :: UInt64
4+
end
5+
6+
maketime(ts) = ts.tv_sec * 1e9 + ts.tv_nsec
7+
8+
# From bits/times.h on a Linux system
9+
# Check if those are the same on BSD
10+
if Compat.Sys.islinux()
11+
const CLOCK_MONOTONIC = Cint(1)
12+
const CLOCK_PROCESS_CPUTIME_ID = Cint(2)
13+
elseif Sys.KERNEL == :FreeBSD # atleast on FreeBSD 11.1
14+
const CLOCK_MONOTONIC = Cint(4)
15+
const CLOCK_PROCESS_CPUTIME_ID = Cint(14)
16+
elseif Compat.Sys.isapple() # Version 10.12 required
17+
const CLOCK_MONOTONIC = Cint(6)
18+
const CLOCK_PROCESS_CPUTIME_ID = Cint(12)
19+
else
20+
error("""
21+
BenchmarkTools doesn't currently support your operating system.
22+
Please file an issue, your kernel is $(Sys.KERNEL)
23+
""")
24+
end
25+
26+
@inline function clock_gettime(cid)
27+
ts = Ref{TimeSpec}()
28+
ccall(:clock_gettime, Cint, (Cint, Ref{TimeSpec}), cid, ts)
29+
return ts[]
30+
end
31+
32+
@inline function realtime()
33+
maketime(clock_gettime(CLOCK_MONOTONIC))
34+
end
35+
36+
@inline function cputime()
37+
maketime(clock_gettime(CLOCK_PROCESS_CPUTIME_ID))
38+
end

src/timers/windows.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
FileTime
3+
4+
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
5+
"""
6+
struct FileTime
7+
dwHighDateTime::UInt32
8+
dwLowDateTime::UInt32
9+
end
10+
11+
const HANDLE = Ptr{Void}
12+
13+
@inline function maketime(kernel_time::FileTime, user_time::FileTime)
14+
kernel = (kernel_time.dwHighDateTime % UInt64) << 32 | kernel_time.dwLowDateTime
15+
user = ( user_time.dwHighDateTime % UInt64) << 32 | user_time.dwLowDateTime
16+
(kernel + user) * 1e2
17+
end
18+
19+
@inline function realtime()
20+
return Float64(Base.time_ns())
21+
end
22+
23+
@inline function cputime()
24+
proc = ccall(:GetCurrentProcess, HANDLE, ())
25+
creation_time = Ref{FileTime}()
26+
exit_time = Ref{FileTime}()
27+
kernel_time = Ref{FileTime}()
28+
user_time = Ref{FileTime}()
29+
30+
ccall(:GetProccessTimes, Cint, (HANDLE, Ref{FileTime}, Ref{FileTime}, Ref{FileTime}, Ref{FileTime}),
31+
proc, creation_time, exit_time, kernel_time, user_time)
32+
return maketime(kernel_time, user_time)
33+
end

0 commit comments

Comments
 (0)