1use std::sync::Mutex;
7
8pub struct InstrumentStats {
10 pub parse_expr_calls: u64,
13 pub parse_expr_bp_recursive_calls: u64,
15 pub parse_array_element_calls: u64,
17 pub parse_array_element_with_arrow: u64,
19 pub parse_expr_array_first: u64,
21 pub parse_expr_array_second: u64,
23 pub parse_array_count: u64,
25 pub parse_array_element_count: u64,
27 pub parse_atom_calls: u64,
29 pub parse_array_simple_values: u64,
31
32 pub parse_stmt_calls: u64,
35 pub parse_function_calls: u64,
37 pub parse_class_calls: u64,
39 pub parse_foreach_calls: u64,
41 pub parse_loop_calls: u64,
43 pub parse_if_calls: u64,
45 pub parse_switch_calls: u64,
47 pub parse_try_calls: u64,
49 pub parse_attribute_calls: u64,
51
52 pub arena_vec_allocations: u64,
55 pub arena_vec_bytes: u64,
57 pub arena_alloc_calls: u64,
59 pub arena_vec_reallocations: u64,
61 pub arena_vec_wasted_capacity: u64,
63 pub arena_vec_empty: u64,
65}
66
67lazy_static::lazy_static! {
68 static ref STATS: Mutex<InstrumentStats> = Mutex::new(InstrumentStats {
69 parse_expr_calls: 0,
70 parse_expr_bp_recursive_calls: 0,
71 parse_array_element_calls: 0,
72 parse_array_element_with_arrow: 0,
73 parse_expr_array_first: 0,
74 parse_expr_array_second: 0,
75 parse_array_count: 0,
76 parse_array_element_count: 0,
77 parse_atom_calls: 0,
78 parse_array_simple_values: 0,
79 parse_stmt_calls: 0,
80 parse_function_calls: 0,
81 parse_class_calls: 0,
82 parse_foreach_calls: 0,
83 parse_loop_calls: 0,
84 parse_if_calls: 0,
85 parse_switch_calls: 0,
86 parse_try_calls: 0,
87 parse_attribute_calls: 0,
88 arena_vec_allocations: 0,
89 arena_vec_bytes: 0,
90 arena_alloc_calls: 0,
91 arena_vec_reallocations: 0,
92 arena_vec_wasted_capacity: 0,
93 arena_vec_empty: 0,
94 });
95}
96
97#[inline]
99pub fn record_parse_expr() {
100 #[cfg(feature = "instrument")]
101 {
102 if let Ok(mut stats) = STATS.lock() {
103 stats.parse_expr_calls += 1;
104 }
105 }
106}
107
108#[inline]
110pub fn record_parse_expr_bp_recursive() {
111 #[cfg(feature = "instrument")]
112 {
113 if let Ok(mut stats) = STATS.lock() {
114 stats.parse_expr_bp_recursive_calls += 1;
115 }
116 }
117}
118
119#[inline]
121pub fn record_parse_array() {
122 #[cfg(feature = "instrument")]
123 {
124 if let Ok(mut stats) = STATS.lock() {
125 stats.parse_array_count += 1;
126 }
127 }
128}
129
130#[inline]
132pub fn record_parse_array_element() {
133 #[cfg(feature = "instrument")]
134 {
135 if let Ok(mut stats) = STATS.lock() {
136 stats.parse_array_element_calls += 1;
137 }
138 }
139}
140
141#[inline]
143pub fn record_parse_expr_array_first() {
144 #[cfg(feature = "instrument")]
145 {
146 if let Ok(mut stats) = STATS.lock() {
147 stats.parse_expr_array_first += 1;
148 }
149 }
150}
151
152#[inline]
154pub fn record_parse_expr_array_second() {
155 #[cfg(feature = "instrument")]
156 {
157 if let Ok(mut stats) = STATS.lock() {
158 stats.parse_expr_array_second += 1;
159 }
160 }
161}
162
163#[inline]
165pub fn record_parse_array_element_with_arrow() {
166 #[cfg(feature = "instrument")]
167 {
168 if let Ok(mut stats) = STATS.lock() {
169 stats.parse_array_element_with_arrow += 1;
170 }
171 }
172}
173
174#[inline]
176pub fn record_parse_array_element_count(_count: usize) {
177 #[cfg(feature = "instrument")]
178 {
179 if let Ok(mut stats) = STATS.lock() {
180 stats.parse_array_element_count += _count as u64;
181 }
182 }
183}
184
185#[inline]
187pub fn record_parse_atom() {
188 #[cfg(feature = "instrument")]
189 {
190 if let Ok(mut stats) = STATS.lock() {
191 stats.parse_atom_calls += 1;
192 }
193 }
194}
195
196#[inline]
198pub fn record_parse_array_simple_value() {
199 #[cfg(feature = "instrument")]
200 {
201 if let Ok(mut stats) = STATS.lock() {
202 stats.parse_array_simple_values += 1;
203 }
204 }
205}
206
207#[inline]
211pub fn record_parse_stmt() {
212 #[cfg(feature = "instrument")]
213 {
214 if let Ok(mut stats) = STATS.lock() {
215 stats.parse_stmt_calls += 1;
216 }
217 }
218}
219
220#[inline]
222pub fn record_parse_function() {
223 #[cfg(feature = "instrument")]
224 {
225 if let Ok(mut stats) = STATS.lock() {
226 stats.parse_function_calls += 1;
227 }
228 }
229}
230
231#[inline]
233pub fn record_parse_class() {
234 #[cfg(feature = "instrument")]
235 {
236 if let Ok(mut stats) = STATS.lock() {
237 stats.parse_class_calls += 1;
238 }
239 }
240}
241
242#[inline]
244pub fn record_parse_foreach() {
245 #[cfg(feature = "instrument")]
246 {
247 if let Ok(mut stats) = STATS.lock() {
248 stats.parse_foreach_calls += 1;
249 }
250 }
251}
252
253#[inline]
255pub fn record_parse_loop() {
256 #[cfg(feature = "instrument")]
257 {
258 if let Ok(mut stats) = STATS.lock() {
259 stats.parse_loop_calls += 1;
260 }
261 }
262}
263
264#[inline]
266pub fn record_parse_if() {
267 #[cfg(feature = "instrument")]
268 {
269 if let Ok(mut stats) = STATS.lock() {
270 stats.parse_if_calls += 1;
271 }
272 }
273}
274
275#[inline]
277pub fn record_parse_switch() {
278 #[cfg(feature = "instrument")]
279 {
280 if let Ok(mut stats) = STATS.lock() {
281 stats.parse_switch_calls += 1;
282 }
283 }
284}
285
286#[inline]
288pub fn record_parse_try() {
289 #[cfg(feature = "instrument")]
290 {
291 if let Ok(mut stats) = STATS.lock() {
292 stats.parse_try_calls += 1;
293 }
294 }
295}
296
297#[inline]
299pub fn record_parse_attribute() {
300 #[cfg(feature = "instrument")]
301 {
302 if let Ok(mut stats) = STATS.lock() {
303 stats.parse_attribute_calls += 1;
304 }
305 }
306}
307
308#[inline]
312pub fn record_arena_vec_allocation(_capacity: usize) {
313 #[cfg(feature = "instrument")]
314 {
315 if let Ok(mut stats) = STATS.lock() {
316 stats.arena_vec_allocations += 1;
317 stats.arena_vec_bytes += _capacity as u64;
318 }
319 }
320}
321
322#[inline]
324pub fn record_arena_alloc() {
325 #[cfg(feature = "instrument")]
326 {
327 if let Ok(mut stats) = STATS.lock() {
328 stats.arena_alloc_calls += 1;
329 }
330 }
331}
332
333#[inline]
335pub fn record_arena_vec_waste(_wasted_bytes: usize) {
336 #[cfg(feature = "instrument")]
337 {
338 if let Ok(mut stats) = STATS.lock() {
339 stats.arena_vec_wasted_capacity += _wasted_bytes as u64;
340 }
341 }
342}
343
344#[inline]
346pub fn record_arena_vec_empty() {
347 #[cfg(feature = "instrument")]
348 {
349 if let Ok(mut stats) = STATS.lock() {
350 stats.arena_vec_empty += 1;
351 }
352 }
353}
354
355pub fn get_stats() -> InstrumentStats {
357 #[cfg(feature = "instrument")]
358 {
359 STATS
360 .lock()
361 .ok()
362 .map(|stats| InstrumentStats {
363 parse_expr_calls: stats.parse_expr_calls,
364 parse_expr_bp_recursive_calls: stats.parse_expr_bp_recursive_calls,
365 parse_array_element_calls: stats.parse_array_element_calls,
366 parse_array_element_with_arrow: stats.parse_array_element_with_arrow,
367 parse_expr_array_first: stats.parse_expr_array_first,
368 parse_expr_array_second: stats.parse_expr_array_second,
369 parse_array_count: stats.parse_array_count,
370 parse_array_element_count: stats.parse_array_element_count,
371 parse_atom_calls: stats.parse_atom_calls,
372 parse_array_simple_values: stats.parse_array_simple_values,
373 parse_stmt_calls: stats.parse_stmt_calls,
374 parse_function_calls: stats.parse_function_calls,
375 parse_class_calls: stats.parse_class_calls,
376 parse_foreach_calls: stats.parse_foreach_calls,
377 parse_loop_calls: stats.parse_loop_calls,
378 parse_if_calls: stats.parse_if_calls,
379 parse_switch_calls: stats.parse_switch_calls,
380 parse_try_calls: stats.parse_try_calls,
381 parse_attribute_calls: stats.parse_attribute_calls,
382 arena_vec_allocations: stats.arena_vec_allocations,
383 arena_vec_bytes: stats.arena_vec_bytes,
384 arena_alloc_calls: stats.arena_alloc_calls,
385 arena_vec_reallocations: stats.arena_vec_reallocations,
386 arena_vec_wasted_capacity: stats.arena_vec_wasted_capacity,
387 arena_vec_empty: stats.arena_vec_empty,
388 })
389 .unwrap_or(InstrumentStats {
390 parse_expr_calls: 0,
391 parse_expr_bp_recursive_calls: 0,
392 parse_array_element_calls: 0,
393 parse_array_element_with_arrow: 0,
394 parse_expr_array_first: 0,
395 parse_expr_array_second: 0,
396 parse_array_count: 0,
397 parse_array_element_count: 0,
398 parse_atom_calls: 0,
399 parse_array_simple_values: 0,
400 parse_stmt_calls: 0,
401 parse_function_calls: 0,
402 parse_class_calls: 0,
403 parse_foreach_calls: 0,
404 parse_loop_calls: 0,
405 parse_if_calls: 0,
406 parse_switch_calls: 0,
407 parse_try_calls: 0,
408 parse_attribute_calls: 0,
409 arena_vec_allocations: 0,
410 arena_vec_bytes: 0,
411 arena_alloc_calls: 0,
412 arena_vec_reallocations: 0,
413 arena_vec_wasted_capacity: 0,
414 arena_vec_empty: 0,
415 })
416 }
417 #[cfg(not(feature = "instrument"))]
418 {
419 InstrumentStats {
420 parse_expr_calls: 0,
421 parse_expr_bp_recursive_calls: 0,
422 parse_array_element_calls: 0,
423 parse_array_element_with_arrow: 0,
424 parse_expr_array_first: 0,
425 parse_expr_array_second: 0,
426 parse_array_count: 0,
427 parse_array_element_count: 0,
428 parse_atom_calls: 0,
429 parse_array_simple_values: 0,
430 parse_stmt_calls: 0,
431 parse_function_calls: 0,
432 parse_class_calls: 0,
433 parse_foreach_calls: 0,
434 parse_loop_calls: 0,
435 parse_if_calls: 0,
436 parse_switch_calls: 0,
437 parse_try_calls: 0,
438 parse_attribute_calls: 0,
439 arena_vec_allocations: 0,
440 arena_vec_bytes: 0,
441 arena_alloc_calls: 0,
442 arena_vec_reallocations: 0,
443 arena_vec_wasted_capacity: 0,
444 arena_vec_empty: 0,
445 }
446 }
447}
448
449pub fn report_stats() {
451 #[cfg(feature = "instrument")]
452 {
453 let stats = get_stats();
454 println!("\n╔════════════════════════════════════════════════════════════╗");
455 println!("║ Parser Instrumentation Report (Full Analysis) ║");
456 println!("╠════════════════════════════════════════════════════════════╣");
457
458 println!("║ STATEMENT PARSING: ║");
459 println!(
460 "║ Total statements: {:18} ║",
461 stats.parse_stmt_calls
462 );
463 println!(
464 "║ - Functions: {:18} ║",
465 stats.parse_function_calls
466 );
467 println!(
468 "║ - Classes/Traits: {:18} ║",
469 stats.parse_class_calls
470 );
471 println!(
472 "║ - If statements: {:18} ║",
473 stats.parse_if_calls
474 );
475 println!(
476 "║ - Loops (for/while/do): {:18} ║",
477 stats.parse_loop_calls
478 );
479 println!(
480 "║ - Foreach: {:18} ║",
481 stats.parse_foreach_calls
482 );
483 println!(
484 "║ - Switch: {:18} ║",
485 stats.parse_switch_calls
486 );
487 println!(
488 "║ - Try/Catch: {:18} ║",
489 stats.parse_try_calls
490 );
491 println!(
492 "║ - Attributes: {:18} ║",
493 stats.parse_attribute_calls
494 );
495
496 println!("╠════════════════════════════════════════════════════════════╣");
497 println!("║ ARRAY & EXPRESSION PARSING: ║");
498 println!(
499 "║ Arrays Parsed: {:18} ║",
500 stats.parse_array_count
501 );
502 println!(
503 "║ Array Elements: {:18} ║",
504 stats.parse_array_element_count
505 );
506 println!(
507 "║ Array Elements with =>: {:18} ║",
508 stats.parse_array_element_with_arrow
509 );
510
511 let arrow_rate = if stats.parse_array_element_calls > 0 {
512 (stats.parse_array_element_with_arrow as f64 / stats.parse_array_element_calls as f64)
513 * 100.0
514 } else {
515 0.0
516 };
517 println!(
518 "║ => Rate: {:15.1}% ║",
519 arrow_rate
520 );
521
522 println!("╠════════════════════════════════════════════════════════════╣");
523 println!(
524 "║ Total parse_expr calls: {:18} ║",
525 stats.parse_expr_calls
526 );
527 println!(
528 "║ parse_expr calls (array, first): {:18} ║",
529 stats.parse_expr_array_first
530 );
531 println!(
532 "║ parse_expr calls (array, second =>): {:18} ║",
533 stats.parse_expr_array_second
534 );
535
536 let second_expr_overhead = stats.parse_expr_array_second;
537 let second_expr_pct = if stats.parse_expr_calls > 0 {
538 (second_expr_overhead as f64 / stats.parse_expr_calls as f64) * 100.0
539 } else {
540 0.0
541 };
542 println!(
543 "║ Double-parse overhead (%): {:15.1}% ║",
544 second_expr_pct
545 );
546
547 println!("╠════════════════════════════════════════════════════════════╣");
548 println!(
549 "║ parse_atom calls: {:18} ║",
550 stats.parse_atom_calls
551 );
552 println!(
553 "║ Simple array values (no operators): {:18} ║",
554 stats.parse_array_simple_values
555 );
556
557 let simple_pct = if stats.parse_array_element_count > 0 {
558 (stats.parse_array_simple_values as f64 / stats.parse_array_element_count as f64)
559 * 100.0
560 } else {
561 0.0
562 };
563 println!(
564 "║ Simple value rate: {:15.1}% ║",
565 simple_pct
566 );
567
568 println!("╚════════════════════════════════════════════════════════════╝\n");
569 }
570 #[cfg(not(feature = "instrument"))]
571 {
572 eprintln!("⚠️ Instrumentation not enabled. Compile with `--features instrument`");
573 }
574}
575
576pub fn reset_stats() {
578 #[cfg(feature = "instrument")]
579 {
580 if let Ok(mut stats) = STATS.lock() {
581 stats.parse_expr_calls = 0;
582 stats.parse_expr_bp_recursive_calls = 0;
583 stats.parse_array_element_calls = 0;
584 stats.parse_array_element_with_arrow = 0;
585 stats.parse_expr_array_first = 0;
586 stats.parse_expr_array_second = 0;
587 stats.parse_array_count = 0;
588 stats.parse_array_element_count = 0;
589 stats.parse_atom_calls = 0;
590 stats.parse_array_simple_values = 0;
591 stats.parse_stmt_calls = 0;
592 stats.parse_function_calls = 0;
593 stats.parse_class_calls = 0;
594 stats.parse_foreach_calls = 0;
595 stats.parse_loop_calls = 0;
596 stats.parse_if_calls = 0;
597 stats.parse_switch_calls = 0;
598 stats.parse_try_calls = 0;
599 stats.parse_attribute_calls = 0;
600 stats.arena_vec_allocations = 0;
601 stats.arena_vec_bytes = 0;
602 stats.arena_alloc_calls = 0;
603 stats.arena_vec_reallocations = 0;
604 stats.arena_vec_wasted_capacity = 0;
605 stats.arena_vec_empty = 0;
606 }
607 }
608}