1pub mod column_map;
7pub mod concurrency;
8pub mod correlate;
9pub mod docgen;
10pub mod error;
11pub mod event_ref;
12pub mod gaps;
13pub mod graph_replays;
14pub mod hardware;
15pub mod inspect;
16pub mod kind_filter;
17pub mod kind_policy;
18pub mod kind_sql;
19pub mod metrics;
20pub mod ncu_command;
21pub mod nvtx_attribution;
22pub mod nvtx_parent;
23pub mod nvtx_projection;
24pub mod nvtx_reverse;
25mod query_sql;
26pub mod row_id;
27pub mod search;
28pub mod slices;
29pub mod stats;
30pub mod stats_by_size;
31pub mod summary;
32pub mod timeline;
33pub mod viz_timeline;
34
35pub use error::{NsysQueryError, NsysQueryResult, SqlPhase};
36pub use event_ref::{EventRef, NvtxContext};
37pub use kind_filter::KindFilter;
38pub use row_id::{EventKind, RowId};
39
40pub fn check_limit(limit: usize) -> NsysQueryResult<()> {
46 veloq_core::LimitRef::new(limit)
47 .map(|_| ())
48 .map_err(|_| NsysQueryError::LimitTooSmall { limit })
49}
50
51pub fn open_scoped(
59 path: &std::path::Path,
60 limit: usize,
61 window: Option<veloq_core::time::TimeWindow>,
62) -> NsysQueryResult<(veloq_nsys_data::Trace, Option<(i64, i64)>)> {
63 check_limit(limit)?;
64 let trace = veloq_nsys_data::Trace::open(path).map_err(NsysQueryError::trace_open)?;
65 let abs_window = trace
66 .resolve_window(window)
67 .map_err(NsysQueryError::time_window_resolve)?;
68 Ok((trace, abs_window))
69}
70
71pub fn module_basename(path: &str) -> String {
79 path.rsplit(['/', '\\']).next().unwrap_or("").to_string()
80}
81
82pub fn decode_global_tid(global_tid: i64) -> (i64, i64) {
100 let pid = (global_tid >> 24) & 0xFFFFFF;
101 let tid = global_tid & 0xFFFF;
102 (pid, tid)
103}
104
105pub fn parse_positive_duration(s: &str, flag: &str) -> NsysQueryResult<i64> {
115 let ns = veloq_core::time::parse_duration_ns(s).map_err(|source| {
116 NsysQueryError::PositiveDurationInvalid {
117 flag: flag.to_string(),
118 value: s.to_string(),
119 source,
120 }
121 })?;
122 if ns <= 0 {
123 return Err(NsysQueryError::PositiveDurationTooSmall {
124 flag: flag.to_string(),
125 ns,
126 });
127 }
128 Ok(ns)
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use veloq_core::VeloqDiagnostic;
135
136 #[test]
137 fn check_limit_zero_returns_typed_error() -> anyhow::Result<()> {
138 let err = match check_limit(0) {
139 Ok(()) => anyhow::bail!("expected check_limit(0) to fail"),
140 Err(err) => err,
141 };
142
143 assert_eq!(err.code().as_str(), "nsys.query.limit-too-small");
144 assert!(matches!(err, NsysQueryError::LimitTooSmall { limit: 0 }));
145 Ok(())
146 }
147
148 #[test]
149 fn parse_positive_duration_invalid_literal_returns_typed_error() -> anyhow::Result<()> {
150 let err = match parse_positive_duration("bogus", "--bucket") {
151 Ok(ns) => anyhow::bail!("expected invalid duration to fail, got {ns} ns"),
152 Err(err) => err,
153 };
154
155 assert_eq!(err.code().as_str(), "nsys.query.invalid-positive-duration");
156 match err {
157 NsysQueryError::PositiveDurationInvalid { flag, value, .. } => {
158 assert_eq!(flag, "--bucket");
159 assert_eq!(value, "bogus");
160 }
161 other => anyhow::bail!("expected PositiveDurationInvalid, got {other:?}"),
162 }
163 Ok(())
164 }
165
166 #[test]
167 fn parse_positive_duration_zero_returns_typed_error() -> anyhow::Result<()> {
168 let err = match parse_positive_duration("0ns", "--interval") {
169 Ok(ns) => anyhow::bail!("expected zero duration to fail, got {ns} ns"),
170 Err(err) => err,
171 };
172
173 assert_eq!(
174 err.code().as_str(),
175 "nsys.query.positive-duration-too-small"
176 );
177 assert!(matches!(
178 err,
179 NsysQueryError::PositiveDurationTooSmall {
180 flag,
181 ns: 0
182 } if flag == "--interval"
183 ));
184 Ok(())
185 }
186}