Skip to main content

keyhog_profile/
lib.rs

1//! Record causal performance evidence for one KeyHog run.
2//!
3//! Start a [`Session`] at the beginning of the production operation. Record
4//! macro state changes with [`Session::transition`]. Wrap measured work in
5//! [`span`], then call [`Session::finish`] to produce a versioned [`RunProfile`].
6//!
7//! ```
8//! use keyhog_profile::{RunIdentity, RunState, Session, Stage, span};
9//!
10//! let identity = RunIdentity::new(
11//!     "0.5.49",
12//!     "detector-digest",
13//!     "config-digest",
14//!     "filesystem",
15//!     "small-text",
16//!     "auto",
17//! );
18//! let mut session = Session::start(identity).expect("start profile");
19//! session.transition(RunState::Scanning);
20//! {
21//!     let _read = span(Stage::SourceRead);
22//!     std::hint::black_box(42);
23//! }
24//! let profile = session.finish(RunState::Completed);
25//!
26//! assert_eq!(profile.status, RunState::Completed);
27//! assert_eq!(profile.stages[0].stage, Stage::SourceRead);
28//! assert_eq!(profile.stages[0].calls, 1);
29//! ```
30//!
31//! # Runtime ownership
32//!
33//! A session owns an isolated [`Runtime`]. The session enters that runtime on
34//! the calling thread. Propagate a clone explicitly when work crosses a thread
35//! boundary. This keeps concurrent runs isolated.
36//!
37//! ```
38//! use keyhog_profile::{RunIdentity, RunState, Session, Stage, span};
39//!
40//! let identity = RunIdentity::new("0.5.49", "d", "c", "stdin", "stream", "auto");
41//! let session = Session::start(identity).expect("start profile");
42//! let runtime = session.runtime();
43//! std::thread::spawn(move || runtime.scope(|| {
44//!     let _scan = span(Stage::BackendDispatch);
45//! }))
46//! .join()
47//! .expect("join worker");
48//! let profile = session.finish(RunState::Completed);
49//! assert_eq!(profile.stages[0].stage, Stage::BackendDispatch);
50//! ```
51//!
52//! # Recording cost
53//!
54//! The disabled span path checks one relaxed atomic and does not read the clock.
55//! Enabled spans update fixed atomic counters indexed by [`MetricId`]. They do
56//! not allocate, hash metric names, or format text. Vector construction, JSON
57//! serialization, and report analysis run only when counters are drained or a
58//! session is finished.
59//!
60//! `cargo bench -p keyhog-profile --bench overhead_budget` enforces absolute
61//! median budgets for disabled checks, aggregate spans, and causal spans. The
62//! regular CI workflow runs this gate with an optimized benchmark build.
63//!
64//! # Metrics and collectors
65//!
66//! [`METRICS`] is the static registry for metric names, kinds, and units. A
67//! collector implements [`SnapshotCollector`] and reports a
68//! [`CollectorCapability`] before sampling. The default `process-metrics`
69//! feature samples process CPU time, resident memory, virtual memory, and thread
70//! count. Disable default features when you need stage timing without platform
71//! process sampling. The profile then reports the collector as disabled instead
72//! of silently emitting unavailable measurements.
73//!
74//! # Persisted records
75//!
76//! [`PROFILE_SCHEMA`] identifies the profile envelope. Every persisted component
77//! also carries its own numeric version. Missing component versions decode as
78//! version one for compatibility with early records. Compare identity fields,
79//! collector capabilities, workload state, and metric units before comparing
80//! measurements from two profiles.
81//!
82//! # Privacy
83//!
84//! The profiler records counts, durations, run identity, execution choices, and
85//! process resources. Do not use source content, credentials, raw URLs, or
86//! sensitive paths as identity labels. [`RunProfile::render_text`] and
87//! [`RunProfile::to_json_pretty`] serialize the labels supplied by the caller.
88
89mod allocation;
90mod analysis;
91mod collector;
92mod comparison;
93mod detail;
94mod hardware;
95mod identity;
96pub mod insight;
97mod metrics;
98mod resources;
99mod runtime;
100mod schema;
101mod schema_v2;
102mod session;
103mod system;
104
105pub use allocation::{
106    allocation_snapshot, allocation_tracking_installed, reset_allocation_peaks, AllocationSlotV2,
107    AllocationSnapshotV2, TrackingAllocator, ROOT_SLOT, STAGE_SLOTS,
108};
109pub use analysis::take_stage_measurements;
110pub use collector::{
111    CollectorAvailability, CollectorCapability, CollectorId, SnapshotCollector,
112    COLLECTOR_CAPABILITY_VERSION,
113};
114pub use comparison::{
115    compare_profiles, ComparisonDifference, ProfileComparison, StageComparison,
116    COMPARISON_DIFFERENCE_VERSION, PROFILE_COMPARISON_VERSION, STAGE_COMPARISON_VERSION,
117};
118pub use detail::{detail, set_detail, Detail};
119pub use hardware::{
120    aggregate_span_hardware, milli_ratio, CpuFrequencySampleV2, HardwareCounterCollector,
121    HardwareCounterSampleV2, HardwareCounterSetV2, HardwareFieldSourceV2, HardwareRunEvidenceV2,
122    RunSpanHardwareV2, SchedulerCollector, SchedulerEvidenceV2, SchedulerSampleV2,
123    SourcedEvidenceV2, SpanHardwareAggregationV2, SpanHardwareV2, StageHardwareV2, ThreadCpuV2,
124    ThreadHardwareV2, ThreadUtilizationCollector, ThreadUtilizationSampleV2, ThreadUtilizationV2,
125    TopologyCollector, TopologyEvidenceV2, UtilizationEvidenceV2, HARDWARE_EVIDENCE_V2_VERSION,
126    MAX_SAMPLE_THREADS, MAX_UTILIZATION_SAMPLES, SPAN_HARDWARE_V2_VERSION,
127};
128pub use identity::{
129    BuildIdentityInput, ConfigIdentityInput, DetectorIdentityInput, SourceIdentityInput,
130    WorkloadIdentityInput,
131};
132pub use insight::{
133    BackendAttributionV2, BottleneckKindV2, FindingV2, InsightCoverageV2, MemoryInsightV2,
134    ParallelismInsightV2, PhaseInsightV2, RunInsightV2, SerialRegionV2, SerialScopeV2,
135    StageAttributionV2, StageMemoryV2, ThroughputInsightV2, RUN_INSIGHT_V2_VERSION,
136};
137pub use metrics::{
138    AnnotationId, CacheId, CounterId, EventId, GaugeId, IndexedCounterId, MacroStageId,
139    MetricDescriptor, MetricId, MetricKind, MetricUnit, QueueId, RetryCause, INDEXED_COUNTER_SLOTS,
140    METRICS,
141};
142pub use runtime::{
143    add_backend_dispatched_bytes, add_counter, add_derived_decoder_bytes, add_indexed_counter,
144    add_input_bytes, add_input_units, add_stage_bytes, blocked, counter_span,
145    current_causal_parent, current_runtime, current_task_id, current_work_origin, decision_timer,
146    enabled, instrument_future, instrument_future_with_parent, record_annotation,
147    record_batch_route, record_cache_hit, record_cache_miss, record_distribution, record_event,
148    record_fs_metadata_latency_ns, record_fs_open_latency_ns, record_fs_read_latency_ns,
149    record_io_cache_state, record_network_bytes, record_network_latency_ns, record_network_request,
150    record_queue_depth_dequeue, record_queue_depth_enqueue, record_queue_dequeue,
151    record_queue_enqueue, record_retained_buffer_bytes, record_retry, record_sampled_event, reset,
152    serial_span, set_attribution, set_enabled, set_gauge, set_queue_depth, set_task_id,
153    set_work_origin, span, span_with_parent, take_input_totals, take_metric_distributions,
154    take_typed_metrics, Attribution, CausalParent, ContextGuard, CounterSpan, DecisionTimer,
155    EventLossCounts, QueueLinkLossCounts, Runtime, SamplingPolicy, Span, MAX_ANNOTATIONS,
156    MAX_BATCH_ROUTES, MAX_POINT_EVENTS, MAX_QUEUE_LINKS, MAX_RECORDED_SPANS,
157};
158pub use schema::{
159    CacheState, DaemonState, ResourceSample, ResourceSnapshot, ResourceUsage, RunIdentity,
160    RunProfile, RunState, Stage, StageMeasurement, StateMeasurement, StateTransition,
161    WorkloadMeasurements, PROFILE_SCHEMA, RESOURCE_SAMPLE_VERSION, RESOURCE_SNAPSHOT_VERSION,
162    RESOURCE_USAGE_VERSION, RUN_IDENTITY_VERSION, RUN_PROFILE_VERSION, STAGE_MEASUREMENT_VERSION,
163    STATE_MEASUREMENT_VERSION, STATE_TRANSITION_VERSION, WORKLOAD_MEASUREMENTS_VERSION,
164};
165pub use schema_v2::{
166    AnnotationV2, ArtifactIntegrityV2, BatchRouteV2, BlockedWaitRecordV2, BuildIdentityV2,
167    CacheEffectivenessV2, CacheLayerKindV2, CacheLayerV2, CausalProfileV2, CausalRunIdentityV2,
168    ConfigIdentityV2, CoverageStateV2, DaemonIdentityV2, DetectorIdentityV2, DistributionBucketV2,
169    EventStreamV2, Evidence, EvidenceGap, HostIdentityV2, IndexedCounterRecordV2, LatencyBucketV2,
170    LatencyDistributionV2, MetricDistributionV2, OutcomeIdentityV2, PointEventV2,
171    ProducerIdentityV2, ProfileEnvelopeV2, QueueDepthV2, QueueLinkV2, RetryRecordV2,
172    RouteIdentityV2, SchemaVersionV2, SourceIdentityV2, SpanRecordV2, StageConcurrencyV2,
173    TypedMetricRecordV2, WorkOrigin, WorkerImbalanceV2, WorkerLoadV2, WorkerOccupancyRowV2,
174    WorkerOccupancyV2, WorkloadIdentityV2, CACHE_EFFECTIVENESS_V2_VERSION,
175    CAUSAL_IDENTITY_V2_VERSION, CAUSAL_PROFILE_V2_VERSION, EVENT_SCHEMA_VERSION, EXPORTER_VERSION,
176    INDEXED_COUNTER_V2_VERSION, METRIC_REGISTRY_VERSION, PROFILE_ENVELOPE_V2_VERSION,
177    PROFILE_SCHEMA_V2, PROFILE_SCHEMA_V2_MAJOR, PROFILE_SCHEMA_V2_MINOR, RETRY_RECORD_V2_VERSION,
178    STAGE_CONCURRENCY_V2_VERSION, WORKER_OCCUPANCY_V2_VERSION,
179};
180pub use session::{Session, SessionActive};
181pub use system::{
182    AllocationEvidenceV2, AllocationTotalsV2, DecodeRetentionEvidenceV2, FaultEvidenceV2,
183    IoCacheStateV2, IoEvidenceV2, MemoryEvidenceV2, NetworkEvidenceV2, NetworkProcessCountersV2,
184    PressureEvidenceV2, PressureThermalCollector, PressureThermalSampleV2, StageAllocationV2,
185    SystemIoCollector, SystemIoSampleV2, SystemRunEvidenceV2, ThermalEvidenceV2,
186    SYSTEM_EVIDENCE_V2_VERSION,
187};