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