implements PLN-0032
This commit is contained in:
parent
52785b5a8c
commit
33dd6d008b
@ -2,6 +2,7 @@ use prometeu_drivers::hardware::Hardware;
|
||||
use prometeu_firmware::{BootTarget, Firmware};
|
||||
use prometeu_hal::cartridge_loader::CartridgeLoader;
|
||||
use prometeu_hal::debugger_protocol::*;
|
||||
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
|
||||
use prometeu_system::CrashReport;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
@ -12,6 +13,8 @@ use std::net::{TcpListener, TcpStream};
|
||||
/// Prometeu Debugger) to observe and control the execution of the virtual machine.
|
||||
///
|
||||
/// Communication is based on JSONL (JSON lines) over TCP.
|
||||
/// Detailed inspection and certification events are synthesized in the host
|
||||
/// from telemetry snapshots and host/runtime integration state.
|
||||
pub struct HostDebugger {
|
||||
/// If true, the VM will not start execution until a 'start' command is received.
|
||||
pub waiting_for_start: bool,
|
||||
@ -230,6 +233,70 @@ impl HostDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cert_event_from_snapshot(
|
||||
tag: u16,
|
||||
telemetry: TelemetryFrame,
|
||||
cert_config: &CertificationConfig,
|
||||
frame_index: u64,
|
||||
) -> Option<DebugEvent> {
|
||||
let (rule, used, limit) = match tag {
|
||||
0xCA01 => (
|
||||
"cycles_budget".to_string(),
|
||||
telemetry.cycles_used,
|
||||
cert_config.cycles_budget_per_frame.unwrap_or(0),
|
||||
),
|
||||
0xCA02 => (
|
||||
"max_syscalls".to_string(),
|
||||
telemetry.syscalls as u64,
|
||||
cert_config.max_syscalls_per_frame.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA03 => (
|
||||
"max_host_cpu_us".to_string(),
|
||||
telemetry.host_cpu_time_us,
|
||||
cert_config.max_host_cpu_us_per_frame.unwrap_or(0),
|
||||
),
|
||||
0xCA04 => (
|
||||
"max_glyph_slots_used".to_string(),
|
||||
telemetry.glyph_slots_used as u64,
|
||||
cert_config.max_glyph_slots_used.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA05 => (
|
||||
"max_sound_slots_used".to_string(),
|
||||
telemetry.sound_slots_used as u64,
|
||||
cert_config.max_sound_slots_used.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA06 => (
|
||||
"max_heap_bytes".to_string(),
|
||||
telemetry.heap_used_bytes as u64,
|
||||
cert_config.max_heap_bytes.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA07 => (
|
||||
"max_logs_per_frame".to_string(),
|
||||
telemetry.logs_count as u64,
|
||||
cert_config.max_logs_per_frame.unwrap_or(0) as u64,
|
||||
),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(DebugEvent::Cert { rule, used, limit, frame_index })
|
||||
}
|
||||
|
||||
pub(crate) fn telemetry_event_from_snapshot(telemetry: TelemetryFrame) -> DebugEvent {
|
||||
DebugEvent::Telemetry {
|
||||
frame_index: telemetry.frame_index,
|
||||
vm_steps: telemetry.vm_steps,
|
||||
syscalls: telemetry.syscalls,
|
||||
cycles: telemetry.cycles_used,
|
||||
cycles_budget: telemetry.cycles_budget,
|
||||
host_cpu_time_us: telemetry.host_cpu_time_us,
|
||||
violations: telemetry.violations,
|
||||
glyph_slots_used: telemetry.glyph_slots_used,
|
||||
glyph_slots_total: telemetry.glyph_slots_total,
|
||||
sound_slots_used: telemetry.sound_slots_used,
|
||||
sound_slots_total: telemetry.sound_slots_total,
|
||||
}
|
||||
}
|
||||
|
||||
/// Scans the system for new information to push to the debugger client.
|
||||
fn stream_events(&mut self, firmware: &mut Firmware) {
|
||||
if let Some(report) = firmware.os.last_crash_report.as_ref() {
|
||||
@ -251,46 +318,15 @@ impl HostDebugger {
|
||||
});
|
||||
}
|
||||
|
||||
// Map Certification tags (0xCA01-0xCA03) to 'Cert' protocol events.
|
||||
if event.tag >= 0xCA01 && event.tag <= 0xCA03 {
|
||||
let tel = firmware.os.atomic_telemetry.snapshot();
|
||||
let cert_config = &firmware.os.certifier.config;
|
||||
|
||||
let (rule, used, limit) = match event.tag {
|
||||
0xCA01 => (
|
||||
"cycles_budget".to_string(),
|
||||
tel.cycles_used,
|
||||
cert_config.cycles_budget_per_frame.unwrap_or(0),
|
||||
),
|
||||
0xCA02 => (
|
||||
"max_syscalls".to_string(),
|
||||
tel.syscalls as u64,
|
||||
cert_config.max_syscalls_per_frame.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA03 => (
|
||||
"max_host_cpu_us".to_string(),
|
||||
tel.host_cpu_time_us,
|
||||
cert_config.max_host_cpu_us_per_frame.unwrap_or(0),
|
||||
),
|
||||
0xCA04 => (
|
||||
"max_glyph_slots_used".to_string(),
|
||||
tel.glyph_slots_used as u64,
|
||||
cert_config.max_glyph_slots_used.unwrap_or(0) as u64,
|
||||
),
|
||||
0xCA05 => (
|
||||
"max_sound_slots_used".to_string(),
|
||||
tel.sound_slots_used as u64,
|
||||
cert_config.max_sound_slots_used.unwrap_or(0) as u64,
|
||||
),
|
||||
_ => ("unknown".to_string(), 0, 0),
|
||||
};
|
||||
|
||||
self.send_event(DebugEvent::Cert {
|
||||
rule,
|
||||
used,
|
||||
limit,
|
||||
frame_index: firmware.os.logical_frame_index,
|
||||
});
|
||||
if (0xCA01..=0xCA07).contains(&event.tag)
|
||||
&& let Some(cert_event) = Self::cert_event_from_snapshot(
|
||||
event.tag,
|
||||
firmware.os.atomic_telemetry.snapshot(),
|
||||
&firmware.os.certifier.config,
|
||||
firmware.os.logical_frame_index,
|
||||
)
|
||||
{
|
||||
self.send_event(cert_event);
|
||||
}
|
||||
|
||||
self.send_event(DebugEvent::Log {
|
||||
@ -304,19 +340,7 @@ impl HostDebugger {
|
||||
let current_frame = firmware.os.logical_frame_index;
|
||||
if current_frame > self.last_telemetry_frame {
|
||||
let tel = firmware.os.atomic_telemetry.snapshot();
|
||||
self.send_event(DebugEvent::Telemetry {
|
||||
frame_index: tel.frame_index,
|
||||
vm_steps: tel.vm_steps,
|
||||
syscalls: tel.syscalls,
|
||||
cycles: tel.cycles_used,
|
||||
cycles_budget: tel.cycles_budget,
|
||||
host_cpu_time_us: tel.host_cpu_time_us,
|
||||
violations: tel.violations,
|
||||
glyph_slots_used: tel.glyph_slots_used,
|
||||
glyph_slots_total: tel.glyph_slots_total,
|
||||
sound_slots_used: tel.sound_slots_used,
|
||||
sound_slots_total: tel.sound_slots_total,
|
||||
});
|
||||
self.send_event(Self::telemetry_event_from_snapshot(tel));
|
||||
self.last_telemetry_frame = current_frame;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +58,8 @@ pub struct HostRunner {
|
||||
|
||||
/// Performance metrics collector.
|
||||
stats: HostStats,
|
||||
/// Remote debugger interface.
|
||||
/// Remote debugger interface. It consumes host-owned telemetry and runtime state
|
||||
/// directly instead of depending on guest-visible inspection syscalls.
|
||||
debugger: HostDebugger,
|
||||
|
||||
/// Flag to enable/disable the technical telemetry display.
|
||||
@ -225,7 +226,8 @@ impl ApplicationHandler for HostRunner {
|
||||
// 1. Process pending debug commands from the network.
|
||||
self.debugger.check_commands(&mut self.firmware, &mut self.hardware);
|
||||
|
||||
// Sync inspection mode state.
|
||||
// Sync inspection mode state. This is host-owned overlay/debugger control,
|
||||
// not a guest-visible debug ABI switch.
|
||||
self.firmware.os.inspection_active = self.overlay_enabled || self.debugger.stream.is_some();
|
||||
|
||||
// 2. Maintain filesystem connection if it was lost (e.g., directory removed).
|
||||
@ -307,9 +309,117 @@ mod tests {
|
||||
use super::*;
|
||||
use prometeu_firmware::BootTarget;
|
||||
use prometeu_hal::debugger_protocol::DEVTOOLS_PROTOCOL_VERSION;
|
||||
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpStream;
|
||||
|
||||
#[test]
|
||||
fn host_debugger_maps_cert_events_from_host_owned_sources() {
|
||||
let telemetry = TelemetryFrame {
|
||||
glyph_slots_used: 3,
|
||||
heap_used_bytes: 4096,
|
||||
logs_count: 7,
|
||||
..Default::default()
|
||||
};
|
||||
let config = CertificationConfig {
|
||||
enabled: true,
|
||||
max_glyph_slots_used: Some(2),
|
||||
max_heap_bytes: Some(2048),
|
||||
max_logs_per_frame: Some(5),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match HostDebugger::cert_event_from_snapshot(0xCA04, telemetry, &config, 12) {
|
||||
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
|
||||
rule,
|
||||
used,
|
||||
limit,
|
||||
frame_index,
|
||||
}) => {
|
||||
assert_eq!(rule, "max_glyph_slots_used");
|
||||
assert_eq!(used, 3);
|
||||
assert_eq!(limit, 2);
|
||||
assert_eq!(frame_index, 12);
|
||||
}
|
||||
other => panic!("unexpected glyph cert event: {:?}", other),
|
||||
}
|
||||
match HostDebugger::cert_event_from_snapshot(0xCA06, telemetry, &config, 12) {
|
||||
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
|
||||
rule,
|
||||
used,
|
||||
limit,
|
||||
frame_index,
|
||||
}) => {
|
||||
assert_eq!(rule, "max_heap_bytes");
|
||||
assert_eq!(used, 4096);
|
||||
assert_eq!(limit, 2048);
|
||||
assert_eq!(frame_index, 12);
|
||||
}
|
||||
other => panic!("unexpected heap cert event: {:?}", other),
|
||||
}
|
||||
match HostDebugger::cert_event_from_snapshot(0xCA07, telemetry, &config, 12) {
|
||||
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
|
||||
rule,
|
||||
used,
|
||||
limit,
|
||||
frame_index,
|
||||
}) => {
|
||||
assert_eq!(rule, "max_logs_per_frame");
|
||||
assert_eq!(used, 7);
|
||||
assert_eq!(limit, 5);
|
||||
assert_eq!(frame_index, 12);
|
||||
}
|
||||
other => panic!("unexpected logs cert event: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_debugger_maps_telemetry_from_atomic_snapshot_fields() {
|
||||
let telemetry = TelemetryFrame {
|
||||
frame_index: 8,
|
||||
vm_steps: 123,
|
||||
syscalls: 9,
|
||||
cycles_used: 456,
|
||||
cycles_budget: 789,
|
||||
host_cpu_time_us: 321,
|
||||
violations: 2,
|
||||
glyph_slots_used: 1,
|
||||
glyph_slots_total: 16,
|
||||
sound_slots_used: 0,
|
||||
sound_slots_total: 8,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match HostDebugger::telemetry_event_from_snapshot(telemetry) {
|
||||
prometeu_hal::debugger_protocol::DebugEvent::Telemetry {
|
||||
frame_index,
|
||||
vm_steps,
|
||||
syscalls,
|
||||
cycles,
|
||||
cycles_budget,
|
||||
host_cpu_time_us,
|
||||
violations,
|
||||
glyph_slots_used,
|
||||
glyph_slots_total,
|
||||
sound_slots_used,
|
||||
sound_slots_total,
|
||||
} => {
|
||||
assert_eq!(frame_index, 8);
|
||||
assert_eq!(vm_steps, 123);
|
||||
assert_eq!(syscalls, 9);
|
||||
assert_eq!(cycles, 456);
|
||||
assert_eq!(cycles_budget, 789);
|
||||
assert_eq!(host_cpu_time_us, 321);
|
||||
assert_eq!(violations, 2);
|
||||
assert_eq!(glyph_slots_used, 1);
|
||||
assert_eq!(glyph_slots_total, 16);
|
||||
assert_eq!(sound_slots_used, 0);
|
||||
assert_eq!(sound_slots_total, 8);
|
||||
}
|
||||
other => panic!("unexpected telemetry event: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires localhost TCP bind/connect; run via `cargo test -p prometeu-host-desktop-winit --lib -- --ignored`"]
|
||||
fn test_debug_port_opens() {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0008","file":"workflow/agendas/AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0009","file":"workflow/agendas/AGD-0009-perf-host-desktop-frame-pacing-and-presentation.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0010","file":"workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0012","status":"review","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0009","file":"workflow/decisions/DEC-0009-host-owned-debug-and-certification.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-19","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0030","file":"workflow/plans/PLN-0030-dec9-spec-boundary-propagation.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0031","file":"workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0032","file":"workflow/plans/PLN-0032-dec9-host-debugger-and-certification-alignment.md","status":"review","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0012","status":"review","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0009","file":"workflow/decisions/DEC-0009-host-owned-debug-and-certification.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-19","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0030","file":"workflow/plans/PLN-0030-dec9-spec-boundary-propagation.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0031","file":"workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0032","file":"workflow/plans/PLN-0032-dec9-host-debugger-and-certification-alignment.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"generic-memory-bank-slot-contract","title":"Agenda - Generic Memory Bank Slot Contract","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["runtime","asset","memory-bank","slots","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"lessons/DSC-0024-generic-memory-bank-slot-contract/LSN-0029-slot-first-bank-telemetry-belongs-in-asset-manager.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"scene-bank-and-viewport-cache-refactor","title":"Scene Bank and Viewport Cache Refactor","created_at":"2026-04-11","updated_at":"2026-04-14","tags":["gfx","tilemap","runtime","render"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0030","file":"lessons/DSC-0025-scene-bank-and-viewport-cache-refactor/LSN-0030-canonical-scene-cache-and-resolver-split.md","status":"done","created_at":"2026-04-14","updated_at":"2026-04-14"}]}
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
id: PLN-0032
|
||||
ticket: perf-runtime-introspection-syscalls
|
||||
title: DEC-0009 Host Debugger and Certification Alignment
|
||||
status: review
|
||||
status: done
|
||||
created: 2026-04-19
|
||||
completed:
|
||||
completed: 2026-04-19
|
||||
tags: [host, debug, certification, telemetry, desktop]
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user