Skip to main content

streaming_crypto/core_api/benchmarks/
bench_utils.rs

1
2use chrono::{Utc};
3use rand::Rng; // bring the Rng trait into scope
4use rand::RngCore;
5use std::fs::File;
6use std::io::BufWriter;
7use std::io::{Write};
8use std::io::{Read};
9use std::path::Path;
10use std::path::PathBuf;
11use sysinfo::{System, ProcessesToUpdate}; // only these are needed
12use async_stream::stream;
13use futures::Stream;
14
15use crate::stream_v2::core::MasterKey;
16
17pub fn dummy_master_key() -> MasterKey {
18    MasterKey::new(vec![0x11u8; 32]) // valid 32-byte key
19}
20
21/// Timestamp in ISO8601 UTC
22pub fn get_timestamp() -> String {
23    Utc::now().to_rfc3339()
24}
25
26/// Random bytes
27pub fn random_bytes(n: usize) -> Vec<u8> {
28    let mut buf = vec![0u8; n];
29    rand::thread_rng().fill_bytes(&mut buf);
30    buf
31}
32
33/// Measure memory usage of current process in MB
34
35pub fn measure_memory_mb() -> f64 {
36    let mut sys = System::new_all();
37
38    // Refresh all processes
39    sys.refresh_processes(ProcessesToUpdate::All, true);
40
41    if let Ok(pid) = sysinfo::get_current_pid() {
42        if let Some(proc) = sys.process(pid) {
43            // proc.memory() returns kilobytes
44            return proc.memory() as f64 / 1024.0; // KB → MB
45        }
46    }
47    0.0
48}
49
50
51/// Measure CPU percent over a duration
52
53pub fn measure_cpu_percent(duration_sec: f64) -> f64 {
54    let mut sys = System::new();
55    sys.refresh_cpu_usage();
56
57    // Warm-up sample
58    let _ = sys.global_cpu_usage();
59
60    // Sleep for the requested duration
61    std::thread::sleep(std::time::Duration::from_secs_f64(duration_sec));
62
63    // Refresh and measure again
64    sys.refresh_cpu_usage();
65    sys.global_cpu_usage() as f64
66}
67
68
69
70/// Sync random chunk source
71pub fn random_chunk_source(total_bytes: usize, max_chunk: usize) -> impl Iterator<Item = Vec<u8>> {
72    let mut remaining = total_bytes;
73    std::iter::from_fn(move || {
74        if remaining == 0 {
75            None
76        } else {
77            let n = remaining.min(max_chunk);
78            remaining -= n;
79            Some(random_bytes(n))
80        }
81    })
82}
83
84/// Async random chunk source
85pub fn random_chunk_source_async(total_bytes: usize, max_chunk: usize) -> impl Stream<Item = Vec<u8>> {
86    stream! {
87        let mut remaining = total_bytes;
88        while remaining > 0 {
89            let n = remaining.min(max_chunk);
90            remaining -= n;
91            yield random_bytes(n);
92        }
93    }
94}
95
96/// Fragmented source
97
98pub fn fragmented_source(data: &[u8], min_frag: usize, max_frag: usize) -> impl Iterator<Item = Vec<u8>> + '_ {
99    let mut pos = 0;
100    std::iter::from_fn(move || {
101        if pos >= data.len() {
102            None
103        } else {
104            // gen_range is from the Rng trait
105            let frag = rand::thread_rng().gen_range(min_frag..=max_frag);
106            let end = (pos + frag).min(data.len());
107            let chunk = data[pos..end].to_vec();
108            pos = end;
109            Some(chunk)
110        }
111    })
112}
113
114
115/// Async fragmented source
116pub fn fragmented_source_async<'a>(data: &'a [u8], min_frag: usize, max_frag: usize) -> impl Stream<Item = Vec<u8>> + 'a {
117    stream! {
118        let mut pos = 0;
119        while pos < data.len() {
120            let frag = rand::thread_rng().gen_range(min_frag..=max_frag);
121            let end = (pos + frag).min(data.len());
122            let chunk = data[pos..end].to_vec();
123            pos = end;
124            yield chunk;
125        }
126    }
127}
128
129/// Sync file reader
130pub fn sync_file_reader(path: &Path, chunk_size: usize) -> impl Iterator<Item = Vec<u8>> {
131    let mut file = File::open(path).expect("file not found");
132    std::iter::from_fn(move || {
133        let mut buf = vec![0u8; chunk_size];
134        match file.read(&mut buf) {
135            Ok(0) => None,
136            Ok(n) => Some(buf[..n].to_vec()),
137            Err(_) => None,
138        }
139    })
140}
141
142/// Async file reader
143
144// pub fn async_file_reader(path: PathBuf, chunk_size: usize) -> impl Stream<Item = Vec<u8>> {
145//     stream! {
146//         let mut file = AsyncFile::open(path).await.expect("file not found");
147//         loop {
148//             let mut buf = vec![0u8; chunk_size];
149//             match file.read(&mut buf).await {
150//                 Ok(0) => break, // EOF
151//                 Ok(n) => yield buf[..n].to_vec(),
152//                 Err(_) => break,
153//             }
154//         }
155//     }
156// }
157
158/// Safe cleanup sync
159pub fn safe_cleanup_sync<T: ?Sized>(obj: &T)
160where
161    T: Cleanup,
162{
163    obj.cleanup();
164}
165
166/// Safe cleanup async
167pub async fn safe_cleanup_async<T: ?Sized>(obj: &T)
168where
169    T: AsyncCleanup,
170{
171    obj.cleanup().await;
172}
173
174/// Trait for cleanup
175pub trait Cleanup {
176    fn cleanup(&self);
177}
178
179/// Trait for async cleanup
180#[async_trait::async_trait]
181pub trait AsyncCleanup {
182    async fn cleanup(&self);
183}
184
185/// Safe remove
186pub fn safe_remove(path: &Path) {
187    let _ = std::fs::remove_file(path);
188}
189
190// helper: create plain.dat of given size 
191pub fn create_plain_file(path: &str, size_bytes: usize) { 
192    let file = File::create(path).expect("Unable to create file"); 
193    let mut writer = BufWriter::new(file); 
194    let data = random_bytes(1024); // 1 KB buffer 
195    let mut written = 0; 
196    
197    while written < size_bytes { 
198        let remaining = size_bytes - written; 
199        let chunk = if remaining < data.len() { 
200            &data[..remaining] 
201        } 
202        else { 
203            &data 
204        }; 
205        writer.write_all(chunk).expect("Write failed"); 
206        written += chunk.len(); 
207    } 
208    writer.flush().expect("Flush failed");
209}
210
211pub fn cleanup_file(path: Option<PathBuf>) {
212    if let Some(p) = path {
213        if p.exists() {
214            if let Err(e) = std::fs::remove_file(&p) {
215                eprintln!("Failed to delete temp file {:?}: {}", p, e);
216            }
217        }
218    }
219}
220
221// ### 🧩 Key Notes
222// - `async-stream` crate is used to yield values asynchronously.
223// - `sysinfo` provides CPU and memory info; CPU usage is sampled before and after a sleep.
224// - Traits `Cleanup` and `AsyncCleanup` mimic Python’s `cleanup` method detection.
225// - `safe_remove` ignores missing files.