Skip to main content

veloq_nsys_query/
error.rs

1use thiserror::Error;
2use veloq_core::{ErrorCode, VeloqDiagnostic, sort::SortParseError};
3
4pub type NsysQueryResult<T> = Result<T, NsysQueryError>;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum SqlPhase {
8    Prepare,
9    Query,
10    Read,
11}
12
13impl SqlPhase {
14    fn code(self) -> ErrorCode {
15        match self {
16            Self::Prepare => ErrorCode::new("nsys.query.sql-prepare"),
17            Self::Query => ErrorCode::new("nsys.query.sql-query"),
18            Self::Read => ErrorCode::new("nsys.query.sql-read"),
19        }
20    }
21}
22
23impl std::fmt::Display for SqlPhase {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.write_str(match self {
26            Self::Prepare => "prepare",
27            Self::Query => "execute",
28            Self::Read => "read",
29        })
30    }
31}
32
33#[derive(Debug, Error)]
34pub enum NsysQueryError {
35    #[error("internal: {verb} cannot process `{kind}` rows after kind validation")]
36    InternalUnsupportedKind {
37        verb: &'static str,
38        kind: &'static str,
39    },
40
41    #[error("internal: {verb} SQL returned unrecognised kind tag `{kind}`")]
42    InternalSqlKindTagInvalid { verb: &'static str, kind: String },
43
44    #[error("internal: {verb} NVTX attribution cannot process `{kind}` rows after kind validation")]
45    InternalNvtxAttributionUnsupportedKind {
46        verb: &'static str,
47        kind: &'static str,
48    },
49
50    #[error("internal: {query} stats SQL returned no row")]
51    InternalStatsRowMissing { query: &'static str },
52
53    #[error("internal: ncu-command expected one launch recipe after count check ({selector})")]
54    InternalNcuCommandLaunchRecipeSelectionMissing { selector: &'static str },
55
56    #[error("internal: ncu-command {query} SQL returned no row")]
57    InternalNcuCommandSqlRowMissing { query: &'static str },
58
59    #[error("internal: slice builder for nvtx_rowid {row_id} disappeared between fold and emit")]
60    InternalSliceBuilderMissing { row_id: i64 },
61
62    #[error("reverse NVTX attribution failed to {mode} sidecar")]
63    NvtxReverseSidecarLoad {
64        mode: &'static str,
65        #[source]
66        source: Box<veloq_nsys_data::NsysDataError>,
67    },
68
69    #[error("{source}")]
70    TraceOpen {
71        #[source]
72        source: Box<veloq_nsys_data::NsysDataError>,
73    },
74
75    #[error("{source}")]
76    CorrelationIndexLoad {
77        #[source]
78        source: Box<veloq_nsys_data::NsysDataError>,
79    },
80
81    #[error("hardware extraction failed")]
82    HardwareExtract {
83        #[source]
84        source: Box<veloq_nsys_data::NsysDataError>,
85    },
86
87    #[error("time-window resolution failed")]
88    TimeWindowResolve {
89        #[source]
90        source: Box<veloq_nsys_data::NsysDataError>,
91    },
92
93    #[error("{source}")]
94    Data {
95        #[source]
96        source: Box<veloq_nsys_data::NsysDataError>,
97    },
98
99    #[error("summary metadata load failed")]
100    SummaryMetaLoad {
101        #[source]
102        source: Box<veloq_nsys_data::NsysDataError>,
103    },
104
105    #[error("NVTX-parent sidecar ensure failed")]
106    NvtxParentSidecarEnsure {
107        #[source]
108        source: Box<veloq_nsys_data::NsysDataError>,
109    },
110
111    #[error("NVTX nesting load failed")]
112    NvtxNestingLoad {
113        #[source]
114        source: Box<veloq_nsys_data::NsysDataError>,
115    },
116
117    #[error("NVTX tree load failed")]
118    NvtxTreeLoad {
119        #[source]
120        source: Box<veloq_nsys_data::NsysDataError>,
121    },
122
123    #[error("{area} failed to {phase} {label} SQL")]
124    Sql {
125        area: &'static str,
126        phase: SqlPhase,
127        label: String,
128        #[source]
129        source: duckdb::Error,
130    },
131
132    #[error("--limit must be at least 1 (got {limit})")]
133    LimitTooSmall { limit: usize },
134
135    #[error("invalid {flag} `{value}`")]
136    PositiveDurationInvalid {
137        flag: String,
138        value: String,
139        #[source]
140        source: veloq_core::time::TimeParseError,
141    },
142
143    #[error("{flag} must be positive (got {ns} ns)")]
144    PositiveDurationTooSmall { flag: String, ns: i64 },
145
146    #[error("`--name` and `--name-regex` are mutually exclusive; pick one")]
147    NameFilterConflict,
148
149    #[error(
150        "search doesn't surface cpu_sample rows; use `veloq metrics --type cpu-sampling` or `veloq inspect cpu_sample:<id>` instead"
151    )]
152    SearchCpuSampleUnsupported,
153
154    #[error("invalid search --sort")]
155    SearchSortInvalid {
156        #[source]
157        source: SortParseError,
158    },
159
160    #[error("invalid --interval `{value}`")]
161    TimelineIntervalInvalid {
162        value: String,
163        #[source]
164        source: veloq_core::time::TimeParseError,
165    },
166
167    #[error("--interval must be positive (got {interval_ns} ns)")]
168    TimelineIntervalTooSmall { interval_ns: i64 },
169
170    #[error("timeline only buckets GPU kinds (kernel/memcpy/memset/graph); got `{kind}`")]
171    TimelineKindNotAllowed { kind: &'static str },
172
173    #[error("viz timeline requires --from and --to")]
174    VizTimelineWindowRequired,
175
176    #[error("unknown viz timeline track kind `{kind}`")]
177    VizTimelineUnknownTrackKind { kind: String },
178
179    #[error("invalid viz timeline track selector `{selector}`; expected name=value")]
180    VizTimelineInvalidSelector { selector: String },
181
182    #[error("unknown selector `{selector}` for viz timeline track `{kind}`")]
183    VizTimelineUnknownSelector { kind: String, selector: String },
184
185    #[error("viz timeline selector `{selector}` must be a non-negative integer")]
186    VizTimelineSelectorNonNegativeInt { selector: String },
187
188    #[error("viz timeline selector `{selector}` must be a positive integer")]
189    VizTimelineSelectorPositiveInt { selector: String },
190
191    #[error("viz timeline --highlight-kernels requires `top=<n>`")]
192    VizTimelineHighlightTopRequired,
193
194    #[error("unknown viz timeline highlight scope `{scope}` (expected: name, instance)")]
195    VizTimelineUnknownHighlightScope { scope: String },
196
197    #[error(
198        "unknown viz timeline highlight metric `{metric}` (expected: duration, count, max-duration)"
199    )]
200    VizTimelineUnknownHighlightMetric { metric: String },
201
202    #[error("viz timeline track `cuda-stream` requires `device=<id>`")]
203    VizTimelineCudaStreamDeviceRequired,
204
205    #[error("viz timeline track `cuda-stream` requires `stream=<id>`")]
206    VizTimelineCudaStreamStreamRequired,
207
208    #[error("viz timeline track `cuda-stream` does not accept `device=all`")]
209    VizTimelineCudaStreamDeviceAll,
210
211    #[error("visualization artifact failed")]
212    VizTimelineArtifact {
213        #[source]
214        source: veloq_vis::VisualizationError,
215    },
216
217    #[error("unknown --group-by `{group_by}` for slices --aggregate (expected: name, path)")]
218    SlicesUnknownGroupBy { group_by: String },
219
220    #[error("invalid slices --sort")]
221    SlicesSortInvalid {
222        #[source]
223        source: SortParseError,
224    },
225
226    #[error(
227        "slices requires `{table}`, which is not present in this trace (NVTX attribution is unavailable)"
228    )]
229    SlicesPrereqTableMissing { table: &'static str },
230
231    #[error(
232        "slices requires at least one GPU event table (kernel/memcpy/memset), but none is present in this trace"
233    )]
234    SlicesGpuEventTableMissing,
235
236    #[error("--nvtx attribution requires `{table}`, which is not present in this trace")]
237    NvtxAttributionPrereqTableMissing { table: &'static str },
238
239    #[error(
240        "--nvtx attribution needs at least one attributable kind (kernel/memcpy/memset/sync/runtime); requested kinds don't match any present table"
241    )]
242    NvtxAttributionNoAttributableTableMatch,
243
244    #[error(
245        "--nvtx attribution on kernel/memcpy/memset/sync requires `TARGET_INFO_CUDA_CONTEXT_INFO`, which is not present in this trace (GPU activity rows cannot be bridged to runtime rows without the context-info table; the lookup would silently miss every kernel)"
246    )]
247    NvtxAttributionContextInfoMissing,
248
249    #[error("graph-replays --nvtx requires `{table}`, which is not present in this trace")]
250    GraphReplaysNvtxPrereqTableMissing { table: &'static str },
251
252    #[error("invalid graph-replays --sort")]
253    GraphReplaysSortInvalid {
254        #[source]
255        source: SortParseError,
256    },
257
258    #[error("--group-by name axis specified twice (`{previous}` and `{current}`); pick one")]
259    StatsGroupByNameAxisConflict {
260        previous: &'static str,
261        current: &'static str,
262    },
263
264    #[error(
265        "unknown --group-by token `{token}` (expected: short, demangled, mangled, no-name, device, stream, context, graph, graph_node, nvtx-parent, nvtx-path, grid_block)"
266    )]
267    StatsGroupByUnknownToken { token: String },
268
269    #[error(
270        "stats only aggregates duration-bearing kinds (kernel/memcpy/memset/sync/graph/nvtx); got `{kind}`"
271    )]
272    StatsKindNotAllowed { kind: &'static str },
273
274    #[error(
275        "stats: --group-by device/context/stream/graph/graph_node has no meaning for `--type {kinds}`; every kind in the set is CPU-side and carries no device/stream/graph columns. Group by name (the default) or mix in a GPU-side kind (kernel/memcpy/memset/sync/graph/cuda_event) to split GPU rows by device while keeping the CPU-side rows in their own null bucket."
276    )]
277    StatsGroupByLocationAxisConflict { kinds: String },
278
279    #[error(
280        "{verb}: --group-by {axis} requires a device parent axis because {axis} ids are device-local; use `--device <id>` for one device or include `device,{axis}` in --group-by for comparison"
281    )]
282    StatsGroupByDeviceParentRequired {
283        verb: &'static str,
284        axis: &'static str,
285    },
286
287    #[error(
288        "stats: --group-by grid_block is kernel-only; gridX/Y/Z and blockX/Y/Z columns live on CUPTI_ACTIVITY_KIND_KERNEL and nowhere else. Got `--type {kind}` in the explicit kind set; either drop the non-kernel kinds or unset --group-by grid_block"
289    )]
290    StatsGridBlockKindConflict { kind: &'static str },
291
292    #[error("invalid stats --sort")]
293    StatsSortInvalid {
294        #[source]
295        source: SortParseError,
296    },
297
298    #[error(
299        "--by size only aggregates byte-carrying kinds (memcpy/memset); got `--type {kind}`; drop the kind or unset --by size"
300    )]
301    StatsBySizeKindNotAllowed { kind: &'static str },
302
303    #[error(
304        "stats-by-size does not yet support --group-by {axes}; supported axes today are the name axis (short/demangled/mangled/no-name) and device/context/stream"
305    )]
306    StatsBySizeGroupByUnsupported { axes: String },
307
308    #[error("invalid stats-by-size --sort")]
309    StatsBySizeSortInvalid {
310        #[source]
311        source: SortParseError,
312    },
313
314    #[error(
315        "stats: --group-by nvtx-parent and nvtx-path are mutually exclusive; pick rowid-level parent buckets or path-level hierarchy buckets"
316    )]
317    StatsNvtxHierarchyAxesConflict,
318
319    #[error(
320        "stats: --group-by {axis_name} is mutually exclusive with graph/graph_node; NVTX attribution walks host-thread containment, captured-graph axes walk device-side state. Pick one model per query"
321    )]
322    StatsNvtxHierarchyGraphAxisConflict { axis_name: &'static str },
323
324    #[error(
325        "stats: --group-by {axis_name} + --type nvtx is a self-attribute tautology; NVTX rows are the ranges NVTX hierarchy axes attribute other kinds to. Drop one of the two flags"
326    )]
327    StatsNvtxHierarchySelfAttribute { axis_name: &'static str },
328
329    #[error("--group-by {axis_name} requires `{table}`, which is not present in this trace")]
330    StatsNvtxHierarchyPrereqTableMissing {
331        axis_name: &'static str,
332        table: &'static str,
333    },
334
335    #[error(
336        "--group-by {axis_name} on kernel/memcpy/memset/sync requires `TARGET_INFO_CUDA_CONTEXT_INFO`, which is not present in this trace (GPU activity rows cannot be bridged to runtime rows without the context-info table; the lookup would silently miss every kernel)"
337    )]
338    StatsNvtxHierarchyContextInfoMissing { axis_name: &'static str },
339
340    #[error("unknown --env `{env}` (expected: none, safe, all)")]
341    NcuCommandUnknownEnv { env: String },
342
343    #[error(
344        "ncu-command requires a CUDA kernel row id (got `{row_id}`); use `search --type kernel` first"
345    )]
346    NcuCommandRowIdKind { row_id: String },
347
348    #[error("ncu-command requires `CUPTI_ACTIVITY_KIND_KERNEL`, which is absent from this trace")]
349    NcuCommandKernelTableMissing,
350
351    #[error(
352        "ncu-command requires `META_DATA_CAPTURE` to recover the original command, argv, cwd, and env"
353    )]
354    NcuCommandMetadataTableMissing,
355
356    #[error("kernel row `{row_id}` was not found")]
357    NcuCommandKernelNotFound { row_id: String },
358
359    #[error("kernel row `{row_id}` has neither a resolved shortName nor demangledName")]
360    NcuCommandKernelNameMissing { row_id: String },
361
362    #[error("META_DATA_CAPTURE contains no PROCESS_N:COMMAND launch recipe")]
363    NcuCommandLaunchRecipeMissing,
364
365    #[error(
366        "multiple META_DATA_CAPTURE launch recipes match process `{process}`; cannot choose an NCU target command"
367    )]
368    NcuCommandAmbiguousProcessRecipe { process: String },
369
370    #[error(
371        "multiple META_DATA_CAPTURE launch recipes are present and none matched the selected kernel process"
372    )]
373    NcuCommandAmbiguousLaunchRecipe,
374
375    #[error(
376        "{verb}: {axes} cannot be combined with `--type {kinds}`; these kinds have no device/stream columns"
377    )]
378    KindLocationFilterConflict {
379        verb: String,
380        axes: &'static str,
381        kinds: String,
382    },
383
384    #[error(
385        "{verb}: --nvtx cannot scope `--type {kinds}`; NVTX attribution for these kinds is experimental and not yet implemented"
386    )]
387    KindNvtxAttributionUnsupported { verb: String, kinds: String },
388
389    #[error("invalid --scope `{scope}`; expected device, stream, or trace")]
390    GapsInvalidScope { scope: String },
391
392    #[error("invalid --min-duration `{value}`")]
393    GapsMinDurationInvalid {
394        value: String,
395        #[source]
396        source: veloq_core::time::TimeParseError,
397    },
398
399    #[error("--min must be positive (got {min_ns} ns)")]
400    GapsMinTooSmall { min_ns: i64 },
401
402    #[error(
403        "--stream <id> requires --scope stream; under --scope {scope} rows have no stream axis"
404    )]
405    GapsStreamRequiresStreamScope { scope: &'static str },
406
407    #[error(
408        "--device {device} is incompatible with --scope trace; use --scope device --device {device}"
409    )]
410    GapsDeviceInTraceScope { device: i32 },
411
412    #[error(
413        "--sort stream requires --scope stream; under --scope {scope} rows have no stream axis"
414    )]
415    GapsSortStreamRequiresStreamScope { scope: &'static str },
416
417    #[error(
418        "--sort device is incompatible with --scope trace; trace-scope gaps are not partitioned by device"
419    )]
420    GapsSortDeviceInTraceScope,
421
422    #[error("invalid gaps --sort")]
423    GapsSortInvalid {
424        #[source]
425        source: SortParseError,
426    },
427
428    #[error("--sort doesn't apply in bucketed mode; buckets are time-ordered")]
429    MetricsSortWithBucket,
430
431    #[error("--bucket must be positive (got {bucket_ns} ns)")]
432    MetricsBucketTooSmall { bucket_ns: i64 },
433
434    #[error("invalid metrics --sort")]
435    MetricsSortInvalid {
436        #[source]
437        source: SortParseError,
438    },
439
440    #[error(
441        "unknown `--type {metric_source}` for metrics (supported: gpu, nic, cpu-sampling, cpu-sched)"
442    )]
443    MetricsUnknownSource { metric_source: String },
444
445    #[error(
446        "metrics --type gpu requires `GPU_METRICS`, which is absent from this trace; re-capture with `nsys profile --gpu-metrics-devices=…`"
447    )]
448    MetricsGpuTableMissing,
449
450    #[error(
451        "metrics --type gpu requires `TARGET_INFO_GPU_METRICS` (counter dictionary); likely a partial or corrupted nsys export"
452    )]
453    MetricsGpuDictionaryMissing,
454
455    #[error(
456        "no GPU counters match `--counter {glob}`; run `veloq metrics <trace> --type gpu` (no --counter) to list available names"
457    )]
458    MetricsGpuCounterNoMatch { glob: String },
459
460    #[error(
461        "metrics --type nic requires `NET_NIC_METRIC`, which is absent from this trace; re-capture with `nsys profile --nic-metrics=lf` (or `hf`) and verify `nsys status --network` passes"
462    )]
463    MetricsNicTableMissing,
464
465    #[error(
466        "metrics --type nic requires `TARGET_INFO_NETWORK_METRICS` (counter dictionary); likely a partial or corrupted nsys export"
467    )]
468    MetricsNicDictionaryMissing,
469
470    #[error(
471        "metrics --type nic requires `NIC_ID_MAP` (globalId to nicId mapping); likely a partial or corrupted nsys export"
472    )]
473    MetricsNicIdMapMissing,
474
475    #[error(
476        "metrics --type nic requires `TARGET_INFO_NIC_INFO` (NIC identity); likely a partial or corrupted nsys export"
477    )]
478    MetricsNicInfoMissing,
479
480    #[error(
481        "no NIC counters match `--counter {glob}`; run `veloq metrics <trace> --type nic` (no --counter) to list available names"
482    )]
483    MetricsNicCounterNoMatch { glob: String },
484
485    #[error(
486        "metrics --type cpu-sampling requires `COMPOSITE_EVENTS`, which is absent from this trace; re-capture with `nsys profile --sample=process-tree`"
487    )]
488    MetricsCpuSamplingCompositeEventsMissing,
489
490    #[error(
491        "unknown --group-by `{axis}` for cpu-sampling (expected: symbol, tid, cpu, module, stack)"
492    )]
493    MetricsCpuSamplingUnknownGroupBy { axis: String },
494
495    #[error(
496        "--group-by {group_by} needs `SAMPLING_CALLCHAINS` (per-sample stacks), which is absent from this trace; either re-capture with stack sampling enabled or switch to `--group-by tid` / `cpu`"
497    )]
498    MetricsCpuSamplingCallchainsMissing { group_by: &'static str },
499
500    #[error(
501        "--group-by {group_by} bucketed mode needs `SAMPLING_CALLCHAINS`, which is absent from this trace"
502    )]
503    MetricsCpuSamplingBucketCallchainsMissing { group_by: &'static str },
504
505    #[error(
506        "--group-by stack does not support --bucket yet; use summary mode for stack aggregation or switch to symbol/module/tid/cpu for bucketed samples"
507    )]
508    MetricsCpuSamplingStackBucketUnsupported,
509
510    #[error(
511        "--name doesn't apply on --group-by {group_by} (keys are numeric); drop it or switch to `--group-by symbol` / `module` / `stack`"
512    )]
513    MetricsCpuSamplingNameOnNumericAxis { group_by: &'static str },
514
515    #[error(
516        "metrics --type cpu-sched requires `SCHED_EVENTS`, which is absent from this trace; re-capture with `nsys profile --cpuctxsw=process-tree` (or `system-wide`)"
517    )]
518    MetricsCpuSchedEventsMissing,
519
520    #[error("unknown --group-by `{axis}` for cpu-sched (expected: tid, cpu, state)")]
521    MetricsCpuSchedUnknownGroupBy { axis: String },
522
523    #[error("--top-nodes must be at least 1 (got 0)")]
524    GraphReplaysTopNodesTooSmall,
525}
526
527impl NsysQueryError {
528    pub fn internal_unsupported_kind(verb: &'static str, kind: &'static str) -> Self {
529        Self::InternalUnsupportedKind { verb, kind }
530    }
531
532    pub fn internal_sql_kind_tag_invalid(verb: &'static str, kind: &str) -> Self {
533        Self::InternalSqlKindTagInvalid {
534            verb,
535            kind: kind.to_string(),
536        }
537    }
538
539    pub fn internal_nvtx_attribution_unsupported_kind(
540        verb: &'static str,
541        kind: &'static str,
542    ) -> Self {
543        Self::InternalNvtxAttributionUnsupportedKind { verb, kind }
544    }
545
546    pub fn internal_stats_row_missing(query: &'static str) -> Self {
547        Self::InternalStatsRowMissing { query }
548    }
549
550    pub fn internal_slice_builder_missing(row_id: i64) -> Self {
551        Self::InternalSliceBuilderMissing { row_id }
552    }
553
554    pub fn nvtx_reverse_sidecar_load(
555        mode: &'static str,
556        source: veloq_nsys_data::NsysDataError,
557    ) -> Self {
558        Self::NvtxReverseSidecarLoad {
559            mode,
560            source: Box::new(source),
561        }
562    }
563
564    pub fn trace_open(source: veloq_nsys_data::NsysDataError) -> Self {
565        Self::TraceOpen {
566            source: Box::new(source),
567        }
568    }
569
570    pub fn correlation_index_load(source: veloq_nsys_data::NsysDataError) -> Self {
571        Self::CorrelationIndexLoad {
572            source: Box::new(source),
573        }
574    }
575
576    pub fn hardware_extract(source: veloq_nsys_data::NsysDataError) -> Self {
577        Self::HardwareExtract {
578            source: Box::new(source),
579        }
580    }
581
582    pub fn time_window_resolve(source: veloq_nsys_data::NsysDataError) -> Self {
583        Self::TimeWindowResolve {
584            source: Box::new(source),
585        }
586    }
587
588    pub fn data(source: veloq_nsys_data::NsysDataError) -> Self {
589        Self::Data {
590            source: Box::new(source),
591        }
592    }
593
594    pub fn summary_meta_load(source: veloq_nsys_data::NsysDataError) -> Self {
595        Self::SummaryMetaLoad {
596            source: Box::new(source),
597        }
598    }
599
600    pub fn nvtx_parent_sidecar_ensure(source: veloq_nsys_data::NsysDataError) -> Self {
601        Self::NvtxParentSidecarEnsure {
602            source: Box::new(source),
603        }
604    }
605
606    pub fn nvtx_nesting_load(source: veloq_nsys_data::NsysDataError) -> Self {
607        Self::NvtxNestingLoad {
608            source: Box::new(source),
609        }
610    }
611
612    pub fn nvtx_tree_load(source: veloq_nsys_data::NsysDataError) -> Self {
613        Self::NvtxTreeLoad {
614            source: Box::new(source),
615        }
616    }
617
618    pub fn sql(
619        area: &'static str,
620        phase: SqlPhase,
621        label: impl Into<String>,
622        source: duckdb::Error,
623    ) -> Self {
624        Self::Sql {
625            area,
626            phase,
627            label: label.into(),
628            source,
629        }
630    }
631
632    pub fn sql_prepare(
633        area: &'static str,
634        label: impl Into<String>,
635        source: duckdb::Error,
636    ) -> Self {
637        Self::sql(area, SqlPhase::Prepare, label, source)
638    }
639
640    pub fn sql_query(area: &'static str, label: impl Into<String>, source: duckdb::Error) -> Self {
641        Self::sql(area, SqlPhase::Query, label, source)
642    }
643
644    pub fn sql_read(area: &'static str, label: impl Into<String>, source: duckdb::Error) -> Self {
645        Self::sql(area, SqlPhase::Read, label, source)
646    }
647
648    pub fn sql_parts(&self) -> Option<(&'static str, SqlPhase, &str)> {
649        match self {
650            Self::Sql {
651                area, phase, label, ..
652            } => Some((*area, *phase, label.as_str())),
653            _ => None,
654        }
655    }
656
657    pub fn search_sort_invalid(source: SortParseError) -> Self {
658        Self::SearchSortInvalid { source }
659    }
660
661    pub fn kind_location_filter_conflict(verb: &str, axes: &'static str, kinds: String) -> Self {
662        Self::KindLocationFilterConflict {
663            verb: verb.to_string(),
664            axes,
665            kinds,
666        }
667    }
668
669    pub fn kind_nvtx_attribution_unsupported(verb: &str, kinds: String) -> Self {
670        Self::KindNvtxAttributionUnsupported {
671            verb: verb.to_string(),
672            kinds,
673        }
674    }
675
676    pub fn gaps_invalid_scope(scope: &str) -> Self {
677        Self::GapsInvalidScope {
678            scope: scope.to_string(),
679        }
680    }
681
682    pub fn gaps_sort_invalid(source: SortParseError) -> Self {
683        Self::GapsSortInvalid { source }
684    }
685
686    pub fn graph_replays_sort_invalid(source: SortParseError) -> Self {
687        Self::GraphReplaysSortInvalid { source }
688    }
689
690    pub fn metrics_unknown_source(metric_source: &str) -> Self {
691        Self::MetricsUnknownSource {
692            metric_source: metric_source.to_string(),
693        }
694    }
695
696    pub fn metrics_sort_invalid(source: SortParseError) -> Self {
697        Self::MetricsSortInvalid { source }
698    }
699
700    pub fn metrics_gpu_counter_no_match(glob: &str) -> Self {
701        Self::MetricsGpuCounterNoMatch {
702            glob: glob.to_string(),
703        }
704    }
705
706    pub fn metrics_nic_counter_no_match(glob: &str) -> Self {
707        Self::MetricsNicCounterNoMatch {
708            glob: glob.to_string(),
709        }
710    }
711
712    pub fn metrics_cpu_sampling_unknown_group_by(axis: &str) -> Self {
713        Self::MetricsCpuSamplingUnknownGroupBy {
714            axis: axis.to_string(),
715        }
716    }
717
718    pub fn metrics_cpu_sched_unknown_group_by(axis: &str) -> Self {
719        Self::MetricsCpuSchedUnknownGroupBy {
720            axis: axis.to_string(),
721        }
722    }
723
724    pub fn slices_unknown_group_by(group_by: &str) -> Self {
725        Self::SlicesUnknownGroupBy {
726            group_by: group_by.to_string(),
727        }
728    }
729
730    pub fn slices_sort_invalid(source: SortParseError) -> Self {
731        Self::SlicesSortInvalid { source }
732    }
733
734    pub fn stats_group_by_unknown_token(token: &str) -> Self {
735        Self::StatsGroupByUnknownToken {
736            token: token.to_string(),
737        }
738    }
739
740    pub fn stats_group_by_location_axis_conflict(kinds: String) -> Self {
741        Self::StatsGroupByLocationAxisConflict { kinds }
742    }
743
744    pub fn stats_by_size_group_by_unsupported(axes: String) -> Self {
745        Self::StatsBySizeGroupByUnsupported { axes }
746    }
747
748    pub fn stats_sort_invalid(source: SortParseError) -> Self {
749        Self::StatsSortInvalid { source }
750    }
751
752    pub fn stats_by_size_sort_invalid(source: SortParseError) -> Self {
753        Self::StatsBySizeSortInvalid { source }
754    }
755
756    pub fn ncu_command_unknown_env(env: &str) -> Self {
757        Self::NcuCommandUnknownEnv {
758            env: env.to_string(),
759        }
760    }
761
762    pub fn ncu_command_row_id_kind(row_id: impl ToString) -> Self {
763        Self::NcuCommandRowIdKind {
764            row_id: row_id.to_string(),
765        }
766    }
767
768    pub fn ncu_command_kernel_not_found(row_id: impl ToString) -> Self {
769        Self::NcuCommandKernelNotFound {
770            row_id: row_id.to_string(),
771        }
772    }
773
774    pub fn ncu_command_kernel_name_missing(row_id: impl ToString) -> Self {
775        Self::NcuCommandKernelNameMissing {
776            row_id: row_id.to_string(),
777        }
778    }
779
780    pub fn ncu_command_ambiguous_process_recipe(process: &str) -> Self {
781        Self::NcuCommandAmbiguousProcessRecipe {
782            process: process.to_string(),
783        }
784    }
785}
786
787impl VeloqDiagnostic for NsysQueryError {
788    fn code(&self) -> ErrorCode {
789        match self {
790            Self::InternalUnsupportedKind { .. } => {
791                ErrorCode::new("nsys.internal.unsupported-kind")
792            }
793            Self::InternalSqlKindTagInvalid { .. } => {
794                ErrorCode::new("nsys.internal.sql-kind-tag-invalid")
795            }
796            Self::InternalNvtxAttributionUnsupportedKind { .. } => {
797                ErrorCode::new("nsys.internal.nvtx-attribution-unsupported-kind")
798            }
799            Self::InternalStatsRowMissing { .. } => {
800                ErrorCode::new("nsys.internal.stats-row-missing")
801            }
802            Self::InternalNcuCommandLaunchRecipeSelectionMissing { .. } => {
803                ErrorCode::new("nsys.internal.ncu-command-launch-recipe-selection-missing")
804            }
805            Self::InternalNcuCommandSqlRowMissing { .. } => {
806                ErrorCode::new("nsys.internal.ncu-command-sql-row-missing")
807            }
808            Self::InternalSliceBuilderMissing { .. } => {
809                ErrorCode::new("nsys.internal.slice-builder-missing")
810            }
811            Self::NvtxReverseSidecarLoad { .. } => {
812                ErrorCode::new("nsys.query.nvtx-reverse-sidecar-load")
813            }
814            Self::TraceOpen { source }
815            | Self::CorrelationIndexLoad { source }
816            | Self::Data { source } => source.code(),
817            Self::HardwareExtract { .. } => ErrorCode::new("nsys.query.hardware-extract"),
818            Self::TimeWindowResolve { .. } => ErrorCode::new("nsys.query.time-window-resolve"),
819            Self::SummaryMetaLoad { .. } => ErrorCode::new("nsys.query.summary-meta-load"),
820            Self::NvtxParentSidecarEnsure { .. } => {
821                ErrorCode::new("nsys.query.nvtx-parent-sidecar-ensure")
822            }
823            Self::NvtxNestingLoad { .. } => ErrorCode::new("nsys.query.nvtx-nesting-load"),
824            Self::NvtxTreeLoad { .. } => ErrorCode::new("nsys.query.nvtx-tree-load"),
825            Self::Sql { phase, .. } => phase.code(),
826            Self::LimitTooSmall { .. } => ErrorCode::new("nsys.query.limit-too-small"),
827            Self::PositiveDurationInvalid { .. } => {
828                ErrorCode::new("nsys.query.invalid-positive-duration")
829            }
830            Self::PositiveDurationTooSmall { .. } => {
831                ErrorCode::new("nsys.query.positive-duration-too-small")
832            }
833            Self::NameFilterConflict => ErrorCode::new("nsys.query.name-filter-conflict"),
834            Self::SearchCpuSampleUnsupported => {
835                ErrorCode::new("nsys.query.search-cpu-sample-unsupported")
836            }
837            Self::SearchSortInvalid { .. } => ErrorCode::new("nsys.query.search-sort-invalid"),
838            Self::TimelineIntervalInvalid { .. } => {
839                ErrorCode::new("nsys.query.timeline-interval-invalid")
840            }
841            Self::TimelineIntervalTooSmall { .. } => {
842                ErrorCode::new("nsys.query.timeline-interval-too-small")
843            }
844            Self::TimelineKindNotAllowed { .. } => {
845                ErrorCode::new("nsys.query.timeline-kind-not-allowed")
846            }
847            Self::VizTimelineWindowRequired => {
848                ErrorCode::new("nsys.query.viz-timeline-window-required")
849            }
850            Self::VizTimelineUnknownTrackKind { .. } => {
851                ErrorCode::new("nsys.query.viz-timeline-unknown-track-kind")
852            }
853            Self::VizTimelineInvalidSelector { .. } => {
854                ErrorCode::new("nsys.query.viz-timeline-invalid-selector")
855            }
856            Self::VizTimelineUnknownSelector { .. } => {
857                ErrorCode::new("nsys.query.viz-timeline-unknown-selector")
858            }
859            Self::VizTimelineSelectorNonNegativeInt { .. } => {
860                ErrorCode::new("nsys.query.viz-timeline-selector-non-negative-int")
861            }
862            Self::VizTimelineSelectorPositiveInt { .. } => {
863                ErrorCode::new("nsys.query.viz-timeline-selector-positive-int")
864            }
865            Self::VizTimelineHighlightTopRequired => {
866                ErrorCode::new("nsys.query.viz-timeline-highlight-top-required")
867            }
868            Self::VizTimelineUnknownHighlightScope { .. } => {
869                ErrorCode::new("nsys.query.viz-timeline-unknown-highlight-scope")
870            }
871            Self::VizTimelineUnknownHighlightMetric { .. } => {
872                ErrorCode::new("nsys.query.viz-timeline-unknown-highlight-metric")
873            }
874            Self::VizTimelineCudaStreamDeviceRequired => {
875                ErrorCode::new("nsys.query.viz-timeline-cuda-stream-device-required")
876            }
877            Self::VizTimelineCudaStreamStreamRequired => {
878                ErrorCode::new("nsys.query.viz-timeline-cuda-stream-stream-required")
879            }
880            Self::VizTimelineCudaStreamDeviceAll => {
881                ErrorCode::new("nsys.query.viz-timeline-cuda-stream-device-all")
882            }
883            Self::VizTimelineArtifact { source } => source.code(),
884            Self::SlicesUnknownGroupBy { .. } => {
885                ErrorCode::new("nsys.query.slices-unknown-group-by")
886            }
887            Self::SlicesSortInvalid { .. } => ErrorCode::new("nsys.query.slices-sort-invalid"),
888            Self::SlicesPrereqTableMissing { .. } => {
889                ErrorCode::new("nsys.query.slices-prereq-missing")
890            }
891            Self::SlicesGpuEventTableMissing => {
892                ErrorCode::new("nsys.query.slices-gpu-event-table-missing")
893            }
894            Self::NvtxAttributionPrereqTableMissing { .. } => {
895                ErrorCode::new("nsys.query.nvtx-attribution-prereq-missing")
896            }
897            Self::NvtxAttributionNoAttributableTableMatch => {
898                ErrorCode::new("nsys.query.nvtx-attribution-no-attributable-kind")
899            }
900            Self::NvtxAttributionContextInfoMissing => {
901                ErrorCode::new("nsys.query.nvtx-attribution-context-info-missing")
902            }
903            Self::GraphReplaysNvtxPrereqTableMissing { .. } => {
904                ErrorCode::new("nsys.query.graph-replays-nvtx-prereq-missing")
905            }
906            Self::GraphReplaysSortInvalid { .. } => {
907                ErrorCode::new("nsys.query.graph-replays-sort-invalid")
908            }
909            Self::StatsGroupByNameAxisConflict { .. } => {
910                ErrorCode::new("nsys.query.stats-group-by-name-axis-conflict")
911            }
912            Self::StatsGroupByUnknownToken { .. } => {
913                ErrorCode::new("nsys.query.stats-group-by-unknown-token")
914            }
915            Self::StatsKindNotAllowed { .. } => ErrorCode::new("nsys.query.stats-kind-not-allowed"),
916            Self::StatsGroupByLocationAxisConflict { .. } => {
917                ErrorCode::new("nsys.query.stats-group-by-location-axis-conflict")
918            }
919            Self::StatsGroupByDeviceParentRequired { .. } => {
920                ErrorCode::new("nsys.query.stats-group-by-device-parent-required")
921            }
922            Self::StatsGridBlockKindConflict { .. } => {
923                ErrorCode::new("nsys.query.stats-grid-block-kind-conflict")
924            }
925            Self::StatsSortInvalid { .. } => ErrorCode::new("nsys.query.stats-sort-invalid"),
926            Self::StatsBySizeKindNotAllowed { .. } => {
927                ErrorCode::new("nsys.query.stats-by-size-kind-not-allowed")
928            }
929            Self::StatsBySizeGroupByUnsupported { .. } => {
930                ErrorCode::new("nsys.query.stats-by-size-group-by-unsupported")
931            }
932            Self::StatsBySizeSortInvalid { .. } => {
933                ErrorCode::new("nsys.query.stats-by-size-sort-invalid")
934            }
935            Self::StatsNvtxHierarchyAxesConflict => {
936                ErrorCode::new("nsys.query.stats-nvtx-hierarchy-axis-conflict")
937            }
938            Self::StatsNvtxHierarchyGraphAxisConflict { .. } => {
939                ErrorCode::new("nsys.query.stats-nvtx-hierarchy-graph-axis-conflict")
940            }
941            Self::StatsNvtxHierarchySelfAttribute { .. } => {
942                ErrorCode::new("nsys.query.stats-nvtx-hierarchy-self-attribute")
943            }
944            Self::StatsNvtxHierarchyPrereqTableMissing { .. } => {
945                ErrorCode::new("nsys.query.stats-nvtx-hierarchy-prereq-missing")
946            }
947            Self::StatsNvtxHierarchyContextInfoMissing { .. } => {
948                ErrorCode::new("nsys.query.stats-nvtx-hierarchy-context-info-missing")
949            }
950            Self::NcuCommandUnknownEnv { .. } => {
951                ErrorCode::new("nsys.query.ncu-command-unknown-env")
952            }
953            Self::NcuCommandRowIdKind { .. } => {
954                ErrorCode::new("nsys.query.ncu-command-row-id-kind")
955            }
956            Self::NcuCommandKernelTableMissing => {
957                ErrorCode::new("nsys.query.ncu-command-kernel-table-missing")
958            }
959            Self::NcuCommandMetadataTableMissing => {
960                ErrorCode::new("nsys.query.ncu-command-metadata-table-missing")
961            }
962            Self::NcuCommandKernelNotFound { .. } => {
963                ErrorCode::new("nsys.query.ncu-command-kernel-not-found")
964            }
965            Self::NcuCommandKernelNameMissing { .. } => {
966                ErrorCode::new("nsys.query.ncu-command-kernel-name-missing")
967            }
968            Self::NcuCommandLaunchRecipeMissing => {
969                ErrorCode::new("nsys.query.ncu-command-launch-recipe-missing")
970            }
971            Self::NcuCommandAmbiguousProcessRecipe { .. } => {
972                ErrorCode::new("nsys.query.ncu-command-launch-recipe-ambiguous-process")
973            }
974            Self::NcuCommandAmbiguousLaunchRecipe => {
975                ErrorCode::new("nsys.query.ncu-command-launch-recipe-ambiguous")
976            }
977            Self::KindLocationFilterConflict { .. } => {
978                ErrorCode::new("nsys.query.kind-location-filter-conflict")
979            }
980            Self::KindNvtxAttributionUnsupported { .. } => {
981                ErrorCode::new("nsys.query.kind-nvtx-attribution-unsupported")
982            }
983            Self::GapsInvalidScope { .. } => ErrorCode::new("nsys.query.gaps-invalid-scope"),
984            Self::GapsMinDurationInvalid { .. } => {
985                ErrorCode::new("nsys.query.gaps-min-duration-invalid")
986            }
987            Self::GapsMinTooSmall { .. } => ErrorCode::new("nsys.query.gaps-min-too-small"),
988            Self::GapsStreamRequiresStreamScope { .. } => {
989                ErrorCode::new("nsys.query.gaps-stream-scope-required")
990            }
991            Self::GapsDeviceInTraceScope { .. } => {
992                ErrorCode::new("nsys.query.gaps-device-scope-conflict")
993            }
994            Self::GapsSortStreamRequiresStreamScope { .. } => {
995                ErrorCode::new("nsys.query.gaps-sort-stream-scope-required")
996            }
997            Self::GapsSortDeviceInTraceScope => {
998                ErrorCode::new("nsys.query.gaps-sort-device-scope-conflict")
999            }
1000            Self::GapsSortInvalid { .. } => ErrorCode::new("nsys.query.gaps-sort-invalid"),
1001            Self::MetricsSortWithBucket => {
1002                ErrorCode::new("nsys.query.metrics-sort-bucket-conflict")
1003            }
1004            Self::MetricsBucketTooSmall { .. } => {
1005                ErrorCode::new("nsys.query.metrics-bucket-too-small")
1006            }
1007            Self::MetricsSortInvalid { .. } => ErrorCode::new("nsys.query.metrics-sort-invalid"),
1008            Self::MetricsUnknownSource { .. } => {
1009                ErrorCode::new("nsys.query.metrics-unknown-source")
1010            }
1011            Self::MetricsGpuTableMissing => ErrorCode::new("nsys.query.metrics-gpu-table-missing"),
1012            Self::MetricsGpuDictionaryMissing => {
1013                ErrorCode::new("nsys.query.metrics-gpu-dictionary-missing")
1014            }
1015            Self::MetricsGpuCounterNoMatch { .. } => {
1016                ErrorCode::new("nsys.query.metrics-gpu-counter-no-match")
1017            }
1018            Self::MetricsNicTableMissing => ErrorCode::new("nsys.query.metrics-nic-table-missing"),
1019            Self::MetricsNicDictionaryMissing => {
1020                ErrorCode::new("nsys.query.metrics-nic-dictionary-missing")
1021            }
1022            Self::MetricsNicIdMapMissing => ErrorCode::new("nsys.query.metrics-nic-id-map-missing"),
1023            Self::MetricsNicInfoMissing => ErrorCode::new("nsys.query.metrics-nic-info-missing"),
1024            Self::MetricsNicCounterNoMatch { .. } => {
1025                ErrorCode::new("nsys.query.metrics-nic-counter-no-match")
1026            }
1027            Self::MetricsCpuSamplingCompositeEventsMissing => {
1028                ErrorCode::new("nsys.query.metrics-cpu-sampling-table-missing")
1029            }
1030            Self::MetricsCpuSamplingUnknownGroupBy { .. } => {
1031                ErrorCode::new("nsys.query.metrics-cpu-sampling-unknown-group-by")
1032            }
1033            Self::MetricsCpuSamplingCallchainsMissing { .. } => {
1034                ErrorCode::new("nsys.query.metrics-cpu-sampling-callchains-missing")
1035            }
1036            Self::MetricsCpuSamplingBucketCallchainsMissing { .. } => {
1037                ErrorCode::new("nsys.query.metrics-cpu-sampling-callchains-missing")
1038            }
1039            Self::MetricsCpuSamplingStackBucketUnsupported => {
1040                ErrorCode::new("nsys.query.metrics-cpu-sampling-stack-bucket-unsupported")
1041            }
1042            Self::MetricsCpuSamplingNameOnNumericAxis { .. } => {
1043                ErrorCode::new("nsys.query.metrics-cpu-sampling-name-axis-conflict")
1044            }
1045            Self::MetricsCpuSchedEventsMissing => {
1046                ErrorCode::new("nsys.query.metrics-cpu-sched-table-missing")
1047            }
1048            Self::MetricsCpuSchedUnknownGroupBy { .. } => {
1049                ErrorCode::new("nsys.query.metrics-cpu-sched-unknown-group-by")
1050            }
1051            Self::GraphReplaysTopNodesTooSmall => {
1052                ErrorCode::new("nsys.query.graph-replays-top-nodes-too-small")
1053            }
1054        }
1055    }
1056}