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