profile: use specialized time__vpc_now

pull/4613/head
Delyan Angelov 2020-04-26 20:36:38 +03:00
parent 50a83736ff
commit e523540f3a
5 changed files with 48 additions and 36 deletions

View File

@ -3,5 +3,5 @@ module main
import time import time
const ( const (
profiled_program_time_used = time.sys_mono_now() profiled_program_time_used = time.seconds_per_minute
) )

View File

@ -10,31 +10,29 @@ const (
[typedef] [typedef]
struct C.mach_timebase_info_data_t { struct C.mach_timebase_info_data_t {
numer u64 numer u32
denom u64 denom u32
} }
fn C.mach_absolute_time() u64 fn C.mach_absolute_time() u64
fn C.mach_timebase_info(&C.mach_timebase_info_data_t) fn C.mach_timebase_info(&C.mach_timebase_info_data_t)
fn C.clock_gettime_nsec_np(int) u64
struct InternalTimeBase { struct InternalTimeBase {
numer u64 numer u32 = 1
denom u64 denom u32 = 1
} }
fn init_time_base() InternalTimeBase { fn init_time_base() InternalTimeBase {
mut tb := C.mach_timebase_info_data_t{} tb := C.mach_timebase_info_data_t{}
C.mach_timebase_info(&tb) C.mach_timebase_info(&tb)
return InternalTimeBase{numer:tb.numer, denom:tb.denom} return InternalTimeBase{numer:tb.numer, denom:tb.denom}
} }
fn sys_mono_now_darwin() u64 { fn sys_mono_now_darwin() u64 {
tm := C.mach_absolute_time() tm := C.mach_absolute_time()
return mul_div(tm - start_time, time_base.numer, time_base.denom) if time_base.denom == 0 {
C.mach_timebase_info(&time_base)
} }
return (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

@ -39,3 +39,19 @@ fn sys_mono_now() u64 {
} }
} }
// NB: vpc_now is used by `v -profile` .
// It should NOT call *any other v function*, just C functions and casts.
[inline]
fn vpc_now() u64 {
$if macos {
tm := C.mach_absolute_time()
if time_base.denom == 0 {
C.mach_timebase_info(&time_base)
}
return (tm - start_time) * time_base.numer / time_base.denom
} $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,48 +12,46 @@ struct C.tm {
tm_sec int tm_sec int
} }
[typedef]
struct C.LARGE_INTEGER {
QuadPart i64
}
const ( const (
// start_time is needed on Darwin and Windows because of potential overflows // 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() start_time = init_win_time_start()
freq_time = init_win_time_freq() freq_time = init_win_time_freq()
) )
fn C._mkgmtime(&C.tm) time_t fn C._mkgmtime(&C.tm) time_t
fn C.QueryPerformanceCounter(&C.LARGE_INTEGER) C.BOOL fn C.QueryPerformanceCounter(&u64) C.BOOL
fn C.QueryPerformanceFrequency(&C.LARGE_INTEGER) C.BOOL fn C.QueryPerformanceFrequency(&u64) C.BOOL
fn make_unix_time(t C.tm) int { fn make_unix_time(t C.tm) int {
return int(C._mkgmtime(&t)) return int(C._mkgmtime(&t))
} }
fn init_win_time_freq() u64 { fn init_win_time_freq() u64 {
mut f := C.LARGE_INTEGER{} f := u64(0)
_ := C.QueryPerformanceFrequency(&f) C.QueryPerformanceFrequency(&f)
return u64(f.QuadPart) return f
} }
fn init_win_time_start() u64 { fn init_win_time_start() u64 {
mut s := C.LARGE_INTEGER{} s := u64(0)
_ := C.QueryPerformanceCounter(&s) C.QueryPerformanceCounter(&s)
return u64(s.QuadPart) return s
} }
fn sys_mono_now() u64 { fn sys_mono_now() u64 {
mut tm := C.LARGE_INTEGER{} tm := u64(0)
_ := C.QueryPerformanceCounter(&tm) // XP or later never fail C.QueryPerformanceCounter(&tm) // XP or later never fail
return mul_div(u64(tm.QuadPart) - start_time, 1_000_000_000, freq_time) return (tm - start_time) * 1_000_000_000 / freq_time
} }
fn mul_div(val, numer, denom u64) u64 { // NB: vpc_now is used by `v -profile` .
q := val / denom // It should NOT call *any other v function*, just C functions and casts.
r := val % denom [inline]
return q * numer + r * numer / denom fn vpc_now() u64 {
tm := u64(0)
C.QueryPerformanceCounter(&tm)
return tm
} }

View File

@ -109,14 +109,14 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
g.writeln('\tatexit(vprint_profile_stats);') g.writeln('\tatexit(vprint_profile_stats);')
g.writeln('') g.writeln('')
} }
if it.name == 'time.sys_mono_now' { if it.name == 'time.vpc_now' {
g.defer_profile_code = '' g.defer_profile_code = ''
} else { } else {
fn_profile_counter_name := 'vpc_${g.last_fn_c_name}' fn_profile_counter_name := 'vpc_${g.last_fn_c_name}'
g.writeln('') g.writeln('')
g.writeln('\tdouble _PROF_FN_START = time__sys_mono_now(); ${fn_profile_counter_name}_calls++; // $it.name') g.writeln('\tdouble _PROF_FN_START = time__vpc_now(); ${fn_profile_counter_name}_calls++; // $it.name')
g.writeln('') g.writeln('')
g.defer_profile_code = '\t${fn_profile_counter_name} += time__sys_mono_now() - _PROF_FN_START;' g.defer_profile_code = '\t${fn_profile_counter_name} += time__vpc_now() - _PROF_FN_START;'
g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; u64 ${fn_profile_counter_name}_calls = 0;') g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; u64 ${fn_profile_counter_name}_calls = 0;')
g.pcs[g.last_fn_c_name] = fn_profile_counter_name g.pcs[g.last_fn_c_name] = fn_profile_counter_name
} }