trace/
main.rs

1#![feature(error_reporter)]
2
3use clap::Parser;
4use miette::IntoDiagnostic;
5use monitor_api::{CompartmentLoader, NewCompartmentFlags};
6use tracer::TracingState;
7use tracing::Level;
8use twizzler_abi::{
9    syscall::TraceSpec,
10    trace::{
11        CONTEXT_FAULT, CONTEXT_INVALIDATION, CONTEXT_SHOOTDOWN, THREAD_SAMPLE,
12        THREAD_SYSCALL_ENTRY, TraceFlags, TraceKind,
13    },
14};
15
16pub mod stat;
17pub mod tracer;
18
19#[derive(Debug, Clone, clap::Subcommand)]
20pub enum Subcommand {
21    Stat,
22}
23
24#[derive(clap::Args, Clone, Debug)]
25pub struct RunCli {
26    #[arg(long, short, help = "Sample threads.")]
27    pub sample: bool,
28    #[arg(trailing_var_arg = true, allow_hyphen_values = true, hide = true)]
29    pub cmdline: Vec<String>,
30}
31
32#[derive(clap::Parser, Clone, Debug)]
33pub struct Cli {
34    #[clap(subcommand)]
35    pub cmd: Option<Subcommand>,
36    #[clap(long, short, help = "List of events to traces, one per flag.")]
37    pub events: Vec<String>,
38    #[clap(flatten)]
39    pub prog: RunCli,
40}
41
42fn main() -> miette::Result<()> {
43    tracing::subscriber::set_global_default(
44        tracing_subscriber::fmt()
45            .without_time()
46            .with_max_level(Level::DEBUG)
47            .finish(),
48    )
49    .unwrap();
50
51    let cli = Cli::try_parse().into_diagnostic()?;
52
53    let state = run_trace_program(&cli)?;
54
55    match cli.cmd {
56        None | Some(Subcommand::Stat) => {
57            stat::stat(state);
58        }
59    }
60
61    Ok(())
62}
63
64fn run_trace_program(cli: &Cli) -> miette::Result<TracingState> {
65    let name = &cli.prog.cmdline[0];
66    let compname = format!("trace-{}", name);
67
68    let mut comp = CompartmentLoader::new(&compname, name, NewCompartmentFlags::DEBUG);
69    comp.args(&cli.prog.cmdline);
70    let comp = comp.load().into_diagnostic()?;
71
72    tracing::info!("compartment {} loaded, starting tracing monitor", compname);
73
74    let info = comp.info();
75
76    let mut specs: Vec<_> = cli
77        .events
78        .iter()
79        .map(|event| match event.as_str() {
80            "page-faults" | "pf" | "faults" | "page-fault" => TraceSpec {
81                kind: TraceKind::Context,
82                flags: TraceFlags::empty(),
83                enable_events: CONTEXT_FAULT,
84                disable_events: 0,
85                sctx: Some(info.id),
86                mctx: None,
87                thread: None,
88                cpuid: None,
89                extra: 0.into(),
90            },
91            "tlb" | "tlb-shootdowns" | "tlb-shootdown" | "shootdown" => TraceSpec {
92                kind: TraceKind::Context,
93                flags: TraceFlags::empty(),
94                enable_events: CONTEXT_SHOOTDOWN | CONTEXT_INVALIDATION,
95                disable_events: 0,
96                sctx: Some(info.id),
97                mctx: None,
98                thread: None,
99                cpuid: None,
100                extra: 0.into(),
101            },
102            "sys" | "syscall" | "syscalls" => TraceSpec {
103                kind: TraceKind::Thread,
104                flags: TraceFlags::empty(),
105                enable_events: THREAD_SYSCALL_ENTRY,
106                disable_events: 0,
107                sctx: Some(info.id),
108                mctx: None,
109                thread: None,
110                cpuid: None,
111                extra: 0.into(),
112            },
113            _ => panic!("unknown event type: {}", event),
114        })
115        .collect();
116
117    if cli.prog.sample {
118        specs.push(TraceSpec {
119            kind: TraceKind::Thread,
120            flags: TraceFlags::empty(),
121            enable_events: THREAD_SAMPLE,
122            disable_events: 0,
123            sctx: Some(info.id),
124            mctx: None,
125            thread: None,
126            cpuid: None,
127            extra: 0.into(),
128        })
129    }
130
131    let state = tracer::start(cli, comp, specs)?;
132
133    tracing::info!(
134        "disconnected {}: {} bytes of trace data",
135        compname,
136        state.total
137    );
138
139    tracing::info!("counted {} events", state.data().count());
140
141    Ok(state)
142}