From 3f572156c5519641b2c2529b89a9f165397da917 Mon Sep 17 00:00:00 2001 From: Louis Wyborn Date: Wed, 12 Apr 2023 18:11:08 +0200 Subject: [PATCH 1/3] try read tsc_freq_khz Assert cps and cps2 are eq fix syntax use error types specify error types print string if error Trim whitespace before parsing Try read from kernel first, otherwise calculate value Syntax --- src/tsc_now.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/tsc_now.rs b/src/tsc_now.rs index 68deb85..84a62cd 100644 --- a/src/tsc_now.rs +++ b/src/tsc_now.rs @@ -216,13 +216,33 @@ fn is_tsc_percpu_stable() -> bool { f().unwrap_or(false) } +#[derive(Debug)] +enum TscReadError { + FailedToRead(std::io::Error), + FailedToParse((core::num::ParseIntError, String)), +} + +fn try_read_tsc_freq_khz() -> Result { + let s = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/tsc_freq_khz") + .map_err(TscReadError::FailedToRead)?; + s.trim() + .parse() + .map_err(|e| TscReadError::FailedToParse((e, s))) +} + /// Returns (1) cycles per second and (2) cycles from anchor. /// The result of subtracting `cycles_from_anchor` from newly fetched TSC /// can be used to /// 1. readjust TSC to begin from zero /// 2. sync TSCs between all CPUs fn cycles_per_sec(anchor: Instant) -> (u64, u64) { - let (cps, last_monotonic, last_tsc) = _cycles_per_sec(); + let (cps, last_monotonic, last_tsc) = if let Ok(tsc_freq_khz) = try_read_tsc_freq_khz() { + let (last_monotonic, last_tsc) = monotonic_with_tsc(); + (tsc_freq_khz * 1000, last_monotonic, last_tsc) + } else { + _calculate_cycles_per_sec() + }; + let nanos_from_anchor = (last_monotonic - anchor).as_nanos(); let cycles_flied = cps as f64 * nanos_from_anchor as f64 / 1_000_000_000.0; let cycles_from_anchor = last_tsc - cycles_flied.ceil() as u64; @@ -231,7 +251,7 @@ fn cycles_per_sec(anchor: Instant) -> (u64, u64) { } /// Returns (1) cycles per second, (2) last monotonic time and (3) associated tsc. -fn _cycles_per_sec() -> (u64, Instant, u64) { +fn _calculate_cycles_per_sec() -> (u64, Instant, u64) { let mut cycles_per_sec; let mut last_monotonic; let mut last_tsc; From fb1cfb3c08c1ecf73e8a3c728147988e876f5fe4 Mon Sep 17 00:00:00 2001 From: Louis Wyborn Date: Wed, 12 Apr 2023 18:16:07 +0200 Subject: [PATCH 2/3] Add comment --- src/tsc_now.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tsc_now.rs b/src/tsc_now.rs index 84a62cd..1f78c49 100644 --- a/src/tsc_now.rs +++ b/src/tsc_now.rs @@ -222,6 +222,10 @@ enum TscReadError { FailedToParse((core::num::ParseIntError, String)), } +/// Attempts to read the TSC frequency as reported by the linux kernel. +/// This value only exists in Google's production kernel, but it is not upstreamed to the mainline kernel tree. +/// However it is possible to export the value using a custom kernel module: +/// https://github.com/trailofbits/tsc_freq_khz fn try_read_tsc_freq_khz() -> Result { let s = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/tsc_freq_khz") .map_err(TscReadError::FailedToRead)?; From 9d54bc41f930506dc369ecd6190756d4cd1224ca Mon Sep 17 00:00:00 2001 From: Louis Wyborn Date: Thu, 13 Apr 2023 08:42:43 +0200 Subject: [PATCH 3/3] Bump dependencies to latest --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4aff190..3773dd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" keywords = ["TSC", "clock", "rdtsc", "timing", "nanosecond"] [dependencies] -ctor = "0.1.20" +ctor = "0.2" [target.'cfg(not(target_os = "wasi"))'.dependencies] libc = "0.2" @@ -21,8 +21,8 @@ libc = "0.2" wasi = "0.7" [dev-dependencies] -criterion = "0.3" -quanta = "0.9" +criterion = "0.4" +quanta = "0.11" rand = "0.8" [[bench]]