@@ -14,6 +14,8 @@ mod repl;
1414
1515mod docs;
1616mod highlighter;
17+ #[ cfg( feature = "trace" ) ]
18+ mod span_tracer;
1719
1820#[ derive( Parser ) ]
1921#[ command( name = "Andy C++" ) ]
@@ -28,7 +30,25 @@ struct Cli {
2830#[ derive( Subcommand ) ]
2931enum Command {
3032 /// Execute an .ndc file or start the repl (this default action may be omitted)
31- Run { file : Option < PathBuf > } ,
33+ Run {
34+ file : Option < PathBuf > ,
35+ /// Print each instruction as it is dispatched
36+ #[ cfg( feature = "trace" ) ]
37+ #[ arg( long) ]
38+ trace_print : bool ,
39+ /// Print a histogram of instruction dispatch counts
40+ #[ cfg( feature = "trace" ) ]
41+ #[ arg( long) ]
42+ trace_histogram : bool ,
43+ /// Print cumulative time spent per instruction type
44+ #[ cfg( feature = "trace" ) ]
45+ #[ arg( long) ]
46+ trace_time : bool ,
47+ /// Render source as a heat map colored by time spent per span
48+ #[ cfg( feature = "trace" ) ]
49+ #[ arg( long) ]
50+ trace_span : bool ,
51+ } ,
3252 /// Output an .ndc file using the built-in syntax highlighting engine
3353 Highlight { file : PathBuf } ,
3454
@@ -56,14 +76,32 @@ enum Command {
5676
5777impl Default for Command {
5878 fn default ( ) -> Self {
59- Self :: Run { file : None }
79+ Self :: Run {
80+ file : None ,
81+ #[ cfg( feature = "trace" ) ]
82+ trace_print : false ,
83+ #[ cfg( feature = "trace" ) ]
84+ trace_histogram : false ,
85+ #[ cfg( feature = "trace" ) ]
86+ trace_time : false ,
87+ #[ cfg( feature = "trace" ) ]
88+ trace_span : false ,
89+ }
6090 }
6191}
6292
6393enum Action {
6494 RunLsp ,
6595 RunFile {
6696 path : PathBuf ,
97+ #[ cfg( feature = "trace" ) ]
98+ trace_print : bool ,
99+ #[ cfg( feature = "trace" ) ]
100+ trace_histogram : bool ,
101+ #[ cfg( feature = "trace" ) ]
102+ trace_time : bool ,
103+ #[ cfg( feature = "trace" ) ]
104+ trace_span : bool ,
67105 } ,
68106 DisassembleFile ( PathBuf ) ,
69107 HighlightFile ( PathBuf ) ,
@@ -79,8 +117,28 @@ impl TryFrom<Command> for Action {
79117
80118 fn try_from ( value : Command ) -> Result < Self , Self :: Error > {
81119 let action = match value {
82- Command :: Run { file : Some ( file) } => Self :: RunFile { path : file } ,
83- Command :: Run { file : None } => Self :: StartRepl ,
120+ Command :: Run {
121+ file : Some ( file) ,
122+ #[ cfg( feature = "trace" ) ]
123+ trace_print,
124+ #[ cfg( feature = "trace" ) ]
125+ trace_histogram,
126+ #[ cfg( feature = "trace" ) ]
127+ trace_time,
128+ #[ cfg( feature = "trace" ) ]
129+ trace_span,
130+ } => Self :: RunFile {
131+ path : file,
132+ #[ cfg( feature = "trace" ) ]
133+ trace_print,
134+ #[ cfg( feature = "trace" ) ]
135+ trace_histogram,
136+ #[ cfg( feature = "trace" ) ]
137+ trace_time,
138+ #[ cfg( feature = "trace" ) ]
139+ trace_span,
140+ } ,
141+ Command :: Run { file : None , .. } => Self :: StartRepl ,
84142 Command :: Lsp { stdio : _ } => Self :: RunLsp ,
85143 Command :: Disassemble { file } => Self :: DisassembleFile ( file) ,
86144 Command :: Highlight { file } => Self :: HighlightFile ( file) ,
@@ -93,6 +151,14 @@ impl TryFrom<Command> for Action {
93151 }
94152 1 => Self :: RunFile {
95153 path : args[ 0 ] . parse :: < PathBuf > ( ) . context ( "invalid path" ) ?,
154+ #[ cfg( feature = "trace" ) ]
155+ trace_print : false ,
156+ #[ cfg( feature = "trace" ) ]
157+ trace_histogram : false ,
158+ #[ cfg( feature = "trace" ) ]
159+ trace_time : false ,
160+ #[ cfg( feature = "trace" ) ]
161+ trace_span : false ,
96162 } ,
97163 n => return Err ( anyhow ! ( "invalid number of arguments: {n}" ) ) ,
98164 }
@@ -108,7 +174,17 @@ fn main() -> anyhow::Result<()> {
108174 let action: Action = cli. command . unwrap_or_default ( ) . try_into ( ) ?;
109175
110176 match action {
111- Action :: RunFile { path } => {
177+ Action :: RunFile {
178+ path,
179+ #[ cfg( feature = "trace" ) ]
180+ trace_print,
181+ #[ cfg( feature = "trace" ) ]
182+ trace_histogram,
183+ #[ cfg( feature = "trace" ) ]
184+ trace_time,
185+ #[ cfg( feature = "trace" ) ]
186+ trace_span,
187+ } => {
112188 let filename = path
113189 . file_name ( )
114190 . and_then ( |name| name. to_str ( ) )
@@ -118,6 +194,28 @@ fn main() -> anyhow::Result<()> {
118194
119195 let mut interpreter = Interpreter :: new ( ) ;
120196 interpreter. configure ( ndc_stdlib:: register) ;
197+
198+ #[ cfg( feature = "trace" ) ]
199+ {
200+ use ndc_interpreter:: tracer;
201+ let mut tracers: Vec < Box < dyn tracer:: VmTracer > > = Vec :: new ( ) ;
202+ if trace_print {
203+ tracers. push ( Box :: new ( tracer:: PrintTracer ) ) ;
204+ }
205+ if trace_histogram {
206+ tracers. push ( Box :: new ( tracer:: HistogramTracer :: new ( ) ) ) ;
207+ }
208+ if trace_time {
209+ tracers. push ( Box :: new ( tracer:: TimingTracer :: new ( ) ) ) ;
210+ }
211+ if trace_span {
212+ tracers. push ( Box :: new ( span_tracer:: SpanTracer :: new ( ) ) ) ;
213+ }
214+ if !tracers. is_empty ( ) {
215+ interpreter. set_tracer ( Box :: new ( tracer:: CompositeTracer :: new ( tracers) ) ) ;
216+ }
217+ }
218+
121219 let name = filename. as_deref ( ) . unwrap_or ( "<input>" ) ;
122220 if let Err ( err) = interpreter. eval_named ( name, & string) {
123221 diagnostic:: emit_error ( interpreter. source_db ( ) , err) ;
0 commit comments