Skip to main content

cqlib_core/compile/transform/rewrite/
diagnostics.rs

1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 2026
4//
5// This code is licensed under the Apache License, Version 2.0.
6// You may obtain a copy of this license in the LICENSE.txt file in the root directory
7// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8//
9// Any modifications or derivative works of this code must retain this
10// copyright notice, and modified files need to carry a notice indicating
11// that they have been altered from the originals.
12
13//! Rewrite work-avoidance and condition-evaluation diagnostics.
14
15/// Performance diagnostics produced by rewrite execution.
16///
17/// These counters describe which incremental and condition-evaluation paths
18/// were exercised. They never participate in rule selection or correctness
19/// decisions and are suitable for benchmark attribution.
20#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
21pub struct KnowledgeRewriteDiagnostics {
22    /// Rewrite phases skipped by a reusable session fixpoint proof.
23    pub direct_reuses: usize,
24    /// Anchors presented by verified dirty ranges before any density fallback.
25    pub dirty_anchors: usize,
26    /// Incremental executions conservatively promoted to full scans.
27    ///
28    /// This includes rejected or incompatible edit proofs, unsupported
29    /// circuit shapes, and dirty ranges exceeding the density threshold.
30    pub full_scan_fallbacks: usize,
31    /// Cached rule-condition results reused for identical parameter bindings.
32    pub condition_cache_hits: usize,
33    /// Cacheable rule-condition bindings not found in the pass-local cache.
34    pub condition_cache_misses: usize,
35    /// Conditions evaluated by the conservative symbolic path.
36    pub symbolic_fallbacks: usize,
37}
38
39impl KnowledgeRewriteDiagnostics {
40    pub(crate) fn merge(&mut self, other: Self) {
41        self.direct_reuses = self.direct_reuses.saturating_add(other.direct_reuses);
42        self.dirty_anchors = self.dirty_anchors.saturating_add(other.dirty_anchors);
43        self.full_scan_fallbacks = self
44            .full_scan_fallbacks
45            .saturating_add(other.full_scan_fallbacks);
46        self.condition_cache_hits = self
47            .condition_cache_hits
48            .saturating_add(other.condition_cache_hits);
49        self.condition_cache_misses = self
50            .condition_cache_misses
51            .saturating_add(other.condition_cache_misses);
52        self.symbolic_fallbacks = self
53            .symbolic_fallbacks
54            .saturating_add(other.symbolic_fallbacks);
55    }
56
57    pub(super) fn merge_matcher(&mut self, other: MatcherDiagnostics) {
58        self.merge(Self {
59            direct_reuses: 0,
60            dirty_anchors: other.dirty_anchors,
61            full_scan_fallbacks: other.full_scan_fallbacks,
62            condition_cache_hits: other.condition_cache_hits,
63            condition_cache_misses: other.condition_cache_misses,
64            symbolic_fallbacks: other.symbolic_fallbacks,
65        });
66    }
67}
68
69#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
70pub(super) struct MatcherDiagnostics {
71    pub(super) condition_cache_hits: usize,
72    pub(super) condition_cache_misses: usize,
73    pub(super) symbolic_fallbacks: usize,
74    pub(super) dirty_anchors: usize,
75    pub(super) full_scan_fallbacks: usize,
76}
77
78impl MatcherDiagnostics {
79    pub(super) fn saturating_delta(self, earlier: Self) -> Self {
80        Self {
81            condition_cache_hits: self
82                .condition_cache_hits
83                .saturating_sub(earlier.condition_cache_hits),
84            condition_cache_misses: self
85                .condition_cache_misses
86                .saturating_sub(earlier.condition_cache_misses),
87            symbolic_fallbacks: self
88                .symbolic_fallbacks
89                .saturating_sub(earlier.symbolic_fallbacks),
90            dirty_anchors: self.dirty_anchors.saturating_sub(earlier.dirty_anchors),
91            full_scan_fallbacks: self
92                .full_scan_fallbacks
93                .saturating_sub(earlier.full_scan_fallbacks),
94        }
95    }
96}