1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Internal timing split of the Hyperscan always-active prefilter mark path.
//!
//! `#67` ([`super::mark_stats`]) decomposed the `phase2:prefilter` leaf at the
//! CALL level and showed that on a credential-dense corpus ~99% of per-pattern
//! calls are HS-served. This module decomposes a single HS-served call's TIME
//! into its two halves, so the dominant sub-cost is identifiable:
//!
//! * **scan**: `HsScanner::scan_each_result`: one SIMD pass over the chunk
//! against the whole always-active pattern database (~2.7k patterns incl. the
//! unicode homoglyph classes), plus the marking callback for each hit.
//! * **dropped-host-loop**: the HS-incompatible patterns (those with `^`/`$`,
//! see `hs_prefilter_requires_host_regex`) each run their OWN whole-chunk
//! `regex::is_match` on EVERY HS mark call, unconditionally.
//!
//! If the split shows scan dominates, the lever is the HS database itself (the
//! homoglyph pattern burden), which is recall-critical and deep. If the dropped
//! loop is material, batching those patterns into one `RegexSet` is a localized,
//! recall-identical win. The decomposition exists so that choice is measured, not
//! guessed.
//!
//! Cost discipline: the timing is PROFILE-GATED. `Phase2AlwaysActivePrefilter`'s
//! caller only takes `Instant::now()` when the unified profiler is enabled (the
//! same gate the per-pattern profiler uses). When profiling is off this module
//! contributes nothing to the hot path. The counters are process-wide relaxed
//! atomics that sum across rayon workers, matching `POPULATE_PREFILTER_NS`.
use pct;
use ;
/// Nanoseconds spent in the HS SIMD scan + mark callback, summed across workers.
static HS_MARK_SCAN_NS: AtomicU64 = new;
/// Nanoseconds spent in the dropped HS-incompatible host-regex loop, summed
/// across workers.
static HS_MARK_DROPPED_NS: AtomicU64 = new;
/// Immutable view of the HS-mark timing split. Cumulative since the last
/// [`hs_mark_timing_reset`]. The derived helpers centralize the percentage
/// arithmetic the profiler would otherwise inline.
pub
/// Render the HS-mark timing split line the profiler prints beneath the mark
/// decomposition. Pure (no I/O) so the formatting is unit-testable.
///
/// Example:
/// `hs-mark: scan=8100.0 ms (96.7%) dropped-host-loop=280.0 ms (3.3%)`
pub
/// Add `ns` to the HS SIMD scan accumulator. Called only when profiling is on
/// (the caller gates the `Instant`), so the add is never on the unprofiled path.
pub
/// Add `ns` to the dropped host-loop accumulator.
pub
/// Snapshot the HS-mark timing split without resetting it.
pub
/// Reset the HS-mark timing accumulators (profiler warm-up and post-dump reset).
pub