Last active
May 17, 2023 07:39
-
-
Save leiless/22b6cf392622c6e48ca7ae9d4f15e169 to your computer and use it in GitHub Desktop.
_rdtsc ticks per second estimation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <assert.h> | |
#define N 10 | |
#define SIZE_OF(a) (sizeof(a) / sizeof(*a)) | |
int main(void) { | |
uint64_t arr[N] = {}; | |
uint64_t a, b; | |
unsigned int ret; | |
for (size_t i = 0; i < SIZE_OF(arr); i++) { | |
a = __builtin_ia32_rdtsc(); | |
ret = sleep(1); | |
b = __builtin_ia32_rdtsc(); | |
assert(ret == 0); | |
assert(b >= a); | |
arr[i] = b - a; | |
} | |
uint64_t max = 0; | |
uint64_t min = (uint64_t) -1; | |
uint64_t sum = 0; | |
for (size_t i = 0; i < SIZE_OF(arr); i++) { | |
printf("[%zu] = %zu\n", i, arr[i]); | |
if (max < arr[i]) { | |
max = arr[i]; | |
} | |
if (min > arr[i]) { | |
min = arr[i]; | |
} | |
sum += arr[i]; | |
} | |
printf("\n"); | |
printf("Min = %zu\n", max); | |
printf("Max = %zu\n", min); | |
printf("Max - Min = %zu\n", max - min); | |
printf("Avg = %zu\n", sum / N); | |
return 0; | |
} |
Simple Timer implementation in Rust
use std::fmt::Formatter;
#[derive(Debug, Copy, Clone)]
pub struct Timer {
tick0: u64,
pub timeout_secs: u64,
}
lazy_static::lazy_static! {
static ref TICKS_PER_SECOND: u64 = Timer::init();
}
impl Timer {
pub fn new(timeout_secs: u64) -> Self {
Self {
tick0: Self::_rdtsc(),
timeout_secs,
}
}
pub fn is_timed_out(&self) -> bool {
let due_time = self.tick0 + self.timeout_secs * *TICKS_PER_SECOND;
Self::_rdtsc() >= due_time
}
pub fn reset(&mut self, new_timeout_secs: Option<u64>) {
if let Some(timeout_secs) = new_timeout_secs {
self.timeout_secs = timeout_secs
}
self.tick0 = Self::_rdtsc();
}
#[inline(always)]
fn _rdtsc() -> u64 {
unsafe {
#[cfg(target_arch = "x86_64")]
return core::arch::x86_64::_rdtsc();
#[cfg(target_arch = "x86")]
return core::arch::x86::_rdtsc();
}
}
// FIXME: num_cpus::get()
// https://github.com/seanmonstar/num_cpus
// https://docs.rs/num_cpus/latest/num_cpus/
const N_THREAD: usize = 12;
fn init() -> u64 {
let sleep_time = std::time::Duration::from_secs(1);
let mut handles = Vec::with_capacity(Self::N_THREAD);
for _i in 0..Self::N_THREAD {
let sleep_time_1 = sleep_time.clone();
let h = std::thread::spawn(move || {
let a = Self::_rdtsc();
std::thread::sleep(sleep_time_1);
let b = Self::_rdtsc();
assert!(b >= a);
b - a
});
handles.push(h);
}
let mut sum = 0u64;
for h in handles {
let ticks_per_second = h.join().unwrap();
sum += ticks_per_second;
}
let avg_ticks_per_second = sum / Self::N_THREAD as u64;
avg_ticks_per_second
}
}
impl std::fmt::Display for Timer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
Use Timer
let now = std::time::SystemTime::now();
let mut t = timer::Timer::new(1);
while !t.is_timed_out() {}
let elapsed = std::time::SystemTime::now().duration_since(now).unwrap();
eprintln!("Time elapsed #1: {} ms", elapsed.as_millis());
let now = std::time::SystemTime::now();
t.reset(None);
while !t.is_timed_out() {}
let elapsed = std::time::SystemTime::now().duration_since(now).unwrap();
eprintln!("Time elapsed #2: {} ms", elapsed.as_millis());
let now = std::time::SystemTime::now();
t.reset(None);
while !t.is_timed_out() {}
let elapsed = std::time::SystemTime::now().duration_since(now).unwrap();
eprintln!("Time elapsed #3: {} ms", elapsed.as_millis());
eprintln!("{}", t);
fn estimate_ticks_per_second() {
const N_THREAD: usize = 12;
let mut handles = Vec::with_capacity(N_THREAD);
let sleep_time = std::time::Duration::from_secs(1);
for _i in 0..N_THREAD {
let sleep_time_1 = sleep_time.clone();
let h = std::thread::spawn(move || {
let a = unsafe { core::arch::x86_64::_rdtsc() };
std::thread::sleep(sleep_time_1);
let b = unsafe { core::arch::x86_64::_rdtsc() };
assert!(b >= a);
b - a
});
handles.push(h);
}
let mut v = Vec::with_capacity(handles.len());
for h in handles {
let ticks_per_second = h.join().unwrap();
v.push(ticks_per_second);
}
let min_tps = *v.iter().min().unwrap();
let max_tps = *v.iter().max().unwrap();
let avg_tps: u64 = v.iter().sum::<u64>() / N_THREAD as u64;
let std_dev = std_deviation(v.as_slice());
eprintln!(" N_THREAD: {}", N_THREAD);
eprintln!(" Min TPS: {}", min_tps);
eprintln!(" Max TPS: {}", max_tps);
eprintln!("Max - Min: {}", max_tps - min_tps);
eprintln!(" Avg TPS: {}", avg_tps);
eprintln!(" Std dev: {}", std_dev.unwrap());
}
fn mean(data: &[u64]) -> Option<f64> {
let sum = data.iter().sum::<u64>() as f64;
let count = data.len();
match count {
positive if positive > 0 => Some(sum / count as f64),
_ => None,
}
}
// https://rust-lang-nursery.github.io/rust-cookbook/science/mathematics/statistics.html
fn std_deviation(data: &[u64]) -> Option<f64> {
match (mean(data), data.len()) {
(Some(data_mean), count) if count > 0 => {
let variance = data.iter().map(|value| {
let diff = data_mean - (*value as f64);
diff * diff
}).sum::<f64>() / count as f64;
Some(variance.sqrt())
}
_ => None
}
}
N_THREAD: 12
Min TPS: 3748208824
Max TPS: 3754740006
Max - Min: 6531182
Avg TPS: 3751327835
Std dev: 2131743.207178706
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example