Start profiler UI/thread
This commit is contained in:
		
							parent
							
								
									38b34c9cf9
								
							
						
					
					
						commit
						3bfdcc9366
					
				
							
								
								
									
										17
									
								
								src/app.rs
								
								
								
								
							
							
						
						
									
										17
									
								
								src/app.rs
								
								
								
								
							| 
						 | 
				
			
			@ -24,8 +24,8 @@ use crate::{
 | 
			
		|||
    persistence::Persistence,
 | 
			
		||||
    window::{
 | 
			
		||||
        AboutWindow, AppWindow, BgMapWindow, CharacterDataWindow, FrameBufferWindow, GameWindow,
 | 
			
		||||
        GdbServerWindow, HotkeysWindow, InputWindow, ObjectWindow, RegisterWindow, TerminalWindow,
 | 
			
		||||
        WorldWindow,
 | 
			
		||||
        GdbServerWindow, HotkeysWindow, InputWindow, ObjectWindow, ProfileWindow, RegisterWindow,
 | 
			
		||||
        TerminalWindow, WorldWindow,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +54,7 @@ pub struct Application {
 | 
			
		|||
    viewports: HashMap<ViewportId, Viewport>,
 | 
			
		||||
    focused: Option<ViewportId>,
 | 
			
		||||
    init_debug_port: Option<u16>,
 | 
			
		||||
    init_profiling: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Application {
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +62,7 @@ impl Application {
 | 
			
		|||
        client: EmulatorClient,
 | 
			
		||||
        proxy: EventLoopProxy<UserEvent>,
 | 
			
		||||
        debug_port: Option<u16>,
 | 
			
		||||
        profiling: bool,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let wgpu = WgpuState::new();
 | 
			
		||||
        let icon = load_icon().ok().map(Arc::new);
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +91,7 @@ impl Application {
 | 
			
		|||
            viewports: HashMap::new(),
 | 
			
		||||
            focused: None,
 | 
			
		||||
            init_debug_port: debug_port,
 | 
			
		||||
            init_profiling: profiling,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +116,11 @@ impl ApplicationHandler<UserEvent> for Application {
 | 
			
		|||
            server.launch(port);
 | 
			
		||||
            self.open(event_loop, Box::new(server));
 | 
			
		||||
        }
 | 
			
		||||
        if self.init_profiling {
 | 
			
		||||
            let mut profiler = ProfileWindow::new(SimId::Player1, self.client.clone());
 | 
			
		||||
            profiler.launch();
 | 
			
		||||
            self.open(event_loop, Box::new(profiler));
 | 
			
		||||
        }
 | 
			
		||||
        let app = GameWindow::new(
 | 
			
		||||
            self.client.clone(),
 | 
			
		||||
            self.proxy.clone(),
 | 
			
		||||
| 
						 | 
				
			
			@ -247,6 +255,10 @@ impl ApplicationHandler<UserEvent> for Application {
 | 
			
		|||
                let terminal = TerminalWindow::new(sim_id, &self.client);
 | 
			
		||||
                self.open(event_loop, Box::new(terminal));
 | 
			
		||||
            }
 | 
			
		||||
            UserEvent::OpenProfiler(sim_id) => {
 | 
			
		||||
                let profile = ProfileWindow::new(sim_id, self.client.clone());
 | 
			
		||||
                self.open(event_loop, Box::new(profile));
 | 
			
		||||
            }
 | 
			
		||||
            UserEvent::OpenDebugger(sim_id) => {
 | 
			
		||||
                let debugger =
 | 
			
		||||
                    GdbServerWindow::new(sim_id, self.client.clone(), self.proxy.clone());
 | 
			
		||||
| 
						 | 
				
			
			@ -521,6 +533,7 @@ pub enum UserEvent {
 | 
			
		|||
    OpenFrameBuffers(SimId),
 | 
			
		||||
    OpenRegisters(SimId),
 | 
			
		||||
    OpenTerminal(SimId),
 | 
			
		||||
    OpenProfiler(SimId),
 | 
			
		||||
    OpenDebugger(SimId),
 | 
			
		||||
    OpenInput,
 | 
			
		||||
    OpenHotkeys,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ use tracing::{error, warn};
 | 
			
		|||
 | 
			
		||||
use crate::{
 | 
			
		||||
    audio::Audio,
 | 
			
		||||
    emulator::{cart::Cart, profiler::Profiler},
 | 
			
		||||
    emulator::{cart::Cart, shrooms_vb_core::SimEvent},
 | 
			
		||||
    graphics::TextureSink,
 | 
			
		||||
    memory::{MemoryRange, MemoryRegion},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,6 @@ pub use shrooms_vb_core::{VBKey, VBRegister, VBWatchpointType};
 | 
			
		|||
 | 
			
		||||
mod address_set;
 | 
			
		||||
mod cart;
 | 
			
		||||
mod profiler;
 | 
			
		||||
mod shrooms_vb_core;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +69,6 @@ pub struct EmulatorBuilder {
 | 
			
		|||
    audio_on: Arc<[AtomicBool; 2]>,
 | 
			
		||||
    linked: Arc<AtomicBool>,
 | 
			
		||||
    start_paused: bool,
 | 
			
		||||
    monitor_events: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EmulatorBuilder {
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +85,6 @@ impl EmulatorBuilder {
 | 
			
		|||
            audio_on: Arc::new([AtomicBool::new(true), AtomicBool::new(true)]),
 | 
			
		||||
            linked: Arc::new(AtomicBool::new(false)),
 | 
			
		||||
            start_paused: false,
 | 
			
		||||
            monitor_events: false,
 | 
			
		||||
        };
 | 
			
		||||
        let client = EmulatorClient {
 | 
			
		||||
            queue,
 | 
			
		||||
| 
						 | 
				
			
			@ -113,13 +110,6 @@ impl EmulatorBuilder {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn monitor_events(self, monitor_events: bool) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            monitor_events,
 | 
			
		||||
            ..self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn build(self) -> Result<Emulator> {
 | 
			
		||||
        let mut emulator = Emulator::new(
 | 
			
		||||
            self.commands,
 | 
			
		||||
| 
						 | 
				
			
			@ -134,9 +124,6 @@ impl EmulatorBuilder {
 | 
			
		|||
        if self.start_paused {
 | 
			
		||||
            emulator.pause_sims()?;
 | 
			
		||||
        }
 | 
			
		||||
        if self.monitor_events {
 | 
			
		||||
            emulator.monitor_events(SimId::Player1)?;
 | 
			
		||||
        }
 | 
			
		||||
        Ok(emulator)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +137,7 @@ pub struct Emulator {
 | 
			
		|||
    state: Arc<Atomic<EmulatorState>>,
 | 
			
		||||
    audio_on: Arc<[AtomicBool; 2]>,
 | 
			
		||||
    linked: Arc<AtomicBool>,
 | 
			
		||||
    profilers: [Profiler; 2],
 | 
			
		||||
    profilers: [Option<ProfileSender>; 2],
 | 
			
		||||
    renderers: HashMap<SimId, TextureSink>,
 | 
			
		||||
    messages: HashMap<SimId, mpsc::Sender<Toast>>,
 | 
			
		||||
    debuggers: HashMap<SimId, DebugInfo>,
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +165,7 @@ impl Emulator {
 | 
			
		|||
            state,
 | 
			
		||||
            audio_on,
 | 
			
		||||
            linked,
 | 
			
		||||
            profilers: [Profiler::new(), Profiler::new()],
 | 
			
		||||
            profilers: [None, None],
 | 
			
		||||
            renderers: HashMap::new(),
 | 
			
		||||
            messages: HashMap::new(),
 | 
			
		||||
            debuggers: HashMap::new(),
 | 
			
		||||
| 
						 | 
				
			
			@ -228,12 +215,29 @@ impl Emulator {
 | 
			
		|||
        }
 | 
			
		||||
        let sim = &mut self.sims[index];
 | 
			
		||||
        sim.reset();
 | 
			
		||||
        sim.monitor_events(self.profilers[sim_id.to_index()].is_enabled());
 | 
			
		||||
        if let Some(cart) = new_cart {
 | 
			
		||||
            sim.load_cart(cart.rom.clone(), cart.sram.clone())?;
 | 
			
		||||
            self.carts[index] = Some(cart);
 | 
			
		||||
            self.sim_state[index].store(SimState::Ready, Ordering::Release);
 | 
			
		||||
        }
 | 
			
		||||
        let mut profiling = false;
 | 
			
		||||
        if let Some(profiler) = self.profilers[sim_id.to_index()].as_ref() {
 | 
			
		||||
            if let Some(cart) = self.carts[index].as_ref() {
 | 
			
		||||
                if profiler
 | 
			
		||||
                    .send(ProfileEvent::Start {
 | 
			
		||||
                        file_path: cart.file_path.clone(),
 | 
			
		||||
                    })
 | 
			
		||||
                    .is_ok()
 | 
			
		||||
                {
 | 
			
		||||
                    sim.monitor_events(true);
 | 
			
		||||
                    profiling = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if !profiling {
 | 
			
		||||
            sim.monitor_events(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if self.sim_state[index].load(Ordering::Acquire) == SimState::Ready {
 | 
			
		||||
            self.resume_sims();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -331,6 +335,11 @@ impl Emulator {
 | 
			
		|||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start_profiling(&mut self, sim_id: SimId, sender: ProfileSender) -> Result<()> {
 | 
			
		||||
        self.profilers[sim_id.to_index()] = Some(sender);
 | 
			
		||||
        self.reset_sim(sim_id, None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start_debugging(&mut self, sim_id: SimId, sender: DebugSender) {
 | 
			
		||||
        if self.sim_state[sim_id.to_index()].load(Ordering::Acquire) != SimState::Ready {
 | 
			
		||||
            // Can't debug unless a game is connected
 | 
			
		||||
| 
						 | 
				
			
			@ -399,11 +408,6 @@ impl Emulator {
 | 
			
		|||
        self.watched_regions.insert(range, region);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn monitor_events(&mut self, sim_id: SimId) -> Result<()> {
 | 
			
		||||
        self.profilers[sim_id.to_index()].enable(true);
 | 
			
		||||
        self.reset_sim(sim_id, None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn run(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let idle = self.tick();
 | 
			
		||||
| 
						 | 
				
			
			@ -469,10 +473,20 @@ impl Emulator {
 | 
			
		|||
            .zip(self.profilers.iter_mut())
 | 
			
		||||
            .zip([p1_running, p2_running])
 | 
			
		||||
        {
 | 
			
		||||
            if !running || !profiler.is_enabled() {
 | 
			
		||||
            if !running {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            profiler.track(cycles, sim.take_sim_event());
 | 
			
		||||
            if let Some(p) = profiler {
 | 
			
		||||
                if p.send(ProfileEvent::Update {
 | 
			
		||||
                    cycles,
 | 
			
		||||
                    event: sim.take_sim_event(),
 | 
			
		||||
                })
 | 
			
		||||
                .is_err()
 | 
			
		||||
                {
 | 
			
		||||
                    sim.monitor_events(false);
 | 
			
		||||
                    *profiler = None;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if state == EmulatorState::Stepping {
 | 
			
		||||
| 
						 | 
				
			
			@ -614,6 +628,11 @@ impl Emulator {
 | 
			
		|||
                    self.report_error(SimId::Player1, format!("Error setting speed: {error}"));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            EmulatorCommand::StartProfiling(sim_id, profiler) => {
 | 
			
		||||
                if let Err(error) = self.start_profiling(sim_id, profiler) {
 | 
			
		||||
                    self.report_error(SimId::Player1, format!("Error enaling profiler: {error}"));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            EmulatorCommand::StartDebugging(sim_id, debugger) => {
 | 
			
		||||
                self.start_debugging(sim_id, debugger);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -751,6 +770,7 @@ pub enum EmulatorCommand {
 | 
			
		|||
    Resume,
 | 
			
		||||
    FrameAdvance,
 | 
			
		||||
    SetSpeed(f64),
 | 
			
		||||
    StartProfiling(SimId, ProfileSender),
 | 
			
		||||
    StartDebugging(SimId, DebugSender),
 | 
			
		||||
    StopDebugging(SimId),
 | 
			
		||||
    DebugInterrupt(SimId),
 | 
			
		||||
| 
						 | 
				
			
			@ -792,6 +812,7 @@ pub enum EmulatorState {
 | 
			
		|||
    Debugging,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProfileSender = tokio::sync::mpsc::UnboundedSender<ProfileEvent>;
 | 
			
		||||
type DebugSender = tokio::sync::mpsc::UnboundedSender<DebugEvent>;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 | 
			
		||||
| 
						 | 
				
			
			@ -815,6 +836,16 @@ pub enum DebugEvent {
 | 
			
		|||
    Stopped(DebugStopReason),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum ProfileEvent {
 | 
			
		||||
    Start {
 | 
			
		||||
        file_path: PathBuf,
 | 
			
		||||
    },
 | 
			
		||||
    Update {
 | 
			
		||||
        cycles: u32,
 | 
			
		||||
        event: Option<SimEvent>,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct EmulatorClient {
 | 
			
		||||
    queue: mpsc::Sender<EmulatorCommand>,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
use crate::emulator::shrooms_vb_core::SimEvent;
 | 
			
		||||
 | 
			
		||||
pub struct Profiler {
 | 
			
		||||
    enabled: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Profiler {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self { enabled: false }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn enable(&mut self, enabled: bool) {
 | 
			
		||||
        self.enabled = enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn is_enabled(&self) -> bool {
 | 
			
		||||
        self.enabled
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn track(&mut self, cycles: u32, event: Option<SimEvent>) {
 | 
			
		||||
        println!("profiler {cycles} {event:0x?}");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										13
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
				
			
			@ -22,6 +22,7 @@ mod images;
 | 
			
		|||
mod input;
 | 
			
		||||
mod memory;
 | 
			
		||||
mod persistence;
 | 
			
		||||
mod profiler;
 | 
			
		||||
mod window;
 | 
			
		||||
 | 
			
		||||
#[derive(Parser)]
 | 
			
		||||
| 
						 | 
				
			
			@ -110,10 +111,7 @@ fn main() -> Result<()> {
 | 
			
		|||
        builder = builder.start_paused(true);
 | 
			
		||||
    }
 | 
			
		||||
    if args.profile {
 | 
			
		||||
        if args.rom.is_none() {
 | 
			
		||||
            bail!("to start profiling, please select a game.");
 | 
			
		||||
        }
 | 
			
		||||
        builder = builder.monitor_events(true)
 | 
			
		||||
        builder = builder.start_paused(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ThreadBuilder::default()
 | 
			
		||||
| 
						 | 
				
			
			@ -133,6 +131,11 @@ fn main() -> Result<()> {
 | 
			
		|||
    let event_loop = EventLoop::with_user_event().build().unwrap();
 | 
			
		||||
    event_loop.set_control_flow(ControlFlow::Poll);
 | 
			
		||||
    let proxy = event_loop.create_proxy();
 | 
			
		||||
    event_loop.run_app(&mut Application::new(client, proxy, args.debug_port))?;
 | 
			
		||||
    event_loop.run_app(&mut Application::new(
 | 
			
		||||
        client,
 | 
			
		||||
        proxy,
 | 
			
		||||
        args.debug_port,
 | 
			
		||||
        args.profile,
 | 
			
		||||
    ))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ pub use game::GameWindow;
 | 
			
		|||
pub use gdb::GdbServerWindow;
 | 
			
		||||
pub use hotkeys::HotkeysWindow;
 | 
			
		||||
pub use input::InputWindow;
 | 
			
		||||
pub use profile::ProfileWindow;
 | 
			
		||||
pub use terminal::TerminalWindow;
 | 
			
		||||
pub use vip::{
 | 
			
		||||
    BgMapWindow, CharacterDataWindow, FrameBufferWindow, ObjectWindow, RegisterWindow, WorldWindow,
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,7 @@ mod game_screen;
 | 
			
		|||
mod gdb;
 | 
			
		||||
mod hotkeys;
 | 
			
		||||
mod input;
 | 
			
		||||
mod profile;
 | 
			
		||||
mod terminal;
 | 
			
		||||
mod utils;
 | 
			
		||||
mod vip;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,6 +228,11 @@ impl GameWindow {
 | 
			
		|||
                    .send_event(UserEvent::OpenTerminal(self.sim_id))
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
            }
 | 
			
		||||
            if ui.button("Profiler").clicked() {
 | 
			
		||||
                self.proxy
 | 
			
		||||
                    .send_event(UserEvent::OpenProfiler(self.sim_id))
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
            }
 | 
			
		||||
            if ui.button("GDB Server").clicked() {
 | 
			
		||||
                self.proxy
 | 
			
		||||
                    .send_event(UserEvent::OpenDebugger(self.sim_id))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
use egui::{CentralPanel, ViewportBuilder, ViewportId};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    emulator::{EmulatorClient, SimId},
 | 
			
		||||
    profiler::Profiler,
 | 
			
		||||
    window::AppWindow,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct ProfileWindow {
 | 
			
		||||
    sim_id: SimId,
 | 
			
		||||
    profiler: Profiler,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ProfileWindow {
 | 
			
		||||
    pub fn new(sim_id: SimId, client: EmulatorClient) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            sim_id,
 | 
			
		||||
            profiler: Profiler::new(sim_id, client),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn launch(&mut self) {
 | 
			
		||||
        self.profiler.start();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppWindow for ProfileWindow {
 | 
			
		||||
    fn viewport_id(&self) -> ViewportId {
 | 
			
		||||
        ViewportId::from_hash_of(format!("Profile-{}", self.sim_id))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn sim_id(&self) -> SimId {
 | 
			
		||||
        self.sim_id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn initial_viewport(&self) -> ViewportBuilder {
 | 
			
		||||
        ViewportBuilder::default()
 | 
			
		||||
            .with_title(format!("Profiler ({})", self.sim_id))
 | 
			
		||||
            .with_inner_size((300.0, 200.0))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn show(&mut self, ctx: &egui::Context) {
 | 
			
		||||
        CentralPanel::default().show(ctx, |ui| {
 | 
			
		||||
            let mut started = self.profiler.started();
 | 
			
		||||
            if ui.checkbox(&mut started, "Profiling enabled?").changed() {
 | 
			
		||||
                if started {
 | 
			
		||||
                    self.profiler.start();
 | 
			
		||||
                } else {
 | 
			
		||||
                    self.profiler.stop();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue