time: Timer -> StopWatch; time.Duration

pull/4573/head
Major Taylor 2020-04-24 01:33:25 -04:00 committed by GitHub
parent f3e3d7e0c5
commit 25f2b171fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 225 additions and 72 deletions

View File

@ -54,8 +54,8 @@ const (
pub struct Benchmark {
pub mut:
bench_timer time.Timer
step_timer time.Timer
bench_timer time.StopWatch
step_timer time.StopWatch
ntotal int
nok int
nfail int
@ -70,14 +70,14 @@ pub mut:
pub fn new_benchmark() Benchmark {
return Benchmark{
bench_timer: time.new_timer()
bench_timer: time.new_stopwatch()
verbose: true
}
}
pub fn new_benchmark_no_cstep() Benchmark {
return Benchmark{
bench_timer: time.new_timer()
bench_timer: time.new_stopwatch()
verbose: true
no_cstep: true
}
@ -85,7 +85,7 @@ pub fn new_benchmark_no_cstep() Benchmark {
pub fn new_benchmark_pointer() &Benchmark {
return &Benchmark{
bench_timer: time.new_timer()
bench_timer: time.new_stopwatch()
verbose: true
}
}
@ -147,7 +147,7 @@ pub fn start() Benchmark {
pub fn (b mut Benchmark) measure(label string) i64 {
b.ok()
res := b.step_timer.elapsed()
res := b.step_timer.elapsed().milliseconds()
println(b.step_message_with_label(BSPENT, 'in $label'))
b.step()
return res
@ -172,10 +172,10 @@ pub fn (b &Benchmark) step_message_with_label(label string, msg string) string {
'${b.cstep:3d}/${b.nexpected_steps:3d}'
}
}
timed_line = b.tdiff_in_ms('[${sprogress}] $msg', b.step_timer.elapsed())
timed_line = b.tdiff_in_ms('[${sprogress}] $msg', b.step_timer.elapsed().milliseconds())
}
else {
timed_line = b.tdiff_in_ms(msg, b.step_timer.elapsed())
timed_line = b.tdiff_in_ms(msg, b.step_timer.elapsed().milliseconds())
}
return '${label:-5s}${timed_line}'
}
@ -201,11 +201,11 @@ pub fn (b &Benchmark) total_message(msg string) string {
if b.verbose {
tmsg = '<=== total time spent $tmsg'
}
return ' ' + b.tdiff_in_ms(tmsg, b.bench_timer.elapsed())
return ' ' + b.tdiff_in_ms(tmsg, b.bench_timer.elapsed().milliseconds())
}
pub fn (b &Benchmark) total_duration() i64 {
return b.bench_timer.elapsed()
return b.bench_timer.elapsed().milliseconds()
}
// //////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,52 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module time
pub struct StopWatch {
pause_time u64
pub:
start u64
end u64
}
pub fn new_stopwatch() StopWatch {
return StopWatch{start: time.sys_mono_now()}
}
// start Starts the timer. If the timer was paused, restarts counting.
pub fn (t mut StopWatch) start() {
if t.pause_time == 0 {
t.start = time.sys_mono_now()
} else {
t.start += time.sys_mono_now() - t.pause_time
}
t.end = 0
t.pause_time = 0
}
pub fn (t mut StopWatch) restart() {
t.end = 0
t.pause_time = 0
t.start = time.sys_mono_now()
}
pub fn (t mut StopWatch) stop() {
t.end = time.sys_mono_now()
t.pause_time = 0
}
pub fn (t mut StopWatch) pause() {
t.pause_time = time.sys_mono_now()
t.end = t.pause_time // so elapsed keeps track of actual running time
}
// elapsed returns the Duration since the last start call
pub fn (t StopWatch) elapsed() Duration {
if t.end == 0 {
return Duration(time.sys_mono_now() - t.start)
} else {
return Duration(t.end - t.start)
}
}

View File

@ -20,7 +20,21 @@ const (
days_per_400_years = 365 * 400 + 97
days_per_100_years = 365 * 100 + 24
days_per_4_years = 365 * 4 + 1
days_before = [0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, ]
days_before = [
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
]
)
pub struct Time {
@ -121,7 +135,7 @@ pub fn (t Time) unix_time() int {
return make_unix_time(tt)
}
// add_days returns a new time struct with an added number of seconds.
// add_seconds returns a new time struct with an added number of seconds.
pub fn (t Time) add_seconds(seconds int) Time {
// TODO Add(d time.Duration)
return unix(t.unix + seconds)
@ -265,3 +279,48 @@ fn convert_ctime(t C.tm) Time {
unix: make_unix_time(t)
}
}
// A lot of these are taken from the Go library
pub type Duration i64
pub const(
nanosecond = Duration(1)
microsecond = Duration(1000) * nanosecond
millisecond = Duration(1000) * microsecond
second = Duration(1000) * millisecond
minute = Duration(60) * second
hour = Duration(60) * minute
)
// nanoseconds returns the duration as an integer number of nanoseconds.
pub fn (d Duration) nanoseconds() i64 { return i64(d) }
// microseconds returns the duration as an integer number of microseconds.
pub fn (d Duration) microseconds() i64 { return i64(d) / 1000 }
// milliseconds returns the duration as an integer number of milliseconds.
pub fn (d Duration) milliseconds() i64 { return i64(d) / 1_000_000 }
// The following functions return floating point numbers because it's common to
// consider all of them in sub-one intervals
// seconds returns the duration as a floating point number of seconds.
pub fn (d Duration) seconds() f64 {
sec := d / second
nsec := d % second
return f64(sec) + f64(nsec)/1e9
}
// minutes returns the duration as a floating point number of minutes.
pub fn (d Duration) minutes() f64 {
min := d / minute
nsec := d % minute
return f64(min) + f64(nsec)/(60*1e9)
}
// hours returns the duration as a floating point number of hours.
pub fn (d Duration) hours() f64 {
hr := d / hour
nsec := d % hour
return f64(hr) + f64(nsec)/(60*60*1e9)
}

View File

@ -0,0 +1,40 @@
module time
#include <mach/mach_time.h>
const (
// start_time is needed on Darwin and Windows because of potential overflows
start_time = C.mach_absolute_time()
time_base = init_time_base()
)
[typedef]
struct C.mach_timebase_info_data_t {
numer u64
denom u64
}
fn C.mach_absolute_time() u64
fn C.mach_timebase_info(&C.mach_timebase_info_data_t)
struct InternalTimeBase {
numer u64
denom u64
}
fn init_time_base() InternalTimeBase {
mut tb := C.mach_timebase_info_data_t{}
C.mach_timebase_info(&tb)
return InternalTimeBase{numer:tb.numer, denom:tb.denom}
}
fn sys_mono_now_darwin() u64 {
tm := C.mach_absolute_time()
return mul_div(tm - start_time, time_base.numer, time_base.denom)
}
fn mul_div(val, numer, denom u64) u64 {
q := val / denom
r := val % denom
return q * numer + r * numer / denom
}

View File

@ -17,3 +17,25 @@ fn C.timegm(&tm) time_t
fn make_unix_time(t C.tm) int {
return int(C.timegm(&t))
}
type time_t voidptr
// in most systems, these are __quad_t, which is an i64
struct C.timespec {
tv_sec i64
tv_nsec i64
}
// the first arg is defined in include/bits/types.h as `__S32_TYPE`, which is `int`
fn C.clock_gettime(int, &C.timespec)
fn sys_mono_now() u64 {
$if macos {
return sys_mono_now_darwin()
} $else {
ts := C.timespec{}
C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
return u64(ts.tv_sec) * 1_000_000_000 + u64(ts.tv_nsec)
}
}

View File

@ -12,8 +12,48 @@ struct C.tm {
tm_sec int
}
[typedef]
struct C.LARGE_INTEGER {
QuadPart i64
}
const (
// start_time is needed on Darwin and Windows because of potential overflows
// Windows: don't store the LARGE_INTEGER, just the QuadPart
start_time = init_win_time_start()
freq_time = init_win_time_freq()
)
fn C._mkgmtime(&C.tm) time_t
fn C.QueryPerformanceCounter(&C.LARGE_INTEGER) C.BOOL
fn C.QueryPerformanceFrequency(&C.LARGE_INTEGER) C.BOOL
fn make_unix_time(t C.tm) int {
return int(C._mkgmtime(&t))
}
fn init_win_time_freq() u64 {
mut f := C.LARGE_INTEGER{}
_ := C.QueryPerformanceFrequency(&f)
return u64(f.QuadPart)
}
fn init_win_time_start() u64 {
mut s := C.LARGE_INTEGER{}
_ := C.QueryPerformanceCounter(&s)
return u64(s.QuadPart)
}
fn sys_mono_now() u64 {
mut tm := C.LARGE_INTEGER{}
_ := C.QueryPerformanceCounter(&tm) // XP or later never fail
return mul_div(u64(tm.QuadPart) - start_time, 1_000_000_000, freq_time)
}
fn mul_div(val, numer, denom u64) u64 {
q := val / denom
r := val % denom
return q * numer + r * numer / denom
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module time
// Timer struct and functions
// start and end are # of ms since start of system.
// When end_ticks == 0, this means the timer is actively "running"
pub struct Timer {
pause_start i64
pub:
start_ticks i64
end_ticks i64
}
// start Starts the timer. If the timer was paused, restarts counting.
pub fn (t mut Timer) start() {
if t.pause_start == 0 {
t.start_ticks = ticks()
} else {
// We were paused, so pretend like the time we were paused didn't
// happen
t.start_ticks += ticks() - t.pause_start
}
t.end_ticks = 0
t.pause_start = 0
}
pub fn (t mut Timer) restart() {
t.end_ticks = 0
t.pause_start = 0
t.start_ticks = ticks()
}
pub fn (t mut Timer) pause() {
t.pause_start = ticks()
t.end_ticks = t.pause_start // so elapsed() still keeps track of the cared-amount of time
}
pub fn (t mut Timer) stop() {
t.end_ticks = ticks()
t.pause_start = 0
}
// elapsed If the Timer is stopped, returns the number of milliseconds between
// the last start and stop.
// If the Timer is still running, returns the number of milliseconds from the
// last start to now.
pub fn (t Timer) elapsed() i64 {
if t.end_ticks == 0 {
return ticks() - t.start_ticks
} else {
return t.end_ticks - t.start_ticks
}
}
pub fn new_timer() Timer {
return Timer{start_ticks: ticks()}
}