1#![forbid(unsafe_code)]
2
3use std::{
4 fmt::Display,
5 ops::{Add, AddAssign},
6 sync::atomic::{AtomicBool, AtomicU64, Ordering},
7 time::Duration,
8};
9
10use serde::Serialize;
11
12mod env;
13mod metrics;
14mod result;
15mod runner;
16pub use result::ShumaiResult;
17pub use runner::run;
18pub use shumai_config_impl::{config, ShumaiConfig};
19
20pub mod __dep {
21 pub use colored;
22 pub use regex;
23 pub use serde;
24 pub use serde_json;
25 pub use toml;
26}
27
28pub struct Context<'a, C: BenchConfig> {
30 running: &'a AtomicBool,
31 ready_thread: &'a AtomicU64,
32 pub thread_id: usize,
33 pub thread_cnt: usize,
34 pub config: &'a C,
35}
36
37impl<'a, C: BenchConfig> Context<'a, C> {
38 pub fn wait_for_start(&self) {
41 self.ready_thread.fetch_add(1, Ordering::Relaxed);
42 while !self.is_running() {
43 std::hint::spin_loop();
44 }
45 }
46
47 pub fn is_running(&self) -> bool {
49 self.running.load(Ordering::Relaxed)
50 }
51
52 pub(crate) fn new(
53 thread_id: usize,
54 thread_cnt: usize,
55 config: &'a C,
56 ready_thread: &'a AtomicU64,
57 running: &'a AtomicBool,
58 ) -> Self {
59 Context {
60 running,
61 ready_thread,
62 thread_id,
63 thread_cnt,
64 config,
65 }
66 }
67}
68
69pub trait BenchResult:
70 serde::Serialize + Default + AddAssign + Add<Output = Self> + Clone + Send + Sync + Display
71{
72 fn short_value(&self) -> usize;
73
74 #[must_use]
75 fn normalize_time(self, dur: &Duration) -> Self;
76}
77
78impl BenchResult for usize {
79 fn short_value(&self) -> usize {
80 *self
81 }
82
83 fn normalize_time(self, dur: &Duration) -> usize {
84 ((self as f64) / dur.as_secs_f64()) as usize
85 }
86}
87
88pub trait BenchConfig: Clone + Serialize + Send + Sync {
89 fn name(&self) -> &String;
90 fn thread(&self) -> &[usize];
91 fn bench_sec(&self) -> usize;
92}
93
94pub trait ShumaiBench: Send + Sync {
97 type Result: BenchResult;
98 type Config: BenchConfig;
99
100 fn load(&mut self) -> Option<serde_json::Value>;
103
104 fn run(&self, context: Context<Self::Config>) -> Self::Result;
108
109 fn on_iteration_finished(&mut self, _cur_iter: usize) -> Option<serde_json::Value> {
110 None
111 }
112
113 fn on_thread_finished(&mut self, _cur_thread: usize) -> Option<serde_json::Value> {
114 None
115 }
116
117 fn cleanup(&mut self) -> Option<serde_json::Value>;
119}