Skip to main content

keyhog_profile/
metrics.rs

1use serde::{Deserialize, Serialize};
2
3/// Stable wire identifier for a metric recorded by `keyhog-profile`.
4#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
5#[serde(rename_all = "kebab-case")]
6#[repr(usize)]
7pub enum MetricId {
8    SourceAcquire = 0,
9    SourceWalk,
10    SourceRead,
11    Preprocess,
12    Phase1Triggers,
13    BackendDispatch,
14    HotPatterns,
15    ConfirmedPatterns,
16    Phase2Prefilter,
17    Phase2KeywordAc,
18    Phase2SharedAc,
19    Phase2AnchoredVerify,
20    Phase2WholeChunk,
21    GenericDetection,
22    Entropy,
23    MachineLearning,
24    Decode,
25    Suppression,
26    LiveVerification,
27    Reporting,
28    SourceQueueWait,
29    IncrementalLookup,
30    BackendSelect,
31    ResultMerge,
32    ScannerQueueWait,
33    InputBytes,
34    InputUnits,
35    WallTime,
36    ProcessCpuTime,
37    ResidentMemory,
38    VirtualMemory,
39    ProcessThreads,
40    Phase2PrefilterMarkCalls,
41    Phase2PrefilterGateSkips,
42    Phase2PrefilterPerPatternWork,
43    Phase2PrefilterHsServed,
44    Phase2PrefilterRegexsetServed,
45    DecodeParentChunks,
46    DecodeDerivedChunks,
47    DecodeExtractCalls,
48    DecodeExtractBytes,
49    GenericPrefilterCalls,
50    GenericKeywordLines,
51    GenericRegexCaptures,
52    GenericEmits,
53    MlBatchCalls,
54    MlBatchCandidates,
55    MlBatchCallsGe64,
56    MlBatchCandidatesGe64,
57    DecodeExtractNs,
58    GenericPrefilterNs,
59    GenericExtractNs,
60    Phase2PrefilterHsScanNs,
61    Phase2PrefilterDroppedHostNs,
62    MlFeatureNs,
63    MlScoreNs,
64    MlBatchSize,
65    DecodeDerivedBytes,
66    HardwareCycles,
67    HardwareInstructions,
68    HardwareCacheReferences,
69    HardwareCacheMisses,
70    HardwareBranchInstructions,
71    HardwareBranchMisses,
72    HardwareStalledCyclesFrontend,
73    HardwareStalledCyclesBackend,
74    SchedulerVoluntaryContextSwitches,
75    SchedulerInvoluntaryContextSwitches,
76    SchedulerCpuMigrations,
77    SchedulerDelayNs,
78    GpuDispatchCalls,
79    GpuUploadBytes,
80    GpuReadbackBytes,
81    GpuUploadNs,
82    GpuReadbackNs,
83    GpuSubmitToCompleteNs,
84    GpuKernelNs,
85    GpuQueueWaitNs,
86    GpuAllocCalls,
87    GpuAllocBytes,
88    GpuFreeBytes,
89    GpuCompileCalls,
90    GpuCompileNs,
91    GpuPipelineCacheHits,
92    GpuPipelineCacheMisses,
93    GpuFaults,
94    GpuRetries,
95    GpuRecoveries,
96    GpuResidualBatches,
97    GpuOverlapNs,
98    GpuResidentBytes,
99    GpuPeakResidentBytes,
100    AllocationCount,
101    DeallocationCount,
102    AllocationBytes,
103    DeallocationBytes,
104    AllocationLiveBytes,
105    AllocationPeakLiveBytes,
106    MinorFaults,
107    MajorFaults,
108    IoReadBytes,
109    IoWriteBytes,
110    IoReadSyscalls,
111    IoWriteSyscalls,
112    IoCancelledWriteBytes,
113    ResidentHighWaterBytes,
114    RetainedBufferBytes,
115    RetainedBufferPeakBytes,
116    NetworkBytesRead,
117    NetworkBytesWritten,
118    NetworkRequests,
119    NetworkRetries,
120    PageCacheColdObservations,
121    PageCacheWarmObservations,
122    PageCacheDirectObservations,
123    FsOpenLatencyNs,
124    FsReadLatencyNs,
125    FsMetadataLatencyNs,
126    NetworkLatencyNs,
127    AutorouteCalibration,
128    BoundaryScan,
129    DetectorLoad,
130    DetectorValidate,
131    ExecutionPackSelect,
132    ExecutionPackMap,
133    BackendAcquire,
134    BackendInit,
135    Teardown,
136}
137
138/// Stable identifier for a top-level production pipeline stage.
139#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
140#[serde(rename_all = "kebab-case")]
141#[repr(u8)]
142pub enum MacroStageId {
143    Acquire = 0,
144    Scan,
145    Resolve,
146    Verify,
147    Report,
148}
149
150impl MacroStageId {
151    /// Every macro-stage identifier in stable wire order.
152    pub const ALL: [Self; 5] = [
153        Self::Acquire,
154        Self::Scan,
155        Self::Resolve,
156        Self::Verify,
157        Self::Report,
158    ];
159
160    /// Stable text label used by profiles and operator reports.
161    pub const fn as_str(self) -> &'static str {
162        match self {
163            Self::Acquire => "acquire",
164            Self::Scan => "scan",
165            Self::Resolve => "resolve",
166            Self::Verify => "verify",
167            Self::Report => "report",
168        }
169    }
170}
171
172/// Type-safe identifier for an additive monotonic metric.
173#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
174#[serde(rename_all = "kebab-case")]
175#[repr(u8)]
176pub enum CounterId {
177    InputBytes = 0,
178    InputUnits,
179    ProcessCpuTime,
180    Phase2PrefilterMarkCalls,
181    Phase2PrefilterGateSkips,
182    Phase2PrefilterPerPatternWork,
183    Phase2PrefilterHsServed,
184    Phase2PrefilterRegexsetServed,
185    DecodeParentChunks,
186    DecodeDerivedChunks,
187    DecodeExtractCalls,
188    DecodeExtractBytes,
189    GenericPrefilterCalls,
190    GenericKeywordLines,
191    GenericRegexCaptures,
192    GenericEmits,
193    MlBatchCalls,
194    MlBatchCandidates,
195    MlBatchCallsGe64,
196    MlBatchCandidatesGe64,
197    DecodeExtractNs,
198    GenericPrefilterNs,
199    GenericExtractNs,
200    Phase2PrefilterHsScanNs,
201    Phase2PrefilterDroppedHostNs,
202    MlFeatureNs,
203    MlScoreNs,
204    DecodeDerivedBytes,
205    HardwareCycles,
206    HardwareInstructions,
207    HardwareCacheReferences,
208    HardwareCacheMisses,
209    HardwareBranchInstructions,
210    HardwareBranchMisses,
211    HardwareStalledCyclesFrontend,
212    HardwareStalledCyclesBackend,
213    SchedulerVoluntaryContextSwitches,
214    SchedulerInvoluntaryContextSwitches,
215    SchedulerCpuMigrations,
216    SchedulerDelayNs,
217    GpuDispatchCalls,
218    GpuUploadBytes,
219    GpuReadbackBytes,
220    GpuUploadNs,
221    GpuReadbackNs,
222    GpuSubmitToCompleteNs,
223    GpuKernelNs,
224    GpuQueueWaitNs,
225    GpuAllocCalls,
226    GpuAllocBytes,
227    GpuFreeBytes,
228    GpuCompileCalls,
229    GpuCompileNs,
230    GpuPipelineCacheHits,
231    GpuPipelineCacheMisses,
232    GpuFaults,
233    GpuRetries,
234    GpuRecoveries,
235    GpuResidualBatches,
236    GpuOverlapNs,
237    AllocationCount,
238    DeallocationCount,
239    AllocationBytes,
240    DeallocationBytes,
241    MinorFaults,
242    MajorFaults,
243    IoReadBytes,
244    IoWriteBytes,
245    IoReadSyscalls,
246    IoWriteSyscalls,
247    IoCancelledWriteBytes,
248    NetworkBytesRead,
249    NetworkBytesWritten,
250    NetworkRequests,
251    NetworkRetries,
252    PageCacheColdObservations,
253    PageCacheWarmObservations,
254    PageCacheDirectObservations,
255}
256
257impl CounterId {
258    pub const ALL: [Self; 78] = [
259        Self::InputBytes,
260        Self::InputUnits,
261        Self::ProcessCpuTime,
262        Self::Phase2PrefilterMarkCalls,
263        Self::Phase2PrefilterGateSkips,
264        Self::Phase2PrefilterPerPatternWork,
265        Self::Phase2PrefilterHsServed,
266        Self::Phase2PrefilterRegexsetServed,
267        Self::DecodeParentChunks,
268        Self::DecodeDerivedChunks,
269        Self::DecodeExtractCalls,
270        Self::DecodeExtractBytes,
271        Self::GenericPrefilterCalls,
272        Self::GenericKeywordLines,
273        Self::GenericRegexCaptures,
274        Self::GenericEmits,
275        Self::MlBatchCalls,
276        Self::MlBatchCandidates,
277        Self::MlBatchCallsGe64,
278        Self::MlBatchCandidatesGe64,
279        Self::DecodeExtractNs,
280        Self::GenericPrefilterNs,
281        Self::GenericExtractNs,
282        Self::Phase2PrefilterHsScanNs,
283        Self::Phase2PrefilterDroppedHostNs,
284        Self::MlFeatureNs,
285        Self::MlScoreNs,
286        Self::DecodeDerivedBytes,
287        Self::HardwareCycles,
288        Self::HardwareInstructions,
289        Self::HardwareCacheReferences,
290        Self::HardwareCacheMisses,
291        Self::HardwareBranchInstructions,
292        Self::HardwareBranchMisses,
293        Self::HardwareStalledCyclesFrontend,
294        Self::HardwareStalledCyclesBackend,
295        Self::SchedulerVoluntaryContextSwitches,
296        Self::SchedulerInvoluntaryContextSwitches,
297        Self::SchedulerCpuMigrations,
298        Self::SchedulerDelayNs,
299        Self::GpuDispatchCalls,
300        Self::GpuUploadBytes,
301        Self::GpuReadbackBytes,
302        Self::GpuUploadNs,
303        Self::GpuReadbackNs,
304        Self::GpuSubmitToCompleteNs,
305        Self::GpuKernelNs,
306        Self::GpuQueueWaitNs,
307        Self::GpuAllocCalls,
308        Self::GpuAllocBytes,
309        Self::GpuFreeBytes,
310        Self::GpuCompileCalls,
311        Self::GpuCompileNs,
312        Self::GpuPipelineCacheHits,
313        Self::GpuPipelineCacheMisses,
314        Self::GpuFaults,
315        Self::GpuRetries,
316        Self::GpuRecoveries,
317        Self::GpuResidualBatches,
318        Self::GpuOverlapNs,
319        Self::AllocationCount,
320        Self::DeallocationCount,
321        Self::AllocationBytes,
322        Self::DeallocationBytes,
323        Self::MinorFaults,
324        Self::MajorFaults,
325        Self::IoReadBytes,
326        Self::IoWriteBytes,
327        Self::IoReadSyscalls,
328        Self::IoWriteSyscalls,
329        Self::IoCancelledWriteBytes,
330        Self::NetworkBytesRead,
331        Self::NetworkBytesWritten,
332        Self::NetworkRequests,
333        Self::NetworkRetries,
334        Self::PageCacheColdObservations,
335        Self::PageCacheWarmObservations,
336        Self::PageCacheDirectObservations,
337    ];
338
339    pub const fn metric_id(self) -> MetricId {
340        match self {
341            Self::InputBytes => MetricId::InputBytes,
342            Self::InputUnits => MetricId::InputUnits,
343            Self::ProcessCpuTime => MetricId::ProcessCpuTime,
344            Self::Phase2PrefilterMarkCalls => MetricId::Phase2PrefilterMarkCalls,
345            Self::Phase2PrefilterGateSkips => MetricId::Phase2PrefilterGateSkips,
346            Self::Phase2PrefilterPerPatternWork => MetricId::Phase2PrefilterPerPatternWork,
347            Self::Phase2PrefilterHsServed => MetricId::Phase2PrefilterHsServed,
348            Self::Phase2PrefilterRegexsetServed => MetricId::Phase2PrefilterRegexsetServed,
349            Self::DecodeParentChunks => MetricId::DecodeParentChunks,
350            Self::DecodeDerivedChunks => MetricId::DecodeDerivedChunks,
351            Self::DecodeExtractCalls => MetricId::DecodeExtractCalls,
352            Self::DecodeExtractBytes => MetricId::DecodeExtractBytes,
353            Self::GenericPrefilterCalls => MetricId::GenericPrefilterCalls,
354            Self::GenericKeywordLines => MetricId::GenericKeywordLines,
355            Self::GenericRegexCaptures => MetricId::GenericRegexCaptures,
356            Self::GenericEmits => MetricId::GenericEmits,
357            Self::MlBatchCalls => MetricId::MlBatchCalls,
358            Self::MlBatchCandidates => MetricId::MlBatchCandidates,
359            Self::MlBatchCallsGe64 => MetricId::MlBatchCallsGe64,
360            Self::MlBatchCandidatesGe64 => MetricId::MlBatchCandidatesGe64,
361            Self::DecodeExtractNs => MetricId::DecodeExtractNs,
362            Self::GenericPrefilterNs => MetricId::GenericPrefilterNs,
363            Self::GenericExtractNs => MetricId::GenericExtractNs,
364            Self::Phase2PrefilterHsScanNs => MetricId::Phase2PrefilterHsScanNs,
365            Self::Phase2PrefilterDroppedHostNs => MetricId::Phase2PrefilterDroppedHostNs,
366            Self::MlFeatureNs => MetricId::MlFeatureNs,
367            Self::MlScoreNs => MetricId::MlScoreNs,
368            Self::DecodeDerivedBytes => MetricId::DecodeDerivedBytes,
369            Self::HardwareCycles => MetricId::HardwareCycles,
370            Self::HardwareInstructions => MetricId::HardwareInstructions,
371            Self::HardwareCacheReferences => MetricId::HardwareCacheReferences,
372            Self::HardwareCacheMisses => MetricId::HardwareCacheMisses,
373            Self::HardwareBranchInstructions => MetricId::HardwareBranchInstructions,
374            Self::HardwareBranchMisses => MetricId::HardwareBranchMisses,
375            Self::HardwareStalledCyclesFrontend => MetricId::HardwareStalledCyclesFrontend,
376            Self::HardwareStalledCyclesBackend => MetricId::HardwareStalledCyclesBackend,
377            Self::SchedulerVoluntaryContextSwitches => MetricId::SchedulerVoluntaryContextSwitches,
378            Self::SchedulerInvoluntaryContextSwitches => {
379                MetricId::SchedulerInvoluntaryContextSwitches
380            }
381            Self::SchedulerCpuMigrations => MetricId::SchedulerCpuMigrations,
382            Self::SchedulerDelayNs => MetricId::SchedulerDelayNs,
383            Self::GpuDispatchCalls => MetricId::GpuDispatchCalls,
384            Self::GpuUploadBytes => MetricId::GpuUploadBytes,
385            Self::GpuReadbackBytes => MetricId::GpuReadbackBytes,
386            Self::GpuUploadNs => MetricId::GpuUploadNs,
387            Self::GpuReadbackNs => MetricId::GpuReadbackNs,
388            Self::GpuSubmitToCompleteNs => MetricId::GpuSubmitToCompleteNs,
389            Self::GpuKernelNs => MetricId::GpuKernelNs,
390            Self::GpuQueueWaitNs => MetricId::GpuQueueWaitNs,
391            Self::GpuAllocCalls => MetricId::GpuAllocCalls,
392            Self::GpuAllocBytes => MetricId::GpuAllocBytes,
393            Self::GpuFreeBytes => MetricId::GpuFreeBytes,
394            Self::GpuCompileCalls => MetricId::GpuCompileCalls,
395            Self::GpuCompileNs => MetricId::GpuCompileNs,
396            Self::GpuPipelineCacheHits => MetricId::GpuPipelineCacheHits,
397            Self::GpuPipelineCacheMisses => MetricId::GpuPipelineCacheMisses,
398            Self::GpuFaults => MetricId::GpuFaults,
399            Self::GpuRetries => MetricId::GpuRetries,
400            Self::GpuRecoveries => MetricId::GpuRecoveries,
401            Self::GpuResidualBatches => MetricId::GpuResidualBatches,
402            Self::GpuOverlapNs => MetricId::GpuOverlapNs,
403            Self::AllocationCount => MetricId::AllocationCount,
404            Self::DeallocationCount => MetricId::DeallocationCount,
405            Self::AllocationBytes => MetricId::AllocationBytes,
406            Self::DeallocationBytes => MetricId::DeallocationBytes,
407            Self::MinorFaults => MetricId::MinorFaults,
408            Self::MajorFaults => MetricId::MajorFaults,
409            Self::IoReadBytes => MetricId::IoReadBytes,
410            Self::IoWriteBytes => MetricId::IoWriteBytes,
411            Self::IoReadSyscalls => MetricId::IoReadSyscalls,
412            Self::IoWriteSyscalls => MetricId::IoWriteSyscalls,
413            Self::IoCancelledWriteBytes => MetricId::IoCancelledWriteBytes,
414            Self::NetworkBytesRead => MetricId::NetworkBytesRead,
415            Self::NetworkBytesWritten => MetricId::NetworkBytesWritten,
416            Self::NetworkRequests => MetricId::NetworkRequests,
417            Self::NetworkRetries => MetricId::NetworkRetries,
418            Self::PageCacheColdObservations => MetricId::PageCacheColdObservations,
419            Self::PageCacheWarmObservations => MetricId::PageCacheWarmObservations,
420            Self::PageCacheDirectObservations => MetricId::PageCacheDirectObservations,
421        }
422    }
423}
424
425/// Type-safe identifier for a latest-value metric.
426#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
427#[serde(rename_all = "kebab-case")]
428#[repr(u8)]
429pub enum GaugeId {
430    ResidentMemory = 0,
431    VirtualMemory,
432    ProcessThreads,
433    GpuResidentBytes,
434    GpuPeakResidentBytes,
435    AllocationLiveBytes,
436    AllocationPeakLiveBytes,
437    ResidentHighWaterBytes,
438    RetainedBufferBytes,
439    RetainedBufferPeakBytes,
440}
441
442impl GaugeId {
443    pub const ALL: [Self; 10] = [
444        Self::ResidentMemory,
445        Self::VirtualMemory,
446        Self::ProcessThreads,
447        Self::GpuResidentBytes,
448        Self::GpuPeakResidentBytes,
449        Self::AllocationLiveBytes,
450        Self::AllocationPeakLiveBytes,
451        Self::ResidentHighWaterBytes,
452        Self::RetainedBufferBytes,
453        Self::RetainedBufferPeakBytes,
454    ];
455
456    pub const fn metric_id(self) -> MetricId {
457        match self {
458            Self::ResidentMemory => MetricId::ResidentMemory,
459            Self::VirtualMemory => MetricId::VirtualMemory,
460            Self::ProcessThreads => MetricId::ProcessThreads,
461            Self::GpuResidentBytes => MetricId::GpuResidentBytes,
462            Self::GpuPeakResidentBytes => MetricId::GpuPeakResidentBytes,
463            Self::AllocationLiveBytes => MetricId::AllocationLiveBytes,
464            Self::AllocationPeakLiveBytes => MetricId::AllocationPeakLiveBytes,
465            Self::ResidentHighWaterBytes => MetricId::ResidentHighWaterBytes,
466            Self::RetainedBufferBytes => MetricId::RetainedBufferBytes,
467            Self::RetainedBufferPeakBytes => MetricId::RetainedBufferPeakBytes,
468        }
469    }
470}
471
472/// Stable identifier for an instantaneous causal event.
473#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
474#[serde(rename_all = "kebab-case")]
475#[repr(u8)]
476pub enum EventId {
477    BackendBatchCompleted = 0,
478    BackendRecovered,
479    CoverageGap,
480    Interrupted,
481    DetailedDiagnostic,
482    GpuAdapterAcquired,
483    GpuFault,
484    GpuCapabilityUnsupported,
485}
486
487impl EventId {
488    pub const COUNT: usize = 8;
489
490    pub const fn index(self) -> usize {
491        self as usize
492    }
493}
494
495/// Bounded fixed set of queue slots for causality links and depth gauges.
496#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
497#[serde(rename_all = "kebab-case")]
498#[repr(u8)]
499pub enum QueueId {
500    SourceWork = 0,
501    ScannerWork,
502    DecoderWork,
503    BackendBatch,
504    LiveVerification,
505    ResultMerge,
506}
507
508impl QueueId {
509    /// Every queue slot in stable wire order.
510    pub const ALL: [Self; 6] = [
511        Self::SourceWork,
512        Self::ScannerWork,
513        Self::DecoderWork,
514        Self::BackendBatch,
515        Self::LiveVerification,
516        Self::ResultMerge,
517    ];
518
519    pub const COUNT: usize = 6;
520
521    pub const fn index(self) -> usize {
522        self as usize
523    }
524}
525
526/// A reuse cache the profiler reports hit and miss counts for.
527///
528/// Every KeyHog cache that exists to avoid repeating work reports through this
529/// one enum, so "what is our cache hit rate" has a single answer instead of one
530/// per subsystem. Record every consultation with exactly one of
531/// [`crate::record_cache_hit`] or [`crate::record_cache_miss`], so the reported
532/// rate has a real denominator.
533///
534/// Counters are indexed by [`CacheId::index`] into a fixed array of length
535/// [`CacheId::COUNT`], so recording is one relaxed atomic add with no
536/// allocation and no lookup on the hot path.
537#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
538#[serde(rename_all = "kebab-case")]
539#[repr(u8)]
540pub enum CacheId {
541    /// Persisted autoroute backend decision reused instead of re-deciding.
542    /// A miss means the scan runs without a calibrated route.
543    AutorouteDecision = 0,
544    /// Autoroute calibration measurement reused instead of re-measuring.
545    AutorouteCalibration,
546    /// Chunk skipped because the incremental scan judged it unchanged.
547    IncrementalUnchanged,
548    /// Compiled matcher artifact reused instead of recompiled. This is the
549    /// cache standing between a scan and the engine-initialization cost.
550    MatcherArtifact,
551    /// Credential verification result reused instead of re-requested. A miss
552    /// costs a network round trip, so this rate is also a rate-limit story.
553    VerifierResult,
554}
555
556impl CacheId {
557    /// Every cache slot in stable wire order.
558    pub const ALL: [Self; Self::COUNT] = [
559        Self::AutorouteDecision,
560        Self::AutorouteCalibration,
561        Self::IncrementalUnchanged,
562        Self::MatcherArtifact,
563        Self::VerifierResult,
564    ];
565
566    /// Number of variants, and the length of the profiler's counter arrays.
567    pub const COUNT: usize = 5;
568
569    /// Dense index into the profiler's per-shard counter arrays.
570    pub const fn index(self) -> usize {
571        self as usize
572    }
573
574    /// Stable text label used by profiles and operator reports.
575    pub const fn as_str(self) -> &'static str {
576        match self {
577            Self::AutorouteDecision => "autoroute-decision",
578            Self::AutorouteCalibration => "autoroute-calibration",
579            Self::IncrementalUnchanged => "incremental-unchanged",
580            Self::MatcherArtifact => "matcher-artifact",
581            Self::VerifierResult => "verifier-result",
582        }
583    }
584}
585
586/// Why one operation was attempted again.
587///
588/// A retry that fires is evidence of a defect, not a success, so every attempt
589/// is counted and surfaced. There is deliberately no catch-all cause: an
590/// unclassified failure is permanent and is not retried, which is what stops
591/// "it will just retry" from becoming a reason to ship a racy path.
592#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
593#[serde(rename_all = "kebab-case")]
594#[repr(u8)]
595pub enum RetryCause {
596    /// A syscall returned EINTR.
597    Interrupted = 0,
598    /// A syscall returned EAGAIN or EWOULDBLOCK.
599    WouldBlock,
600    /// ENOENT or ESTALE on a path the walker had already enumerated.
601    VanishedUnderWalk,
602    /// The file was replaced, truncated, or grown between the size decision
603    /// and the completion of the read.
604    SizeChangedUnderRead,
605    /// EBUSY, ETXTBSY, or a sharing violation.
606    Locked,
607    /// A 429 or an equivalent provider throttle.
608    RateLimited,
609    /// Connection reset, timeout, or name resolution failure.
610    Network,
611    /// A git pack was rewritten while it was being read.
612    PackRewritten,
613}
614
615impl RetryCause {
616    /// Every cause in stable wire order.
617    pub const ALL: [Self; Self::COUNT] = [
618        Self::Interrupted,
619        Self::WouldBlock,
620        Self::VanishedUnderWalk,
621        Self::SizeChangedUnderRead,
622        Self::Locked,
623        Self::RateLimited,
624        Self::Network,
625        Self::PackRewritten,
626    ];
627
628    pub const COUNT: usize = 8;
629
630    /// Dense index into the profiler's per-shard counter arrays.
631    pub const fn index(self) -> usize {
632        self as usize
633    }
634
635    /// Stable text label used by profiles and operator reports.
636    pub const fn as_str(self) -> &'static str {
637        match self {
638            Self::Interrupted => "interrupted",
639            Self::WouldBlock => "would-block",
640            Self::VanishedUnderWalk => "vanished-under-walk",
641            Self::SizeChangedUnderRead => "size-changed-under-read",
642            Self::Locked => "locked",
643            Self::RateLimited => "rate-limited",
644            Self::Network => "network",
645            Self::PackRewritten => "pack-rewritten",
646        }
647    }
648}
649
650/// Number of slots in every indexed counter family.
651///
652/// Fixed so recording is one relaxed add with no bounds negotiation. A slot
653/// outside the range is counted as dropped rather than folded into the last
654/// slot, because a misattributed measurement is worse than a missing one.
655pub const INDEXED_COUNTER_SLOTS: usize = 16;
656
657/// An additive counter that exists once per caller-owned slot.
658///
659/// The caller owns the labels. A decoder registry knows slot three is base64,
660/// so the profiler stores sixteen numbers and never a string, which is what
661/// keeps the record path allocation-free and hash-free.
662#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
663#[serde(rename_all = "kebab-case")]
664#[repr(u8)]
665pub enum IndexedCounterId {
666    /// Nanoseconds spent inside one decoder slot.
667    DecoderElapsedNs = 0,
668    /// Sub-chunks one decoder slot produced.
669    DecoderSubchunksEmitted,
670}
671
672impl IndexedCounterId {
673    /// Every indexed family in stable wire order.
674    pub const ALL: [Self; Self::COUNT] = [Self::DecoderElapsedNs, Self::DecoderSubchunksEmitted];
675
676    pub const COUNT: usize = 2;
677
678    pub const fn index(self) -> usize {
679        self as usize
680    }
681
682    /// Stable text label used by profiles and operator reports.
683    pub const fn as_str(self) -> &'static str {
684        match self {
685            Self::DecoderElapsedNs => "decoder-elapsed-ns",
686            Self::DecoderSubchunksEmitted => "decoder-subchunks-emitted",
687        }
688    }
689}
690
691/// Stable identifier for a numeric annotation attached to the run timeline.
692#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
693#[serde(rename_all = "kebab-case")]
694#[repr(u8)]
695pub enum AnnotationId {
696    DecodeDepth = 0,
697    QueueDepth,
698    WorkerIndex,
699    RetryAttempt,
700    GpuBackendKind,
701    GpuAdapterVendor,
702    GpuAdapterDevice,
703    IoCacheState,
704}
705
706impl From<crate::Stage> for MetricId {
707    fn from(stage: crate::Stage) -> Self {
708        match stage {
709            crate::Stage::SourceAcquire => Self::SourceAcquire,
710            crate::Stage::SourceWalk => Self::SourceWalk,
711            crate::Stage::SourceRead => Self::SourceRead,
712            crate::Stage::Preprocess => Self::Preprocess,
713            crate::Stage::Phase1Triggers => Self::Phase1Triggers,
714            crate::Stage::BackendDispatch => Self::BackendDispatch,
715            crate::Stage::HotPatterns => Self::HotPatterns,
716            crate::Stage::ConfirmedPatterns => Self::ConfirmedPatterns,
717            crate::Stage::Phase2Prefilter => Self::Phase2Prefilter,
718            crate::Stage::Phase2KeywordAc => Self::Phase2KeywordAc,
719            crate::Stage::Phase2SharedAc => Self::Phase2SharedAc,
720            crate::Stage::Phase2AnchoredVerify => Self::Phase2AnchoredVerify,
721            crate::Stage::Phase2WholeChunk => Self::Phase2WholeChunk,
722            crate::Stage::GenericDetection => Self::GenericDetection,
723            crate::Stage::Entropy => Self::Entropy,
724            crate::Stage::MachineLearning => Self::MachineLearning,
725            crate::Stage::Decode => Self::Decode,
726            crate::Stage::Suppression => Self::Suppression,
727            crate::Stage::LiveVerification => Self::LiveVerification,
728            crate::Stage::Reporting => Self::Reporting,
729            crate::Stage::SourceQueueWait => Self::SourceQueueWait,
730            crate::Stage::IncrementalLookup => Self::IncrementalLookup,
731            crate::Stage::BackendSelect => Self::BackendSelect,
732            crate::Stage::ResultMerge => Self::ResultMerge,
733            crate::Stage::ScannerQueueWait => Self::ScannerQueueWait,
734            crate::Stage::AutorouteCalibration => Self::AutorouteCalibration,
735            crate::Stage::BoundaryScan => Self::BoundaryScan,
736            crate::Stage::DetectorLoad => Self::DetectorLoad,
737            crate::Stage::DetectorValidate => Self::DetectorValidate,
738            crate::Stage::ExecutionPackSelect => Self::ExecutionPackSelect,
739            crate::Stage::ExecutionPackMap => Self::ExecutionPackMap,
740            crate::Stage::BackendAcquire => Self::BackendAcquire,
741            crate::Stage::BackendInit => Self::BackendInit,
742            crate::Stage::Teardown => Self::Teardown,
743        }
744    }
745}
746
747/// Measurement behavior associated with a metric.
748#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)]
749pub enum MetricKind {
750    Counter,
751    Duration,
752    Gauge,
753    Distribution,
754}
755
756/// Stable unit associated with a metric value.
757#[derive(Clone, Copy, Debug, Eq, PartialEq)]
758pub enum MetricUnit {
759    Bytes,
760    Count,
761    Milliseconds,
762    Nanoseconds,
763}
764
765/// Static metric metadata. Every string is embedded in the binary.
766#[derive(Clone, Copy, Debug, Eq, PartialEq)]
767pub struct MetricDescriptor {
768    pub id: MetricId,
769    pub name: &'static str,
770    pub kind: MetricKind,
771    pub unit: MetricUnit,
772}
773
774const fn metric(
775    id: MetricId,
776    name: &'static str,
777    kind: MetricKind,
778    unit: MetricUnit,
779) -> MetricDescriptor {
780    MetricDescriptor {
781        id,
782        name,
783        kind,
784        unit,
785    }
786}
787
788/// Allocation-free registry in numeric `MetricId` order.
789pub static METRICS: [MetricDescriptor; MetricId::COUNT] = [
790    metric(
791        MetricId::SourceAcquire,
792        "source-acquire",
793        MetricKind::Duration,
794        MetricUnit::Nanoseconds,
795    ),
796    metric(
797        MetricId::SourceWalk,
798        "source-walk",
799        MetricKind::Duration,
800        MetricUnit::Nanoseconds,
801    ),
802    metric(
803        MetricId::SourceRead,
804        "source-read",
805        MetricKind::Duration,
806        MetricUnit::Nanoseconds,
807    ),
808    metric(
809        MetricId::Preprocess,
810        "preprocess",
811        MetricKind::Duration,
812        MetricUnit::Nanoseconds,
813    ),
814    metric(
815        MetricId::Phase1Triggers,
816        "phase1-triggers",
817        MetricKind::Duration,
818        MetricUnit::Nanoseconds,
819    ),
820    metric(
821        MetricId::BackendDispatch,
822        "backend-dispatch",
823        MetricKind::Duration,
824        MetricUnit::Nanoseconds,
825    ),
826    metric(
827        MetricId::HotPatterns,
828        "hot-patterns",
829        MetricKind::Duration,
830        MetricUnit::Nanoseconds,
831    ),
832    metric(
833        MetricId::ConfirmedPatterns,
834        "confirmed-patterns",
835        MetricKind::Duration,
836        MetricUnit::Nanoseconds,
837    ),
838    metric(
839        MetricId::Phase2Prefilter,
840        "phase2-prefilter",
841        MetricKind::Duration,
842        MetricUnit::Nanoseconds,
843    ),
844    metric(
845        MetricId::Phase2KeywordAc,
846        "phase2-keyword-ac",
847        MetricKind::Duration,
848        MetricUnit::Nanoseconds,
849    ),
850    metric(
851        MetricId::Phase2SharedAc,
852        "phase2-shared-ac",
853        MetricKind::Duration,
854        MetricUnit::Nanoseconds,
855    ),
856    metric(
857        MetricId::Phase2AnchoredVerify,
858        "phase2-anchored-verify",
859        MetricKind::Duration,
860        MetricUnit::Nanoseconds,
861    ),
862    metric(
863        MetricId::Phase2WholeChunk,
864        "phase2-whole-chunk",
865        MetricKind::Duration,
866        MetricUnit::Nanoseconds,
867    ),
868    metric(
869        MetricId::GenericDetection,
870        "generic-detection",
871        MetricKind::Duration,
872        MetricUnit::Nanoseconds,
873    ),
874    metric(
875        MetricId::Entropy,
876        "entropy",
877        MetricKind::Duration,
878        MetricUnit::Nanoseconds,
879    ),
880    metric(
881        MetricId::MachineLearning,
882        "machine-learning",
883        MetricKind::Duration,
884        MetricUnit::Nanoseconds,
885    ),
886    metric(
887        MetricId::Decode,
888        "decode",
889        MetricKind::Duration,
890        MetricUnit::Nanoseconds,
891    ),
892    metric(
893        MetricId::Suppression,
894        "suppression",
895        MetricKind::Duration,
896        MetricUnit::Nanoseconds,
897    ),
898    metric(
899        MetricId::LiveVerification,
900        "live-verification",
901        MetricKind::Duration,
902        MetricUnit::Nanoseconds,
903    ),
904    metric(
905        MetricId::Reporting,
906        "reporting",
907        MetricKind::Duration,
908        MetricUnit::Nanoseconds,
909    ),
910    metric(
911        MetricId::SourceQueueWait,
912        "source-queue-wait",
913        MetricKind::Duration,
914        MetricUnit::Nanoseconds,
915    ),
916    metric(
917        MetricId::IncrementalLookup,
918        "incremental-lookup",
919        MetricKind::Duration,
920        MetricUnit::Nanoseconds,
921    ),
922    metric(
923        MetricId::BackendSelect,
924        "backend-select",
925        MetricKind::Duration,
926        MetricUnit::Nanoseconds,
927    ),
928    metric(
929        MetricId::ResultMerge,
930        "result-merge",
931        MetricKind::Duration,
932        MetricUnit::Nanoseconds,
933    ),
934    metric(
935        MetricId::ScannerQueueWait,
936        "scanner-queue-wait",
937        MetricKind::Duration,
938        MetricUnit::Nanoseconds,
939    ),
940    metric(
941        MetricId::InputBytes,
942        "input-bytes",
943        MetricKind::Counter,
944        MetricUnit::Bytes,
945    ),
946    metric(
947        MetricId::InputUnits,
948        "input-units",
949        MetricKind::Counter,
950        MetricUnit::Count,
951    ),
952    metric(
953        MetricId::WallTime,
954        "wall-time",
955        MetricKind::Duration,
956        MetricUnit::Nanoseconds,
957    ),
958    metric(
959        MetricId::ProcessCpuTime,
960        "process-cpu-time",
961        MetricKind::Counter,
962        MetricUnit::Milliseconds,
963    ),
964    metric(
965        MetricId::ResidentMemory,
966        "resident-memory",
967        MetricKind::Gauge,
968        MetricUnit::Bytes,
969    ),
970    metric(
971        MetricId::VirtualMemory,
972        "virtual-memory",
973        MetricKind::Gauge,
974        MetricUnit::Bytes,
975    ),
976    metric(
977        MetricId::ProcessThreads,
978        "process-threads",
979        MetricKind::Gauge,
980        MetricUnit::Count,
981    ),
982    metric(
983        MetricId::Phase2PrefilterMarkCalls,
984        "phase2-prefilter-mark-calls",
985        MetricKind::Counter,
986        MetricUnit::Count,
987    ),
988    metric(
989        MetricId::Phase2PrefilterGateSkips,
990        "phase2-prefilter-gate-skips",
991        MetricKind::Counter,
992        MetricUnit::Count,
993    ),
994    metric(
995        MetricId::Phase2PrefilterPerPatternWork,
996        "phase2-prefilter-per-pattern-work",
997        MetricKind::Counter,
998        MetricUnit::Count,
999    ),
1000    metric(
1001        MetricId::Phase2PrefilterHsServed,
1002        "phase2-prefilter-hs-served",
1003        MetricKind::Counter,
1004        MetricUnit::Count,
1005    ),
1006    metric(
1007        MetricId::Phase2PrefilterRegexsetServed,
1008        "phase2-prefilter-regexset-served",
1009        MetricKind::Counter,
1010        MetricUnit::Count,
1011    ),
1012    metric(
1013        MetricId::DecodeParentChunks,
1014        "decode-parent-chunks",
1015        MetricKind::Counter,
1016        MetricUnit::Count,
1017    ),
1018    metric(
1019        MetricId::DecodeDerivedChunks,
1020        "decode-derived-chunks",
1021        MetricKind::Counter,
1022        MetricUnit::Count,
1023    ),
1024    metric(
1025        MetricId::DecodeExtractCalls,
1026        "decode-extract-calls",
1027        MetricKind::Counter,
1028        MetricUnit::Count,
1029    ),
1030    metric(
1031        MetricId::DecodeExtractBytes,
1032        "decode-extract-bytes",
1033        MetricKind::Counter,
1034        MetricUnit::Bytes,
1035    ),
1036    metric(
1037        MetricId::GenericPrefilterCalls,
1038        "generic-prefilter-calls",
1039        MetricKind::Counter,
1040        MetricUnit::Count,
1041    ),
1042    metric(
1043        MetricId::GenericKeywordLines,
1044        "generic-keyword-lines",
1045        MetricKind::Counter,
1046        MetricUnit::Count,
1047    ),
1048    metric(
1049        MetricId::GenericRegexCaptures,
1050        "generic-regex-captures",
1051        MetricKind::Counter,
1052        MetricUnit::Count,
1053    ),
1054    metric(
1055        MetricId::GenericEmits,
1056        "generic-emits",
1057        MetricKind::Counter,
1058        MetricUnit::Count,
1059    ),
1060    metric(
1061        MetricId::MlBatchCalls,
1062        "ml-batch-calls",
1063        MetricKind::Counter,
1064        MetricUnit::Count,
1065    ),
1066    metric(
1067        MetricId::MlBatchCandidates,
1068        "ml-batch-candidates",
1069        MetricKind::Counter,
1070        MetricUnit::Count,
1071    ),
1072    metric(
1073        MetricId::MlBatchCallsGe64,
1074        "ml-batch-calls-ge64",
1075        MetricKind::Counter,
1076        MetricUnit::Count,
1077    ),
1078    metric(
1079        MetricId::MlBatchCandidatesGe64,
1080        "ml-batch-candidates-ge64",
1081        MetricKind::Counter,
1082        MetricUnit::Count,
1083    ),
1084    metric(
1085        MetricId::DecodeExtractNs,
1086        "decode-extract-ns",
1087        MetricKind::Counter,
1088        MetricUnit::Nanoseconds,
1089    ),
1090    metric(
1091        MetricId::GenericPrefilterNs,
1092        "generic-prefilter-ns",
1093        MetricKind::Counter,
1094        MetricUnit::Nanoseconds,
1095    ),
1096    metric(
1097        MetricId::GenericExtractNs,
1098        "generic-extract-ns",
1099        MetricKind::Counter,
1100        MetricUnit::Nanoseconds,
1101    ),
1102    metric(
1103        MetricId::Phase2PrefilterHsScanNs,
1104        "phase2-prefilter-hs-scan-ns",
1105        MetricKind::Counter,
1106        MetricUnit::Nanoseconds,
1107    ),
1108    metric(
1109        MetricId::Phase2PrefilterDroppedHostNs,
1110        "phase2-prefilter-dropped-host-ns",
1111        MetricKind::Counter,
1112        MetricUnit::Nanoseconds,
1113    ),
1114    metric(
1115        MetricId::MlFeatureNs,
1116        "ml-feature-ns",
1117        MetricKind::Counter,
1118        MetricUnit::Nanoseconds,
1119    ),
1120    metric(
1121        MetricId::MlScoreNs,
1122        "ml-score-ns",
1123        MetricKind::Counter,
1124        MetricUnit::Nanoseconds,
1125    ),
1126    metric(
1127        MetricId::MlBatchSize,
1128        "ml-batch-size",
1129        MetricKind::Distribution,
1130        MetricUnit::Count,
1131    ),
1132    metric(
1133        MetricId::DecodeDerivedBytes,
1134        "decode-derived-bytes",
1135        MetricKind::Counter,
1136        MetricUnit::Bytes,
1137    ),
1138    metric(
1139        MetricId::HardwareCycles,
1140        "hardware-cycles",
1141        MetricKind::Counter,
1142        MetricUnit::Count,
1143    ),
1144    metric(
1145        MetricId::HardwareInstructions,
1146        "hardware-instructions",
1147        MetricKind::Counter,
1148        MetricUnit::Count,
1149    ),
1150    metric(
1151        MetricId::HardwareCacheReferences,
1152        "hardware-cache-references",
1153        MetricKind::Counter,
1154        MetricUnit::Count,
1155    ),
1156    metric(
1157        MetricId::HardwareCacheMisses,
1158        "hardware-cache-misses",
1159        MetricKind::Counter,
1160        MetricUnit::Count,
1161    ),
1162    metric(
1163        MetricId::HardwareBranchInstructions,
1164        "hardware-branch-instructions",
1165        MetricKind::Counter,
1166        MetricUnit::Count,
1167    ),
1168    metric(
1169        MetricId::HardwareBranchMisses,
1170        "hardware-branch-misses",
1171        MetricKind::Counter,
1172        MetricUnit::Count,
1173    ),
1174    metric(
1175        MetricId::HardwareStalledCyclesFrontend,
1176        "hardware-stalled-cycles-frontend",
1177        MetricKind::Counter,
1178        MetricUnit::Count,
1179    ),
1180    metric(
1181        MetricId::HardwareStalledCyclesBackend,
1182        "hardware-stalled-cycles-backend",
1183        MetricKind::Counter,
1184        MetricUnit::Count,
1185    ),
1186    metric(
1187        MetricId::SchedulerVoluntaryContextSwitches,
1188        "scheduler-voluntary-context-switches",
1189        MetricKind::Counter,
1190        MetricUnit::Count,
1191    ),
1192    metric(
1193        MetricId::SchedulerInvoluntaryContextSwitches,
1194        "scheduler-involuntary-context-switches",
1195        MetricKind::Counter,
1196        MetricUnit::Count,
1197    ),
1198    metric(
1199        MetricId::SchedulerCpuMigrations,
1200        "scheduler-cpu-migrations",
1201        MetricKind::Counter,
1202        MetricUnit::Count,
1203    ),
1204    metric(
1205        MetricId::SchedulerDelayNs,
1206        "scheduler-delay-ns",
1207        MetricKind::Counter,
1208        MetricUnit::Nanoseconds,
1209    ),
1210    metric(
1211        MetricId::GpuDispatchCalls,
1212        "gpu-dispatch-calls",
1213        MetricKind::Counter,
1214        MetricUnit::Count,
1215    ),
1216    metric(
1217        MetricId::GpuUploadBytes,
1218        "gpu-upload-bytes",
1219        MetricKind::Counter,
1220        MetricUnit::Bytes,
1221    ),
1222    metric(
1223        MetricId::GpuReadbackBytes,
1224        "gpu-readback-bytes",
1225        MetricKind::Counter,
1226        MetricUnit::Bytes,
1227    ),
1228    metric(
1229        MetricId::GpuUploadNs,
1230        "gpu-upload-ns",
1231        MetricKind::Counter,
1232        MetricUnit::Nanoseconds,
1233    ),
1234    metric(
1235        MetricId::GpuReadbackNs,
1236        "gpu-readback-ns",
1237        MetricKind::Counter,
1238        MetricUnit::Nanoseconds,
1239    ),
1240    metric(
1241        MetricId::GpuSubmitToCompleteNs,
1242        "gpu-submit-to-complete-ns",
1243        MetricKind::Counter,
1244        MetricUnit::Nanoseconds,
1245    ),
1246    metric(
1247        MetricId::GpuKernelNs,
1248        "gpu-kernel-ns",
1249        MetricKind::Counter,
1250        MetricUnit::Nanoseconds,
1251    ),
1252    metric(
1253        MetricId::GpuQueueWaitNs,
1254        "gpu-queue-wait-ns",
1255        MetricKind::Counter,
1256        MetricUnit::Nanoseconds,
1257    ),
1258    metric(
1259        MetricId::GpuAllocCalls,
1260        "gpu-alloc-calls",
1261        MetricKind::Counter,
1262        MetricUnit::Count,
1263    ),
1264    metric(
1265        MetricId::GpuAllocBytes,
1266        "gpu-alloc-bytes",
1267        MetricKind::Counter,
1268        MetricUnit::Bytes,
1269    ),
1270    metric(
1271        MetricId::GpuFreeBytes,
1272        "gpu-free-bytes",
1273        MetricKind::Counter,
1274        MetricUnit::Bytes,
1275    ),
1276    metric(
1277        MetricId::GpuCompileCalls,
1278        "gpu-compile-calls",
1279        MetricKind::Counter,
1280        MetricUnit::Count,
1281    ),
1282    metric(
1283        MetricId::GpuCompileNs,
1284        "gpu-compile-ns",
1285        MetricKind::Counter,
1286        MetricUnit::Nanoseconds,
1287    ),
1288    metric(
1289        MetricId::GpuPipelineCacheHits,
1290        "gpu-pipeline-cache-hits",
1291        MetricKind::Counter,
1292        MetricUnit::Count,
1293    ),
1294    metric(
1295        MetricId::GpuPipelineCacheMisses,
1296        "gpu-pipeline-cache-misses",
1297        MetricKind::Counter,
1298        MetricUnit::Count,
1299    ),
1300    metric(
1301        MetricId::GpuFaults,
1302        "gpu-faults",
1303        MetricKind::Counter,
1304        MetricUnit::Count,
1305    ),
1306    metric(
1307        MetricId::GpuRetries,
1308        "gpu-retries",
1309        MetricKind::Counter,
1310        MetricUnit::Count,
1311    ),
1312    metric(
1313        MetricId::GpuRecoveries,
1314        "gpu-recoveries",
1315        MetricKind::Counter,
1316        MetricUnit::Count,
1317    ),
1318    metric(
1319        MetricId::GpuResidualBatches,
1320        "gpu-residual-batches",
1321        MetricKind::Counter,
1322        MetricUnit::Count,
1323    ),
1324    metric(
1325        MetricId::GpuOverlapNs,
1326        "gpu-overlap-ns",
1327        MetricKind::Counter,
1328        MetricUnit::Nanoseconds,
1329    ),
1330    metric(
1331        MetricId::GpuResidentBytes,
1332        "gpu-resident-bytes",
1333        MetricKind::Gauge,
1334        MetricUnit::Bytes,
1335    ),
1336    metric(
1337        MetricId::GpuPeakResidentBytes,
1338        "gpu-peak-resident-bytes",
1339        MetricKind::Gauge,
1340        MetricUnit::Bytes,
1341    ),
1342    metric(
1343        MetricId::AllocationCount,
1344        "allocation-count",
1345        MetricKind::Counter,
1346        MetricUnit::Count,
1347    ),
1348    metric(
1349        MetricId::DeallocationCount,
1350        "deallocation-count",
1351        MetricKind::Counter,
1352        MetricUnit::Count,
1353    ),
1354    metric(
1355        MetricId::AllocationBytes,
1356        "allocation-bytes",
1357        MetricKind::Counter,
1358        MetricUnit::Bytes,
1359    ),
1360    metric(
1361        MetricId::DeallocationBytes,
1362        "deallocation-bytes",
1363        MetricKind::Counter,
1364        MetricUnit::Bytes,
1365    ),
1366    metric(
1367        MetricId::AllocationLiveBytes,
1368        "allocation-live-bytes",
1369        MetricKind::Gauge,
1370        MetricUnit::Bytes,
1371    ),
1372    metric(
1373        MetricId::AllocationPeakLiveBytes,
1374        "allocation-peak-live-bytes",
1375        MetricKind::Gauge,
1376        MetricUnit::Bytes,
1377    ),
1378    metric(
1379        MetricId::MinorFaults,
1380        "minor-faults",
1381        MetricKind::Counter,
1382        MetricUnit::Count,
1383    ),
1384    metric(
1385        MetricId::MajorFaults,
1386        "major-faults",
1387        MetricKind::Counter,
1388        MetricUnit::Count,
1389    ),
1390    metric(
1391        MetricId::IoReadBytes,
1392        "io-read-bytes",
1393        MetricKind::Counter,
1394        MetricUnit::Bytes,
1395    ),
1396    metric(
1397        MetricId::IoWriteBytes,
1398        "io-write-bytes",
1399        MetricKind::Counter,
1400        MetricUnit::Bytes,
1401    ),
1402    metric(
1403        MetricId::IoReadSyscalls,
1404        "io-read-syscalls",
1405        MetricKind::Counter,
1406        MetricUnit::Count,
1407    ),
1408    metric(
1409        MetricId::IoWriteSyscalls,
1410        "io-write-syscalls",
1411        MetricKind::Counter,
1412        MetricUnit::Count,
1413    ),
1414    metric(
1415        MetricId::IoCancelledWriteBytes,
1416        "io-cancelled-write-bytes",
1417        MetricKind::Counter,
1418        MetricUnit::Bytes,
1419    ),
1420    metric(
1421        MetricId::ResidentHighWaterBytes,
1422        "resident-high-water-bytes",
1423        MetricKind::Gauge,
1424        MetricUnit::Bytes,
1425    ),
1426    metric(
1427        MetricId::RetainedBufferBytes,
1428        "retained-buffer-bytes",
1429        MetricKind::Gauge,
1430        MetricUnit::Bytes,
1431    ),
1432    metric(
1433        MetricId::RetainedBufferPeakBytes,
1434        "retained-buffer-peak-bytes",
1435        MetricKind::Gauge,
1436        MetricUnit::Bytes,
1437    ),
1438    metric(
1439        MetricId::NetworkBytesRead,
1440        "network-bytes-read",
1441        MetricKind::Counter,
1442        MetricUnit::Bytes,
1443    ),
1444    metric(
1445        MetricId::NetworkBytesWritten,
1446        "network-bytes-written",
1447        MetricKind::Counter,
1448        MetricUnit::Bytes,
1449    ),
1450    metric(
1451        MetricId::NetworkRequests,
1452        "network-requests",
1453        MetricKind::Counter,
1454        MetricUnit::Count,
1455    ),
1456    metric(
1457        MetricId::NetworkRetries,
1458        "network-retries",
1459        MetricKind::Counter,
1460        MetricUnit::Count,
1461    ),
1462    metric(
1463        MetricId::PageCacheColdObservations,
1464        "page-cache-cold-observations",
1465        MetricKind::Counter,
1466        MetricUnit::Count,
1467    ),
1468    metric(
1469        MetricId::PageCacheWarmObservations,
1470        "page-cache-warm-observations",
1471        MetricKind::Counter,
1472        MetricUnit::Count,
1473    ),
1474    metric(
1475        MetricId::PageCacheDirectObservations,
1476        "page-cache-direct-observations",
1477        MetricKind::Counter,
1478        MetricUnit::Count,
1479    ),
1480    metric(
1481        MetricId::FsOpenLatencyNs,
1482        "fs-open-latency-ns",
1483        MetricKind::Distribution,
1484        MetricUnit::Nanoseconds,
1485    ),
1486    metric(
1487        MetricId::FsReadLatencyNs,
1488        "fs-read-latency-ns",
1489        MetricKind::Distribution,
1490        MetricUnit::Nanoseconds,
1491    ),
1492    metric(
1493        MetricId::FsMetadataLatencyNs,
1494        "fs-metadata-latency-ns",
1495        MetricKind::Distribution,
1496        MetricUnit::Nanoseconds,
1497    ),
1498    metric(
1499        MetricId::NetworkLatencyNs,
1500        "network-latency-ns",
1501        MetricKind::Distribution,
1502        MetricUnit::Nanoseconds,
1503    ),
1504    metric(
1505        MetricId::AutorouteCalibration,
1506        "autoroute-calibration",
1507        MetricKind::Duration,
1508        MetricUnit::Nanoseconds,
1509    ),
1510    metric(
1511        MetricId::BoundaryScan,
1512        "boundary-scan",
1513        MetricKind::Duration,
1514        MetricUnit::Nanoseconds,
1515    ),
1516    metric(
1517        MetricId::DetectorLoad,
1518        "detector-load",
1519        MetricKind::Duration,
1520        MetricUnit::Nanoseconds,
1521    ),
1522    metric(
1523        MetricId::DetectorValidate,
1524        "detector-validate",
1525        MetricKind::Duration,
1526        MetricUnit::Nanoseconds,
1527    ),
1528    metric(
1529        MetricId::ExecutionPackSelect,
1530        "execution-pack-select",
1531        MetricKind::Duration,
1532        MetricUnit::Nanoseconds,
1533    ),
1534    metric(
1535        MetricId::ExecutionPackMap,
1536        "execution-pack-map",
1537        MetricKind::Duration,
1538        MetricUnit::Nanoseconds,
1539    ),
1540    metric(
1541        MetricId::BackendAcquire,
1542        "backend-acquire",
1543        MetricKind::Duration,
1544        MetricUnit::Nanoseconds,
1545    ),
1546    metric(
1547        MetricId::BackendInit,
1548        "backend-init",
1549        MetricKind::Duration,
1550        MetricUnit::Nanoseconds,
1551    ),
1552    metric(
1553        MetricId::Teardown,
1554        "teardown",
1555        MetricKind::Duration,
1556        MetricUnit::Nanoseconds,
1557    ),
1558];
1559
1560impl MetricId {
1561    pub const COUNT: usize = 128;
1562
1563    /// Return static metadata with no lookup allocation or hashing.
1564    #[inline]
1565    pub const fn descriptor(self) -> &'static MetricDescriptor {
1566        &METRICS[self as usize]
1567    }
1568
1569    /// Stable metric name from the static registry.
1570    #[inline]
1571    pub const fn as_str(self) -> &'static str {
1572        self.descriptor().name
1573    }
1574}