1#![allow(clippy::missing_const_for_thread_local)]
4
5use std::cell::RefCell;
6use std::collections::BTreeMap;
7
8#[derive(Debug, Default)]
9struct Counters {
10 adaptive_calls: u64,
11 forced_full_context_calls: u64,
12 full_context_retries: u64,
13 sll_conflicts: u64,
14 reach_sll_calls: u64,
15 reach_full_context_calls: u64,
16 reach_input_configs: u64,
17 reach_output_configs: u64,
18 reach_max_input_configs: u64,
19 reach_max_output_configs: u64,
20 closure_calls: u64,
21 closure_visited_total: u64,
22 closure_visited_max: u64,
23 config_add_calls: u64,
24 config_inserts: u64,
25 config_merges: u64,
26 config_max_size: u64,
27 context_merge_calls: u64,
28 context_merge_identical: u64,
29 context_merge_cache_hits: u64,
30 context_merge_cache_misses: u64,
31 context_merge_uncached: u64,
32 context_cache_calls: u64,
33 context_cache_hits: u64,
34 context_cache_misses: u64,
35 context_cache_inserts: u64,
36 dfa_edge_lookups: u64,
37 dfa_edge_hits: u64,
38 dfa_edge_misses: u64,
39 dfa_atn_fallbacks: u64,
40 dfa_states_created: u64,
41 dfa_states_deduplicated: u64,
42 dfa_fingerprint_candidates: u64,
43 dfa_fingerprint_collisions: u64,
44 dfa_cache_imports: u64,
45 dfa_cache_import_nanos: u64,
46 dfa_cache_import_states: u64,
47 dfa_cache_publications: u64,
48 dfa_cache_publication_nanos: u64,
49 dfa_cache_publication_states: u64,
50 lexer_direct_ascii_chars: u64,
51 lexer_generic_chars: u64,
52 lexer_scalar_replay_chars: u64,
53 lexer_bulk_committed_chars: u64,
54 lexer_compiled_scalar_ascii_chars: u64,
55 lexer_run_scan_calls: u64,
56 lexer_run_scan_bytes: u64,
57 lexer_run_scan_exits: u64,
58 lexer_run_scan_ends: u64,
59 lexer_run_rejected_states: u64,
60 lexer_run_descriptors_none: u64,
61 lexer_run_descriptors_any: u64,
62 lexer_run_descriptors_until: u64,
63 lexer_range_descriptors: [u64; 4],
64 lexer_range_descriptor_classes: [u64; 4],
65 lexer_range_scalar_calls: u64,
66 lexer_range_scalar_bytes: u64,
67 lexer_range_identifier_bytes: u64,
68 lexer_range_number_bytes: u64,
69 lexer_range_whitespace_bytes: u64,
70 lexer_range_other_bytes: u64,
71 parser_token_set_inline_sets: u64,
72 parser_token_set_dense_sets: u64,
73 parser_token_set_interval_sets: u64,
74 parser_token_set_inline_bytes: u64,
75 parser_token_set_dense_bytes: u64,
76 parser_token_set_inline_hits: u64,
77 parser_token_set_inline_misses: u64,
78 parser_token_set_dense_hits: u64,
79 parser_token_set_dense_misses: u64,
80 parser_token_set_interval_hits: u64,
81 parser_token_set_interval_misses: u64,
82 parser_token_set_interval_probes_eliminated: u64,
83 parser_token_set_interval_binary_probes_retained: u64,
84 decisions: BTreeMap<usize, DecisionCounters>,
85}
86
87#[derive(Debug, Default)]
88struct DecisionCounters {
89 adaptive_calls: u64,
90 forced_full_context_calls: u64,
91 full_context_retries: u64,
92 sll_conflicts: u64,
93}
94
95thread_local! {
96 static COUNTERS: RefCell<Counters> = RefCell::new(Counters::default());
97}
98
99fn with_counters(update: impl FnOnce(&mut Counters)) {
100 COUNTERS.with(|counters| update(&mut counters.borrow_mut()));
101}
102
103fn add_len(total: &mut u64, max: &mut u64, len: usize) {
104 let len = u64::try_from(len).unwrap_or(u64::MAX);
105 *total = total.saturating_add(len);
106 *max = (*max).max(len);
107}
108
109const fn record_hit(hit: bool, hits: &mut u64, misses: &mut u64) {
110 let counter = if hit { hits } else { misses };
111 *counter = counter.saturating_add(1);
112}
113
114pub(crate) fn record_adaptive_call(decision: usize, forced_full_context: bool) {
115 with_counters(|counters| {
116 counters.adaptive_calls = counters.adaptive_calls.saturating_add(1);
117 let decision_counters = counters.decisions.entry(decision).or_default();
118 decision_counters.adaptive_calls = decision_counters.adaptive_calls.saturating_add(1);
119 if forced_full_context {
120 counters.forced_full_context_calls =
121 counters.forced_full_context_calls.saturating_add(1);
122 decision_counters.forced_full_context_calls = decision_counters
123 .forced_full_context_calls
124 .saturating_add(1);
125 }
126 });
127}
128
129pub(crate) fn record_full_context_retry(decision: usize) {
130 with_counters(|counters| {
131 counters.full_context_retries = counters.full_context_retries.saturating_add(1);
132 let decision_counters = counters.decisions.entry(decision).or_default();
133 decision_counters.full_context_retries =
134 decision_counters.full_context_retries.saturating_add(1);
135 });
136}
137
138pub(crate) fn record_sll_conflict(decision: usize) {
139 with_counters(|counters| {
140 counters.sll_conflicts = counters.sll_conflicts.saturating_add(1);
141 let decision_counters = counters.decisions.entry(decision).or_default();
142 decision_counters.sll_conflicts = decision_counters.sll_conflicts.saturating_add(1);
143 });
144}
145
146pub(crate) fn record_reach_set(full_context: bool, input_configs: usize, output_configs: usize) {
147 with_counters(|counters| {
148 if full_context {
149 counters.reach_full_context_calls = counters.reach_full_context_calls.saturating_add(1);
150 } else {
151 counters.reach_sll_calls = counters.reach_sll_calls.saturating_add(1);
152 }
153 add_len(
154 &mut counters.reach_input_configs,
155 &mut counters.reach_max_input_configs,
156 input_configs,
157 );
158 add_len(
159 &mut counters.reach_output_configs,
160 &mut counters.reach_max_output_configs,
161 output_configs,
162 );
163 });
164}
165
166pub(crate) fn record_closure(visited_configs: usize) {
167 with_counters(|counters| {
168 counters.closure_calls = counters.closure_calls.saturating_add(1);
169 add_len(
170 &mut counters.closure_visited_total,
171 &mut counters.closure_visited_max,
172 visited_configs,
173 );
174 });
175}
176
177pub(crate) fn record_config_add_call() {
178 with_counters(|counters| {
179 counters.config_add_calls = counters.config_add_calls.saturating_add(1);
180 });
181}
182
183pub(crate) fn record_config_insert(size_after: usize) {
184 with_counters(|counters| {
185 counters.config_inserts = counters.config_inserts.saturating_add(1);
186 counters.config_max_size = counters
187 .config_max_size
188 .max(u64::try_from(size_after).unwrap_or(u64::MAX));
189 });
190}
191
192pub(crate) fn record_config_merge() {
193 with_counters(|counters| {
194 counters.config_merges = counters.config_merges.saturating_add(1);
195 });
196}
197
198pub(crate) fn record_context_merge_call() {
199 with_counters(|counters| {
200 counters.context_merge_calls = counters.context_merge_calls.saturating_add(1);
201 });
202}
203
204pub(crate) fn record_context_merge_identical() {
205 with_counters(|counters| {
206 counters.context_merge_identical = counters.context_merge_identical.saturating_add(1);
207 });
208}
209
210pub(crate) fn record_context_merge_cache_hit() {
211 with_counters(|counters| {
212 counters.context_merge_cache_hits = counters.context_merge_cache_hits.saturating_add(1);
213 });
214}
215
216pub(crate) fn record_context_merge_cache_miss() {
217 with_counters(|counters| {
218 counters.context_merge_cache_misses = counters.context_merge_cache_misses.saturating_add(1);
219 });
220}
221
222pub(crate) fn record_context_merge_uncached() {
223 with_counters(|counters| {
224 counters.context_merge_uncached = counters.context_merge_uncached.saturating_add(1);
225 });
226}
227
228pub(crate) fn record_context_cache_call() {
229 with_counters(|counters| {
230 counters.context_cache_calls = counters.context_cache_calls.saturating_add(1);
231 });
232}
233
234pub(crate) fn record_context_cache_hit() {
235 with_counters(|counters| {
236 counters.context_cache_hits = counters.context_cache_hits.saturating_add(1);
237 });
238}
239
240pub(crate) fn record_context_cache_miss() {
241 with_counters(|counters| {
242 counters.context_cache_misses = counters.context_cache_misses.saturating_add(1);
243 });
244}
245
246pub(crate) fn record_context_cache_insert() {
247 with_counters(|counters| {
248 counters.context_cache_inserts = counters.context_cache_inserts.saturating_add(1);
249 });
250}
251
252pub(crate) fn record_dfa_edge_lookup(hit: bool) {
253 with_counters(|counters| {
254 counters.dfa_edge_lookups = counters.dfa_edge_lookups.saturating_add(1);
255 if hit {
256 counters.dfa_edge_hits = counters.dfa_edge_hits.saturating_add(1);
257 } else {
258 counters.dfa_edge_misses = counters.dfa_edge_misses.saturating_add(1);
259 counters.dfa_atn_fallbacks = counters.dfa_atn_fallbacks.saturating_add(1);
260 }
261 });
262}
263
264pub(crate) fn record_dfa_state_created() {
265 with_counters(|counters| {
266 counters.dfa_states_created = counters.dfa_states_created.saturating_add(1);
267 });
268}
269
270pub(crate) fn record_dfa_state_deduplicated() {
271 with_counters(|counters| {
272 counters.dfa_states_deduplicated = counters.dfa_states_deduplicated.saturating_add(1);
273 });
274}
275
276pub(crate) fn record_dfa_fingerprint_candidate() {
277 with_counters(|counters| {
278 counters.dfa_fingerprint_candidates = counters.dfa_fingerprint_candidates.saturating_add(1);
279 });
280}
281
282pub(crate) fn record_dfa_fingerprint_collision() {
283 with_counters(|counters| {
284 counters.dfa_fingerprint_collisions = counters.dfa_fingerprint_collisions.saturating_add(1);
285 });
286}
287
288pub(crate) fn record_dfa_cache_import(nanos: u128, states: usize) {
289 with_counters(|counters| {
290 counters.dfa_cache_imports = counters.dfa_cache_imports.saturating_add(1);
291 counters.dfa_cache_import_nanos = counters
292 .dfa_cache_import_nanos
293 .saturating_add(u64::try_from(nanos).unwrap_or(u64::MAX));
294 counters.dfa_cache_import_states = counters
295 .dfa_cache_import_states
296 .saturating_add(u64::try_from(states).unwrap_or(u64::MAX));
297 });
298}
299
300pub(crate) fn record_dfa_cache_publication(nanos: u128, states: usize) {
301 with_counters(|counters| {
302 counters.dfa_cache_publications = counters.dfa_cache_publications.saturating_add(1);
303 counters.dfa_cache_publication_nanos = counters
304 .dfa_cache_publication_nanos
305 .saturating_add(u64::try_from(nanos).unwrap_or(u64::MAX));
306 counters.dfa_cache_publication_states = counters
307 .dfa_cache_publication_states
308 .saturating_add(u64::try_from(states).unwrap_or(u64::MAX));
309 });
310}
311
312pub(crate) fn record_lexer_direct_ascii(count: usize) {
313 with_counters(|counters| {
314 counters.lexer_direct_ascii_chars = counters
315 .lexer_direct_ascii_chars
316 .saturating_add(u64::try_from(count).unwrap_or(u64::MAX));
317 });
318}
319
320pub(crate) fn record_lexer_generic_char() {
321 with_counters(|counters| {
322 counters.lexer_generic_chars = counters.lexer_generic_chars.saturating_add(1);
323 });
324}
325
326pub(crate) fn record_lexer_scalar_replay(count: usize) {
327 with_counters(|counters| {
328 counters.lexer_scalar_replay_chars = counters
329 .lexer_scalar_replay_chars
330 .saturating_add(u64::try_from(count).unwrap_or(u64::MAX));
331 });
332}
333
334pub(crate) fn record_lexer_bulk_commit(count: usize) {
335 with_counters(|counters| {
336 counters.lexer_bulk_committed_chars = counters
337 .lexer_bulk_committed_chars
338 .saturating_add(u64::try_from(count).unwrap_or(u64::MAX));
339 });
340}
341
342pub(crate) fn record_lexer_compiled_scalar_ascii(count: usize) {
343 with_counters(|counters| {
344 counters.lexer_compiled_scalar_ascii_chars = counters
345 .lexer_compiled_scalar_ascii_chars
346 .saturating_add(u64::try_from(count).unwrap_or(u64::MAX));
347 });
348}
349
350pub(crate) fn record_lexer_run_scan(bytes: usize, found_exit: bool) {
351 with_counters(|counters| {
352 counters.lexer_run_scan_calls = counters.lexer_run_scan_calls.saturating_add(1);
353 counters.lexer_run_scan_bytes = counters
354 .lexer_run_scan_bytes
355 .saturating_add(u64::try_from(bytes).unwrap_or(u64::MAX));
356 if found_exit {
357 counters.lexer_run_scan_exits = counters.lexer_run_scan_exits.saturating_add(1);
358 } else {
359 counters.lexer_run_scan_ends = counters.lexer_run_scan_ends.saturating_add(1);
360 }
361 });
362}
363
364pub(crate) fn record_lexer_run_rejected_state() {
365 with_counters(|counters| {
366 counters.lexer_run_rejected_states = counters.lexer_run_rejected_states.saturating_add(1);
367 });
368}
369
370pub(crate) fn record_lexer_run_descriptor(kind: crate::atn::lexer_dfa::AsciiRunDescriptorKind) {
371 use crate::atn::lexer_dfa::AsciiRunDescriptorKind;
372
373 with_counters(|counters| match kind {
374 AsciiRunDescriptorKind::None => {
375 counters.lexer_run_descriptors_none =
376 counters.lexer_run_descriptors_none.saturating_add(1);
377 }
378 AsciiRunDescriptorKind::Any => {
379 counters.lexer_run_descriptors_any =
380 counters.lexer_run_descriptors_any.saturating_add(1);
381 }
382 AsciiRunDescriptorKind::Until => {
383 counters.lexer_run_descriptors_until =
384 counters.lexer_run_descriptors_until.saturating_add(1);
385 }
386 AsciiRunDescriptorKind::Ranges { count, class } => {
387 if let Some(counter) = count
388 .checked_sub(1)
389 .and_then(|index| counters.lexer_range_descriptors.get_mut(usize::from(index)))
390 {
391 *counter = counter.saturating_add(1);
392 }
393 let class_index = match class {
394 crate::atn::ascii_range::AsciiRangeClass::Identifier => 0,
395 crate::atn::ascii_range::AsciiRangeClass::Number => 1,
396 crate::atn::ascii_range::AsciiRangeClass::Whitespace => 2,
397 crate::atn::ascii_range::AsciiRangeClass::Other => 3,
398 };
399 counters.lexer_range_descriptor_classes[class_index] =
400 counters.lexer_range_descriptor_classes[class_index].saturating_add(1);
401 }
402 });
403}
404
405pub(crate) fn record_lexer_range_scan(
406 class: crate::atn::ascii_range::AsciiRangeClass,
407 bytes: usize,
408) {
409 use crate::atn::ascii_range::AsciiRangeClass;
410
411 let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
412 with_counters(|counters| {
413 counters.lexer_range_scalar_calls = counters.lexer_range_scalar_calls.saturating_add(1);
414 counters.lexer_range_scalar_bytes = counters.lexer_range_scalar_bytes.saturating_add(bytes);
415 let class_bytes = match class {
416 AsciiRangeClass::Identifier => &mut counters.lexer_range_identifier_bytes,
417 AsciiRangeClass::Number => &mut counters.lexer_range_number_bytes,
418 AsciiRangeClass::Whitespace => &mut counters.lexer_range_whitespace_bytes,
419 AsciiRangeClass::Other => &mut counters.lexer_range_other_bytes,
420 };
421 *class_bytes = class_bytes.saturating_add(bytes);
422 });
423}
424
425pub(crate) fn record_parser_token_set_selection(
426 kind: crate::atn::parser_atn::ParserTokenSetKind,
427 bytes: usize,
428) {
429 use crate::atn::parser_atn::ParserTokenSetKind;
430
431 let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
432 with_counters(|counters| match kind {
433 ParserTokenSetKind::Inline128 => {
434 counters.parser_token_set_inline_sets =
435 counters.parser_token_set_inline_sets.saturating_add(1);
436 counters.parser_token_set_inline_bytes =
437 counters.parser_token_set_inline_bytes.saturating_add(bytes);
438 }
439 ParserTokenSetKind::Dense => {
440 counters.parser_token_set_dense_sets =
441 counters.parser_token_set_dense_sets.saturating_add(1);
442 counters.parser_token_set_dense_bytes =
443 counters.parser_token_set_dense_bytes.saturating_add(bytes);
444 }
445 ParserTokenSetKind::Intervals => {
446 counters.parser_token_set_interval_sets =
447 counters.parser_token_set_interval_sets.saturating_add(1);
448 }
449 });
450}
451
452pub(crate) fn record_parser_token_set_probe(
453 kind: crate::atn::parser_atn::ParserTokenSetKind,
454 hit: bool,
455) {
456 use crate::atn::parser_atn::ParserTokenSetKind;
457
458 with_counters(|counters| {
459 match kind {
460 ParserTokenSetKind::Inline128 => record_hit(
461 hit,
462 &mut counters.parser_token_set_inline_hits,
463 &mut counters.parser_token_set_inline_misses,
464 ),
465 ParserTokenSetKind::Dense => record_hit(
466 hit,
467 &mut counters.parser_token_set_dense_hits,
468 &mut counters.parser_token_set_dense_misses,
469 ),
470 ParserTokenSetKind::Intervals => record_hit(
471 hit,
472 &mut counters.parser_token_set_interval_hits,
473 &mut counters.parser_token_set_interval_misses,
474 ),
475 }
476 let probe_counter = if kind == ParserTokenSetKind::Intervals {
477 &mut counters.parser_token_set_interval_binary_probes_retained
478 } else {
479 &mut counters.parser_token_set_interval_probes_eliminated
480 };
481 *probe_counter = probe_counter.saturating_add(1);
482 });
483}
484
485pub fn reset() {
486 COUNTERS.with(|counters| {
487 let mut counters = counters.borrow_mut();
488 let descriptors = (
491 counters.lexer_run_descriptors_none,
492 counters.lexer_run_descriptors_any,
493 counters.lexer_run_descriptors_until,
494 counters.lexer_range_descriptors,
495 counters.lexer_range_descriptor_classes,
496 counters.parser_token_set_inline_sets,
497 counters.parser_token_set_dense_sets,
498 counters.parser_token_set_interval_sets,
499 counters.parser_token_set_inline_bytes,
500 counters.parser_token_set_dense_bytes,
501 );
502 *counters = Counters::default();
503 counters.lexer_run_descriptors_none = descriptors.0;
504 counters.lexer_run_descriptors_any = descriptors.1;
505 counters.lexer_run_descriptors_until = descriptors.2;
506 counters.lexer_range_descriptors = descriptors.3;
507 counters.lexer_range_descriptor_classes = descriptors.4;
508 counters.parser_token_set_inline_sets = descriptors.5;
509 counters.parser_token_set_dense_sets = descriptors.6;
510 counters.parser_token_set_interval_sets = descriptors.7;
511 counters.parser_token_set_inline_bytes = descriptors.8;
512 counters.parser_token_set_dense_bytes = descriptors.9;
513 });
514}
515
516pub fn dump() {
517 COUNTERS.with(|counters| {
518 let counters = counters.borrow();
519 dump_totals(&counters);
520 dump_decisions(&counters);
521 });
522}
523
524fn dump_totals(counters: &Counters) {
525 for (name, value) in totals(counters) {
526 print_counter(name, value);
527 }
528}
529
530fn dump_decisions(counters: &Counters) {
531 for (decision, counters) in &counters.decisions {
532 print_decision_counter(*decision, "adaptive_calls", counters.adaptive_calls);
533 print_decision_counter(
534 *decision,
535 "forced_full_context_calls",
536 counters.forced_full_context_calls,
537 );
538 print_decision_counter(
539 *decision,
540 "full_context_retries",
541 counters.full_context_retries,
542 );
543 print_decision_counter(*decision, "sll_conflicts", counters.sll_conflicts);
544 }
545}
546
547const fn totals(counters: &Counters) -> [(&'static str, u64); 80] {
548 [
549 ("prediction.adaptive_calls", counters.adaptive_calls),
550 (
551 "prediction.forced_full_context_calls",
552 counters.forced_full_context_calls,
553 ),
554 (
555 "prediction.full_context_retries",
556 counters.full_context_retries,
557 ),
558 ("prediction.sll_conflicts", counters.sll_conflicts),
559 ("reach.sll_calls", counters.reach_sll_calls),
560 (
561 "reach.full_context_calls",
562 counters.reach_full_context_calls,
563 ),
564 ("reach.input_configs", counters.reach_input_configs),
565 ("reach.output_configs", counters.reach_output_configs),
566 ("reach.max_input_configs", counters.reach_max_input_configs),
567 (
568 "reach.max_output_configs",
569 counters.reach_max_output_configs,
570 ),
571 ("closure.calls", counters.closure_calls),
572 ("closure.visited_total", counters.closure_visited_total),
573 ("closure.visited_max", counters.closure_visited_max),
574 ("config.add_calls", counters.config_add_calls),
575 ("config.inserts", counters.config_inserts),
576 ("config.merges", counters.config_merges),
577 ("config.max_size", counters.config_max_size),
578 ("context_merge.calls", counters.context_merge_calls),
579 ("context_merge.identical", counters.context_merge_identical),
580 (
581 "context_merge.cache_hits",
582 counters.context_merge_cache_hits,
583 ),
584 (
585 "context_merge.cache_misses",
586 counters.context_merge_cache_misses,
587 ),
588 ("context_merge.uncached", counters.context_merge_uncached),
589 ("context_cache.calls", counters.context_cache_calls),
590 ("context_cache.hits", counters.context_cache_hits),
591 ("context_cache.misses", counters.context_cache_misses),
592 ("context_cache.inserts", counters.context_cache_inserts),
593 ("dfa.edge_lookups", counters.dfa_edge_lookups),
594 ("dfa.warm_hits", counters.dfa_edge_hits),
595 ("dfa.warm_misses", counters.dfa_edge_misses),
596 ("dfa.atn_fallbacks", counters.dfa_atn_fallbacks),
597 ("dfa.states_created", counters.dfa_states_created),
598 ("dfa.states_deduplicated", counters.dfa_states_deduplicated),
599 (
600 "dfa.fingerprint_candidates",
601 counters.dfa_fingerprint_candidates,
602 ),
603 (
604 "dfa.fingerprint_collisions",
605 counters.dfa_fingerprint_collisions,
606 ),
607 ("dfa_cache.imports", counters.dfa_cache_imports),
608 ("dfa_cache.import_nanos", counters.dfa_cache_import_nanos),
609 ("dfa_cache.import_states", counters.dfa_cache_import_states),
610 ("dfa_cache.publications", counters.dfa_cache_publications),
611 (
612 "dfa_cache.publication_nanos",
613 counters.dfa_cache_publication_nanos,
614 ),
615 (
616 "dfa_cache.publication_states",
617 counters.dfa_cache_publication_states,
618 ),
619 (
620 "lexer.direct_ascii_chars",
621 counters.lexer_direct_ascii_chars,
622 ),
623 ("lexer.generic_chars", counters.lexer_generic_chars),
624 (
625 "lexer.scalar_replay_chars",
626 counters.lexer_scalar_replay_chars,
627 ),
628 (
629 "lexer.bulk_committed_chars",
630 counters.lexer_bulk_committed_chars,
631 ),
632 (
633 "lexer.compiled_scalar_ascii_chars",
634 counters.lexer_compiled_scalar_ascii_chars,
635 ),
636 ("lexer.run_scan_calls", counters.lexer_run_scan_calls),
637 ("lexer.run_scan_bytes", counters.lexer_run_scan_bytes),
638 ("lexer.run_scan_exits", counters.lexer_run_scan_exits),
639 ("lexer.run_scan_ends", counters.lexer_run_scan_ends),
640 (
641 "lexer.run_rejected_states",
642 counters.lexer_run_rejected_states,
643 ),
644 (
645 "lexer.run_descriptors.none",
646 counters.lexer_run_descriptors_none,
647 ),
648 (
649 "lexer.run_descriptors.any",
650 counters.lexer_run_descriptors_any,
651 ),
652 (
653 "lexer.run_descriptors.until",
654 counters.lexer_run_descriptors_until,
655 ),
656 (
657 "lexer.range_descriptors.1",
658 counters.lexer_range_descriptors[0],
659 ),
660 (
661 "lexer.range_descriptors.2",
662 counters.lexer_range_descriptors[1],
663 ),
664 (
665 "lexer.range_descriptors.3",
666 counters.lexer_range_descriptors[2],
667 ),
668 (
669 "lexer.range_descriptors.4",
670 counters.lexer_range_descriptors[3],
671 ),
672 (
673 "lexer.range_descriptor_classes.identifier",
674 counters.lexer_range_descriptor_classes[0],
675 ),
676 (
677 "lexer.range_descriptor_classes.number",
678 counters.lexer_range_descriptor_classes[1],
679 ),
680 (
681 "lexer.range_descriptor_classes.whitespace",
682 counters.lexer_range_descriptor_classes[2],
683 ),
684 (
685 "lexer.range_descriptor_classes.other",
686 counters.lexer_range_descriptor_classes[3],
687 ),
688 (
689 "lexer.range_scalar_calls",
690 counters.lexer_range_scalar_calls,
691 ),
692 (
693 "lexer.range_scalar_bytes",
694 counters.lexer_range_scalar_bytes,
695 ),
696 (
697 "lexer.range_identifier_bytes",
698 counters.lexer_range_identifier_bytes,
699 ),
700 (
701 "lexer.range_number_bytes",
702 counters.lexer_range_number_bytes,
703 ),
704 (
705 "lexer.range_whitespace_bytes",
706 counters.lexer_range_whitespace_bytes,
707 ),
708 ("lexer.range_other_bytes", counters.lexer_range_other_bytes),
709 (
710 "parser.token_set.selection.inline128",
711 counters.parser_token_set_inline_sets,
712 ),
713 (
714 "parser.token_set.selection.dense",
715 counters.parser_token_set_dense_sets,
716 ),
717 (
718 "parser.token_set.selection.intervals",
719 counters.parser_token_set_interval_sets,
720 ),
721 (
722 "parser.token_set.inline_bytes",
723 counters.parser_token_set_inline_bytes,
724 ),
725 (
726 "parser.token_set.dense_bytes",
727 counters.parser_token_set_dense_bytes,
728 ),
729 (
730 "parser.token_set.inline_hits",
731 counters.parser_token_set_inline_hits,
732 ),
733 (
734 "parser.token_set.inline_misses",
735 counters.parser_token_set_inline_misses,
736 ),
737 (
738 "parser.token_set.dense_hits",
739 counters.parser_token_set_dense_hits,
740 ),
741 (
742 "parser.token_set.dense_misses",
743 counters.parser_token_set_dense_misses,
744 ),
745 (
746 "parser.token_set.interval_hits",
747 counters.parser_token_set_interval_hits,
748 ),
749 (
750 "parser.token_set.interval_misses",
751 counters.parser_token_set_interval_misses,
752 ),
753 (
754 "parser.token_set.interval_probes_eliminated",
755 counters.parser_token_set_interval_probes_eliminated,
756 ),
757 (
758 "parser.token_set.interval_binary_probes_retained",
759 counters.parser_token_set_interval_binary_probes_retained,
760 ),
761 ]
762}
763
764#[cfg(test)]
765pub(crate) fn lexer_snapshot() -> [u64; 4] {
766 COUNTERS.with(|counters| {
767 let counters = counters.borrow();
768 [
769 counters.lexer_direct_ascii_chars,
770 counters.lexer_generic_chars,
771 counters.lexer_scalar_replay_chars,
772 counters.lexer_bulk_committed_chars,
773 ]
774 })
775}
776
777#[cfg(test)]
778pub(crate) fn lexer_run_snapshot() -> [u64; 6] {
779 COUNTERS.with(|counters| {
780 let counters = counters.borrow();
781 [
782 counters.lexer_compiled_scalar_ascii_chars,
783 counters.lexer_run_scan_calls,
784 counters.lexer_run_scan_bytes,
785 counters.lexer_run_scan_exits,
786 counters.lexer_run_scan_ends,
787 counters.lexer_run_rejected_states,
788 ]
789 })
790}
791
792#[cfg(test)]
793pub(crate) fn lexer_range_descriptor_snapshot() -> [u64; 11] {
794 COUNTERS.with(|counters| {
795 let counters = counters.borrow();
796 [
797 counters.lexer_run_descriptors_none,
798 counters.lexer_run_descriptors_any,
799 counters.lexer_run_descriptors_until,
800 counters.lexer_range_descriptors[0],
801 counters.lexer_range_descriptors[1],
802 counters.lexer_range_descriptors[2],
803 counters.lexer_range_descriptors[3],
804 counters.lexer_range_descriptor_classes[0],
805 counters.lexer_range_descriptor_classes[1],
806 counters.lexer_range_descriptor_classes[2],
807 counters.lexer_range_descriptor_classes[3],
808 ]
809 })
810}
811
812#[cfg(test)]
813pub(crate) fn lexer_range_scan_snapshot() -> [u64; 6] {
814 COUNTERS.with(|counters| {
815 let counters = counters.borrow();
816 [
817 counters.lexer_range_scalar_calls,
818 counters.lexer_range_scalar_bytes,
819 counters.lexer_range_identifier_bytes,
820 counters.lexer_range_number_bytes,
821 counters.lexer_range_whitespace_bytes,
822 counters.lexer_range_other_bytes,
823 ]
824 })
825}
826
827#[cfg(test)]
828pub(crate) fn parser_token_set_snapshot() -> [u64; 13] {
829 COUNTERS.with(|counters| {
830 let counters = counters.borrow();
831 [
832 counters.parser_token_set_inline_sets,
833 counters.parser_token_set_dense_sets,
834 counters.parser_token_set_interval_sets,
835 counters.parser_token_set_inline_bytes,
836 counters.parser_token_set_dense_bytes,
837 counters.parser_token_set_inline_hits,
838 counters.parser_token_set_inline_misses,
839 counters.parser_token_set_dense_hits,
840 counters.parser_token_set_dense_misses,
841 counters.parser_token_set_interval_hits,
842 counters.parser_token_set_interval_misses,
843 counters.parser_token_set_interval_probes_eliminated,
844 counters.parser_token_set_interval_binary_probes_retained,
845 ]
846 })
847}
848
849fn print_counter(name: &str, value: u64) {
850 #[allow(clippy::print_stderr)]
851 {
852 eprintln!("perf {name}={value}");
853 }
854}
855
856fn print_decision_counter(decision: usize, name: &str, value: u64) {
857 #[allow(clippy::print_stderr)]
858 {
859 eprintln!("perf decision.{decision}.{name}={value}");
860 }
861}