Browse Source

add sleep-fallback and invariant check

Colin Davidson 2 years ago
parent
commit
8e5e43f335
4 changed files with 60 additions and 20 deletions
  1. 31 2
      core/time/perf.odin
  2. 21 0
      core/time/tsc_freebsd.odin
  3. 7 0
      core/time/tsc_openbsd.odin
  4. 1 18
      core/time/tsc_windows.odin

+ 31 - 2
core/time/perf.odin

@@ -6,7 +6,6 @@ import "core:intrinsics"
 Tick :: struct {
 Tick :: struct {
 	_nsec: i64, // relative amount
 	_nsec: i64, // relative amount
 }
 }
-
 tick_now :: proc "contextless" () -> Tick {
 tick_now :: proc "contextless" () -> Tick {
 	return _tick_now()
 	return _tick_now()
 }
 }
@@ -56,8 +55,38 @@ when ODIN_ARCH == .amd64 {
 	}
 	}
 }
 }
 
 
+has_invariant_tsc :: proc "contextless" () -> bool {
+	when ODIN_ARCH == .amd64 {
+		return x86_has_invariant_tsc()
+	}
+
+	return false
+}
+
+_get_tsc_frequency_fallback :: proc "contextless" () -> u64 {
+	tsc_begin := intrinsics.read_cycle_counter()
+	tick_begin := tick_now()
+
+	sleep(2 * Second)
+
+	tsc_end := intrinsics.read_cycle_counter()
+	tick_end := tick_now()
+
+	time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end)))
+	return u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff)
+}
+
 get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
 get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
-	return _get_tsc_frequency()
+	if !has_invariant_tsc() {
+		return 0, false
+	}
+
+	hz, ok := _get_tsc_frequency()
+	if !ok {
+		hz = _get_tsc_frequency_fallback()
+	}
+
+	return hz, true
 }
 }
 
 
 /*
 /*

+ 21 - 0
core/time/tsc_freebsd.odin

@@ -0,0 +1,21 @@
+//+private
+//+build freebsd
+package time
+
+import "core:c"
+
+foreign import libc "system:c"
+foreign libc {
+	@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
+}
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	tmp_freq : u64 = 0
+	tmp_size : i64 = size_of(tmp_freq)
+	ret := _sysctlbyname("machdep.tsc_freq", &tmp_freq, &tmp_size, nil, 0)
+	if ret < 0 {
+		return 0, false
+	}
+
+	return tmp_freq, true
+}

+ 7 - 0
core/time/tsc_openbsd.odin

@@ -0,0 +1,7 @@
+//+private
+//+build openbsd
+package time
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	return 0, false
+}

+ 1 - 18
core/time/tsc_windows.odin

@@ -2,23 +2,6 @@
 //+build windows
 //+build windows
 package time
 package time
 
 
-import "core:intrinsics"
-import win32 "core:sys/windows"
-
 _get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
 _get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
-	qpc_begin: win32.LARGE_INTEGER
-	win32.QueryPerformanceCounter(&qpc_begin)
-	tsc_begin := intrinsics.read_cycle_counter()
-
-	win32.Sleep(2)
-
-	qpc_end: win32.LARGE_INTEGER
-	win32.QueryPerformanceCounter(&qpc_end)
-	tsc_end := intrinsics.read_cycle_counter()
-
-	qpc_frequency: win32.LARGE_INTEGER
-	win32.QueryPerformanceFrequency(&qpc_frequency)
-
-	frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin))
-	return frequency, true
+	return 0, false
 }
 }