lemur/src/profiler.rs

80 lines
2.2 KiB
Rust

use std::{
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
thread,
};
use tokio::{select, sync::mpsc};
use crate::emulator::{EmulatorClient, EmulatorCommand, ProfileEvent, SimId};
pub struct Profiler {
sim_id: SimId,
client: EmulatorClient,
running: Arc<AtomicBool>,
killer: Option<oneshot::Sender<()>>,
}
impl Profiler {
pub fn new(sim_id: SimId, client: EmulatorClient) -> Self {
Self {
sim_id,
client,
running: Arc::new(AtomicBool::new(false)),
killer: None,
}
}
pub fn started(&self) -> bool {
self.running.load(Ordering::Relaxed)
}
pub fn start(&mut self) {
let sim_id = self.sim_id;
let client = self.client.clone();
let running = self.running.clone();
let (tx, rx) = oneshot::channel();
self.killer = Some(tx);
thread::spawn(move || {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
select! {
_ = run_profile(sim_id, client, running.clone()) => {}
_ = rx => {
running.store(false, Ordering::Relaxed);
}
}
})
});
}
pub fn stop(&mut self) {
if let Some(killer) = self.killer.take() {
let _ = killer.send(());
}
}
}
async fn run_profile(sim_id: SimId, client: EmulatorClient, running: Arc<AtomicBool>) {
let (profile_sync, mut profile_source) = mpsc::unbounded_channel();
client.send_command(EmulatorCommand::StartProfiling(sim_id, profile_sync));
running.store(true, Ordering::Relaxed);
while let Some(event) = profile_source.recv().await {
match event {
ProfileEvent::Start { file_path } => {
println!("profiling {}", file_path.display());
}
ProfileEvent::Update { cycles, event } => {
println!("update {cycles} {event:#x?}");
}
}
}
running.store(false, Ordering::Release);
}