Skip to main content

nvtx_sys/
lib.rs

1// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3
4#![cfg_attr(test, allow(clippy::unwrap_used))]
5#![no_std]
6#![deny(unsafe_op_in_unsafe_fn)]
7
8/// The unmodified FFI imported functions, types, and definitions
9pub mod ffi {
10    #![allow(non_upper_case_globals)]
11    #![allow(non_camel_case_types)]
12    #![allow(non_snake_case)]
13    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
14}
15
16/// The NVTX version.
17#[allow(clippy::cast_possible_truncation)]
18// CAST: This constant cast stays `as` because `From`/`TryFrom` calls are not const on stable Rust.
19pub const NVTX_VERSION: i16 = ffi::NVTX_VERSION as i16;
20
21/// A unique range identifier.
22pub type RangeId = ffi::nvtxRangeId_t;
23
24/// Struct representing all possible Event attributes.
25pub type EventAttributes = ffi::nvtxEventAttributes_t;
26
27pub const NVTX_EVENT_ATTRIBUTES_SIZE: usize = core::mem::size_of::<EventAttributes>();
28
29/// Struct representing all possible Resource attributes.
30pub type ResourceAttributes = ffi::nvtxResourceAttributes_t;
31
32pub const NVTX_RESOURCE_ATTRIBUTES_SIZE: usize = core::mem::size_of::<ResourceAttributes>();
33
34/// Struct representing all possible User-defined Synchronization attributes.
35pub type SyncUserAttributes = ffi::nvtxSyncUserAttributes_t;
36
37pub const NVTX_SYNC_USER_ATTRIBUTES_SIZE: usize = core::mem::size_of::<SyncUserAttributes>();
38
39/// [`ResourceAttributes`] identifier union.
40pub type ResourceAttributesIdentifier = ffi::nvtxResourceAttributes_v0_identifier_t;
41/// [`EventAttributes`] color type.
42pub type ColorType = ffi::nvtxColorType_t;
43/// [`EventAttributes`] and [`ResourceAttributes`] message type.
44pub type MessageType = ffi::nvtxMessageType_t;
45/// [`EventAttributes`] and [`ResourceAttributes`] message value.
46pub type MessageValue = ffi::nvtxMessageValue_t;
47/// [`EventAttributes`] payload type.
48pub type PayloadType = ffi::nvtxPayloadType_t;
49/// [`EventAttributes`] payload value union.
50pub type PayloadValue = ffi::nvtxEventAttributes_v2_payload_t;
51
52// Keep this declarative macro for tightly scoped impl boilerplate only.
53macro_rules! impl_from_repr_u32_enum_for_i32 {
54    ($($ty:ty),+ $(,)?) => {
55        $(
56            impl ::core::convert::From<$ty> for i32 {
57                fn from(value: $ty) -> Self {
58                    // CAST: Rust has no blanket enum->int `From`; `as` preserves the 32-bit bit pattern expected by NVTX's i32 fields.
59                    value as i32
60                }
61            }
62        )+
63    };
64}
65
66impl_from_repr_u32_enum_for_i32!(ColorType, MessageType, PayloadType);
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    fn assert_fits_nvtx_i32_field<T>(name: &str, value: T)
73    where
74        T: Into<i32>,
75    {
76        assert!(
77            value.into() >= 0,
78            "{name} must fit in NVTX's signed 32-bit type fields"
79        );
80    }
81
82    #[test]
83    fn enum_type_values_fit_nvtx_i32_fields() {
84        // `nvToolsExt.h` defines these enum values as non-negative constants in
85        // the range 0..=6 for NVTX's signed 32-bit type discriminator fields.
86        assert_fits_nvtx_i32_field("NVTX_COLOR_UNKNOWN", ColorType::NVTX_COLOR_UNKNOWN);
87        assert_fits_nvtx_i32_field("NVTX_COLOR_ARGB", ColorType::NVTX_COLOR_ARGB);
88
89        assert_fits_nvtx_i32_field("NVTX_MESSAGE_UNKNOWN", MessageType::NVTX_MESSAGE_UNKNOWN);
90        assert_fits_nvtx_i32_field(
91            "NVTX_MESSAGE_TYPE_ASCII",
92            MessageType::NVTX_MESSAGE_TYPE_ASCII,
93        );
94        assert_fits_nvtx_i32_field(
95            "NVTX_MESSAGE_TYPE_UNICODE",
96            MessageType::NVTX_MESSAGE_TYPE_UNICODE,
97        );
98        assert_fits_nvtx_i32_field(
99            "NVTX_MESSAGE_TYPE_REGISTERED",
100            MessageType::NVTX_MESSAGE_TYPE_REGISTERED,
101        );
102
103        assert_fits_nvtx_i32_field("NVTX_PAYLOAD_UNKNOWN", PayloadType::NVTX_PAYLOAD_UNKNOWN);
104        assert_fits_nvtx_i32_field(
105            "NVTX_PAYLOAD_TYPE_UNSIGNED_INT64",
106            PayloadType::NVTX_PAYLOAD_TYPE_UNSIGNED_INT64,
107        );
108        assert_fits_nvtx_i32_field(
109            "NVTX_PAYLOAD_TYPE_INT64",
110            PayloadType::NVTX_PAYLOAD_TYPE_INT64,
111        );
112        assert_fits_nvtx_i32_field(
113            "NVTX_PAYLOAD_TYPE_DOUBLE",
114            PayloadType::NVTX_PAYLOAD_TYPE_DOUBLE,
115        );
116        assert_fits_nvtx_i32_field(
117            "NVTX_PAYLOAD_TYPE_UNSIGNED_INT32",
118            PayloadType::NVTX_PAYLOAD_TYPE_UNSIGNED_INT32,
119        );
120        assert_fits_nvtx_i32_field(
121            "NVTX_PAYLOAD_TYPE_INT32",
122            PayloadType::NVTX_PAYLOAD_TYPE_INT32,
123        );
124        assert_fits_nvtx_i32_field(
125            "NVTX_PAYLOAD_TYPE_FLOAT",
126            PayloadType::NVTX_PAYLOAD_TYPE_FLOAT,
127        );
128    }
129}
130
131/// Unique handle for a registered domain.
132#[derive(Debug, Clone, Copy)]
133pub struct DomainHandle {
134    handle: ffi::nvtxDomainHandle_t,
135}
136
137// SAFETY: `DomainHandle` is an opaque FFI handle with no Rust aliasing guarantees of its own.
138// Sending/sharing this value is equivalent to sending/sharing the raw C handle value.
139unsafe impl Send for DomainHandle {}
140// SAFETY: See the `Send` rationale above.
141unsafe impl Sync for DomainHandle {}
142
143/// Unique handle for a registered resource.
144#[derive(Clone, Copy, PartialEq, Eq)]
145pub struct ResourceHandle {
146    handle: ffi::nvtxResourceHandle_t,
147}
148
149// SAFETY: `ResourceHandle` is an opaque FFI handle; thread-safety is defined by NVTX.
150unsafe impl Send for ResourceHandle {}
151// SAFETY: See the `Send` rationale above.
152unsafe impl Sync for ResourceHandle {}
153
154/// Unique handle for a registered string.
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub struct StringHandle {
157    handle: ffi::nvtxStringHandle_t,
158}
159
160impl From<StringHandle> for ffi::nvtxStringHandle_t {
161    fn from(value: StringHandle) -> Self {
162        value.handle
163    }
164}
165
166// SAFETY: `StringHandle` is an immutable opaque handle managed by NVTX.
167unsafe impl Send for StringHandle {}
168// SAFETY: See the `Send` rationale above.
169unsafe impl Sync for StringHandle {}
170
171/// Unique handle for a registered user-defined synchronization object.
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub struct SyncUserHandle {
174    handle: ffi::nvtxSyncUser_t,
175}
176
177// SAFETY: `SyncUserHandle` is an opaque NVTX token whose synchronization semantics are in NVTX.
178unsafe impl Send for SyncUserHandle {}
179// SAFETY: See the `Send` rationale above.
180unsafe impl Sync for SyncUserHandle {}
181
182#[cfg(feature = "cuda_runtime")]
183/// An opaque CUDA Runtime event type.
184pub type CudaEvent = ffi::cudaEvent_t;
185#[cfg(feature = "cuda_runtime")]
186/// An opaque CUDA Runtime stream type.
187pub type CudaStream = ffi::cudaStream_t;
188
189#[cfg(feature = "cuda")]
190/// An opaque CUDA context type.
191pub type CuContext = ffi::CUcontext;
192#[cfg(feature = "cuda")]
193/// An opaque CUDA device type.
194pub type CuDevice = ffi::CUdevice;
195#[cfg(feature = "cuda")]
196/// An opaque CUDA event type.
197pub type CuEvent = ffi::CUevent;
198#[cfg(feature = "cuda")]
199/// An opaque CUDA stream type.
200pub type CuStream = ffi::CUstream;
201
202/// Resource types for use within [`crate::ResourceAttributes`].
203pub mod resource_type {
204    #![allow(clippy::wildcard_imports)]
205    #![allow(clippy::unnecessary_cast)]
206
207    use crate::ffi::nvtxResourceGenericType_t::*;
208    // CAST: Bindgen emits these enum constants as either `i32` or `u32` across platforms/targets.
209    // Normalize to the raw 32-bit identifier representation expected by NVTX.
210    /// An unknown resource type.
211    pub const UNKNOWN: u32 = NVTX_RESOURCE_TYPE_UNKNOWN as u32;
212    /// A handle to a generic resource.
213    pub const GENERIC_HANDLE: u32 = NVTX_RESOURCE_TYPE_GENERIC_HANDLE as u32;
214    /// A pointer to a generic resource.
215    pub const GENERIC_POINTER: u32 = NVTX_RESOURCE_TYPE_GENERIC_POINTER as u32;
216    /// A handle to a native thread.
217    pub const GENERIC_THREAD_NATIVE: u32 = NVTX_RESOURCE_TYPE_GENERIC_THREAD_NATIVE as u32;
218    /// A handle to a posix thread.
219    pub const GENERIC_THREAD_POSIX: u32 = NVTX_RESOURCE_TYPE_GENERIC_THREAD_POSIX as u32;
220
221    #[cfg(feature = "cuda")]
222    mod cuda {
223        use crate::ffi::nvtxResourceCUDAType_t::*;
224        // CAST: See `resource_type::UNKNOWN` for cast rationale.
225        /// A CUDA device resource.
226        pub const CUDA_DEVICE: u32 = NVTX_RESOURCE_TYPE_CUDA_DEVICE as u32;
227        /// A CUDA context resource.
228        pub const CUDA_CONTEXT: u32 = NVTX_RESOURCE_TYPE_CUDA_CONTEXT as u32;
229        /// A CUDA stream resource.
230        pub const CUDA_STREAM: u32 = NVTX_RESOURCE_TYPE_CUDA_STREAM as u32;
231        /// A CUDA event resource.
232        pub const CUDA_EVENT: u32 = NVTX_RESOURCE_TYPE_CUDA_EVENT as u32;
233    }
234    #[cfg(feature = "cuda")]
235    pub use cuda::*;
236
237    #[cfg(feature = "cuda_runtime")]
238    mod cuda_runtime {
239        use crate::ffi::nvtxResourceCUDARTType_t::*;
240        // CAST: See `resource_type::UNKNOWN` for cast rationale.
241        /// A CUDA runtime device resource.
242        pub const CUDART_DEVICE: u32 = NVTX_RESOURCE_TYPE_CUDART_DEVICE as u32;
243        /// A CUDA runtime stream resource.
244        pub const CUDART_STREAM: u32 = NVTX_RESOURCE_TYPE_CUDART_STREAM as u32;
245        /// A CUDA runtime event resource.
246        pub const CUDART_EVENT: u32 = NVTX_RESOURCE_TYPE_CUDART_EVENT as u32;
247    }
248    #[cfg(feature = "cuda_runtime")]
249    pub use cuda_runtime::*;
250
251    #[cfg(target_family = "unix")]
252    mod pthread {
253        use crate::ffi::nvtxResourceSyncPosixThreadType_t::*;
254        // CAST: See `resource_type::UNKNOWN` for cast rationale.
255        /// A pthread mutex resource.
256        pub const PTHREAD_MUTEX: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_MUTEX as u32;
257        /// A pthread condition variable resource.
258        pub const PTHREAD_CONDITION: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_CONDITION as u32;
259        /// A pthread rwlock resource.
260        pub const PTHREAD_RWLOCK: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_RWLOCK as u32;
261        /// A pthread barrier resource.
262        pub const PTHREAD_BARRIER: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_BARRIER as u32;
263        /// A pthread spinlock resource.
264        pub const PTHREAD_SPINLOCK: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_SPINLOCK as u32;
265        /// A pthread oncelock resource.
266        pub const PTHREAD_ONCE: u32 = NVTX_RESOURCE_TYPE_SYNC_PTHREAD_ONCE as u32;
267    }
268    #[cfg(target_family = "unix")]
269    pub use pthread::*;
270}
271
272use core::ffi::CStr;
273use widestring::WideCStr;
274
275/// Create a mark within a domain.
276pub fn domain_mark_ex(domain: DomainHandle, event_attrib: &EventAttributes) {
277    // SAFETY: We forward a valid NVTX domain handle plus an immutable attributes pointer.
278    unsafe { crate::ffi::nvtxDomainMarkEx(domain.handle, event_attrib) }
279}
280
281/// Create a mark with an attributes structure.
282pub fn mark_ex(event_attrib: &EventAttributes) {
283    // SAFETY: We pass an immutable attributes pointer directly to NVTX.
284    unsafe { crate::ffi::nvtxMarkEx(event_attrib) }
285}
286
287/// Create a mark with an ASCII string.
288pub fn mark_ascii(message: &CStr) {
289    // SAFETY: `message` is a valid NUL-terminated C string for the call duration.
290    unsafe { crate::ffi::nvtxMarkA(message.as_ptr()) }
291}
292
293/// Create a mark with a Unicode string.
294pub fn mark_unicode(message: &WideCStr) {
295    // SAFETY: `message` points to a valid wide C string for the call duration.
296    unsafe { crate::ffi::nvtxMarkW(message.as_ptr().cast()) }
297}
298
299#[must_use]
300/// Start a process-visible range within a domain with an attributes structure.
301///
302/// To close the range, see [`domain_range_end`].
303pub fn domain_range_start_ex(domain: DomainHandle, event_attrib: &EventAttributes) -> RangeId {
304    // SAFETY: We forward a valid NVTX domain handle plus an immutable attributes pointer.
305    unsafe { crate::ffi::nvtxDomainRangeStartEx(domain.handle, event_attrib) }
306}
307
308#[must_use]
309/// Start a process-visible range with an attributes structure.
310///
311/// To close the range, see [`range_end`].
312pub fn range_start_ex(event_attrib: &EventAttributes) -> RangeId {
313    // SAFETY: We pass an immutable attributes pointer directly to NVTX.
314    unsafe { crate::ffi::nvtxRangeStartEx(event_attrib) }
315}
316
317#[must_use]
318/// Start a process-visible range with an ASCII string.
319///
320/// To close the range, see [`range_end`].
321pub fn range_start_ascii(message: &CStr) -> RangeId {
322    // SAFETY: `message` is a valid NUL-terminated C string for the call duration.
323    unsafe { crate::ffi::nvtxRangeStartA(message.as_ptr()) }
324}
325
326#[must_use]
327/// Start a process-visible range with a Unicode string.
328///
329/// To close the range, see [`range_end`].
330pub fn range_start_unicode(message: &WideCStr) -> RangeId {
331    // SAFETY: `message` points to a valid wide C string for the call duration.
332    unsafe { crate::ffi::nvtxRangeStartW(message.as_ptr().cast()) }
333}
334
335/// End a process-visible range within a domain.
336///
337/// The range id is created by [`domain_range_start_ex`]
338pub fn domain_range_end(domain: DomainHandle, id: RangeId) {
339    // SAFETY: `domain` and `id` originate from NVTX range start APIs.
340    unsafe { crate::ffi::nvtxDomainRangeEnd(domain.handle, id) }
341}
342
343/// End a process-visible range.
344///
345/// The range id is created by one of:
346/// * [`range_start_ascii`]
347/// * [`range_start_unicode`]
348/// * [`range_start_ex`]
349pub fn range_end(id: RangeId) {
350    // SAFETY: `id` originates from an NVTX range start API.
351    unsafe { crate::ffi::nvtxRangeEnd(id) }
352}
353
354#[allow(clippy::must_use_candidate)]
355/// Start a thread-visible range within a domain with an attributes structure.
356///
357/// To close, see [`domain_range_pop`].
358pub fn domain_range_push_ex(domain: DomainHandle, event_attrib: &EventAttributes) -> i32 {
359    // SAFETY: We forward a valid NVTX domain handle plus an immutable attributes pointer.
360    unsafe { crate::ffi::nvtxDomainRangePushEx(domain.handle, event_attrib) }
361}
362
363#[allow(clippy::must_use_candidate)]
364/// Start a thread-visible range with an attributes structure.
365///
366/// To close, see [`range_pop`].
367pub fn range_push_ex(event_attrib: &EventAttributes) -> i32 {
368    // SAFETY: We pass an immutable attributes pointer directly to NVTX.
369    unsafe { crate::ffi::nvtxRangePushEx(event_attrib) }
370}
371
372#[allow(clippy::must_use_candidate)]
373/// Start a thread-visible range with an ASCII string.
374///
375/// To close, see [`range_pop`].
376pub fn range_push_ascii(message: &CStr) -> i32 {
377    // SAFETY: `message` is a valid NUL-terminated C string for the call duration.
378    unsafe { crate::ffi::nvtxRangePushA(message.as_ptr()) }
379}
380
381#[allow(clippy::must_use_candidate)]
382/// Start a thread-visible range with a Unicode string.
383///
384/// To close, see [`range_pop`].
385pub fn range_push_unicode(message: &WideCStr) -> i32 {
386    // SAFETY: `message` points to a valid wide C string for the call duration.
387    unsafe { crate::ffi::nvtxRangePushW(message.as_ptr().cast()) }
388}
389
390#[allow(clippy::must_use_candidate)]
391/// End a thread-visible range within a domain.
392///
393/// The range would have been created via [`domain_range_push_ex`].
394pub fn domain_range_pop(domain: DomainHandle) -> i32 {
395    // SAFETY: `domain` is an opaque handle created by NVTX.
396    unsafe { crate::ffi::nvtxDomainRangePop(domain.handle) }
397}
398
399#[allow(clippy::must_use_candidate)]
400/// End a thread-visible range.
401///
402/// The range would have been created via one of:
403/// * [`range_push_ascii`]
404/// * [`range_push_unicode`]
405/// * [`range_push_ex`]
406pub fn range_pop() -> i32 {
407    // SAFETY: Pops the current thread-local NVTX range stack in this process.
408    unsafe { crate::ffi::nvtxRangePop() }
409}
410
411#[must_use]
412/// Create a named resource within a domain.
413///
414/// To destroy the resource, see [`domain_resource_destroy`].
415pub fn domain_resource_create(domain: DomainHandle, attribs: ResourceAttributes) -> ResourceHandle {
416    ResourceHandle {
417        // SAFETY: `domain` is an opaque NVTX handle and `attribs` lives across the call.
418        handle: unsafe {
419            crate::ffi::nvtxDomainResourceCreate(
420                domain.handle,
421                core::ptr::addr_of!(attribs).cast_mut(),
422            )
423        },
424    }
425}
426
427/// Destroy a named resource.
428///
429/// The named resource is created by [`domain_resource_create`].
430pub fn domain_resource_destroy(resource: ResourceHandle) {
431    // SAFETY: `resource` was created by NVTX and is consumed by this destroy call.
432    unsafe { crate::ffi::nvtxDomainResourceDestroy(resource.handle) }
433}
434
435/// Name a category within a domain with an ASCII string.
436pub fn domain_name_category_ascii(domain: DomainHandle, category: u32, name: &CStr) {
437    // SAFETY: `domain` is valid and `name` is a valid C string.
438    unsafe { crate::ffi::nvtxDomainNameCategoryA(domain.handle, category, name.as_ptr()) }
439}
440
441/// Name a category within a domain with a Unicode string.
442pub fn domain_name_category_unicode(domain: DomainHandle, category: u32, name: &WideCStr) {
443    // SAFETY: `domain` is valid and `name` is a valid wide C string.
444    unsafe { crate::ffi::nvtxDomainNameCategoryW(domain.handle, category, name.as_ptr().cast()) }
445}
446
447/// Name a category with an ASCII string.
448pub fn name_category_ascii(category: u32, name: &CStr) {
449    // SAFETY: `name` is a valid C string.
450    unsafe { crate::ffi::nvtxNameCategoryA(category, name.as_ptr()) }
451}
452
453/// Name a category with a Unicode string.
454pub fn name_category_unicode(category: u32, name: &WideCStr) {
455    // SAFETY: `name` is a valid wide C string.
456    unsafe { crate::ffi::nvtxNameCategoryW(category, name.as_ptr().cast()) }
457}
458
459/// Name an OS thread with an ASCII string.
460///
461/// Note: the threadId must be an operating-specific thread id. On Linux this would be a process's tid.
462pub fn name_os_thread_ascii(thread_id: u32, name: &CStr) {
463    // SAFETY: `name` is a valid C string and `thread_id` is passed through verbatim.
464    unsafe { crate::ffi::nvtxNameOsThreadA(thread_id, name.as_ptr()) }
465}
466
467/// Name an OS thread with a Unicode string.
468///
469/// Note: the threadId must be an operating-specific thread id. On Linux this would be a process's tid.
470pub fn name_os_thread_unicode(thread_id: u32, name: &WideCStr) {
471    // SAFETY: `name` is a valid wide C string and `thread_id` is passed through verbatim.
472    unsafe { crate::ffi::nvtxNameOsThreadW(thread_id, name.as_ptr().cast()) }
473}
474
475#[must_use]
476/// Register an immutable ASCII string with a domain.
477pub fn domain_register_string_ascii(domain: DomainHandle, string: &CStr) -> StringHandle {
478    StringHandle {
479        // SAFETY: `domain` is valid and `string` is a valid C string for the call.
480        handle: unsafe { crate::ffi::nvtxDomainRegisterStringA(domain.handle, string.as_ptr()) },
481    }
482}
483
484#[must_use]
485/// Register an immutable Unicode string with a domain.
486pub fn domain_register_string_unicode(domain: DomainHandle, string: &WideCStr) -> StringHandle {
487    StringHandle {
488        // SAFETY: `domain` is valid and `string` is a valid wide C string for the call.
489        handle: unsafe {
490            crate::ffi::nvtxDomainRegisterStringW(domain.handle, string.as_ptr().cast())
491        },
492    }
493}
494
495#[must_use]
496/// Create a new domain with a given ASCII string name.
497pub fn domain_create_ascii(name: &CStr) -> DomainHandle {
498    DomainHandle {
499        // SAFETY: `name` is a valid C string for the call duration.
500        handle: unsafe { crate::ffi::nvtxDomainCreateA(name.as_ptr()) },
501    }
502}
503
504#[must_use]
505/// Create a new domain with a given Unicode string name.
506pub fn domain_create_unicode(name: &WideCStr) -> DomainHandle {
507    DomainHandle {
508        // SAFETY: `name` is a valid wide C string for the call duration.
509        handle: unsafe { crate::ffi::nvtxDomainCreateW(name.as_ptr().cast()) },
510    }
511}
512
513/// Destroy a domain.
514///
515/// The domain is created by [`domain_create_ascii`] or [`domain_create_unicode`].
516pub fn domain_destroy(domain: DomainHandle) {
517    // SAFETY: `domain` is an opaque handle created by NVTX.
518    unsafe { crate::ffi::nvtxDomainDestroy(domain.handle) }
519}
520
521#[cfg(feature = "cuda")]
522/// Name a CUDA device with an ASCII string.
523pub fn name_cudevice_ascii(device: CuDevice, name: &CStr) {
524    // SAFETY: `device` is forwarded opaquely and `name` is a valid C string.
525    unsafe { crate::ffi::nvtxNameCuDeviceA(device, name.as_ptr()) }
526}
527
528#[cfg(feature = "cuda")]
529/// Name a CUDA device with a Unicode string.
530pub fn name_cudevice_unicode(device: CuDevice, name: &WideCStr) {
531    // SAFETY: `device` is forwarded opaquely and `name` is a valid wide C string.
532    unsafe { crate::ffi::nvtxNameCuDeviceW(device, name.as_ptr().cast()) }
533}
534
535#[cfg(feature = "cuda")]
536/// Name a CUDA context with an ASCII string.
537///
538/// # Safety
539/// This function is marked unsafe because of the pointer parameter referring to the CUDA context.
540pub unsafe fn name_cucontext_ascii(context: CuContext, name: &CStr) {
541    // SAFETY: Caller guarantees `context` is a valid CUDA context handle.
542    unsafe { crate::ffi::nvtxNameCuContextA(context, name.as_ptr()) }
543}
544
545#[cfg(feature = "cuda")]
546/// Name a CUDA context with a Unicode string.
547///
548/// # Safety
549/// This function is marked unsafe because of the pointer parameter referring to the CUDA context.
550pub unsafe fn name_cucontext_unicode(context: CuContext, name: &WideCStr) {
551    // SAFETY: Caller guarantees `context` is a valid CUDA context handle.
552    unsafe { crate::ffi::nvtxNameCuContextW(context, name.as_ptr().cast()) }
553}
554
555#[cfg(feature = "cuda")]
556/// Name a CUDA stream with an ASCII string.
557///
558/// # Safety
559/// This function is marked unsafe because of the pointer parameter referring to the CUDA stream.
560pub unsafe fn name_custream_ascii(stream: CuStream, name: &CStr) {
561    // SAFETY: Caller guarantees `stream` is a valid CUDA stream handle.
562    unsafe { crate::ffi::nvtxNameCuStreamA(stream, name.as_ptr()) }
563}
564
565#[cfg(feature = "cuda")]
566/// Name a CUDA stream with a Unicode string.
567///
568/// # Safety
569/// This function is marked unsafe because of the pointer parameter referring to the CUDA stream.
570pub unsafe fn name_custream_unicode(stream: CuStream, name: &WideCStr) {
571    // SAFETY: Caller guarantees `stream` is a valid CUDA stream handle.
572    unsafe { crate::ffi::nvtxNameCuStreamW(stream, name.as_ptr().cast()) }
573}
574
575#[cfg(feature = "cuda")]
576/// Name a CUDA event with an ASCII string.
577///
578/// # Safety
579/// This function is marked unsafe because of the pointer parameter referring to the CUDA event.
580pub unsafe fn name_cuevent_ascii(event: CuEvent, name: &CStr) {
581    // SAFETY: Caller guarantees `event` is a valid CUDA event handle.
582    unsafe { crate::ffi::nvtxNameCuEventA(event, name.as_ptr()) }
583}
584
585#[cfg(feature = "cuda")]
586/// Name a CUDA event with a Unicode string.
587///
588/// # Safety
589/// This function is marked unsafe because of the pointer parameter referring to the CUDA event.
590pub unsafe fn name_cuevent_unicode(event: CuEvent, name: &WideCStr) {
591    // SAFETY: Caller guarantees `event` is a valid CUDA event handle.
592    unsafe { crate::ffi::nvtxNameCuEventW(event, name.as_ptr().cast()) }
593}
594
595#[cfg(feature = "cuda_runtime")]
596/// Name a CUDA Runtime device with an ASCII string.
597pub fn name_cuda_device_ascii(device: i32, name: &CStr) {
598    // SAFETY: `device` is passed through as the CUDA runtime device ID and `name` is valid.
599    unsafe { crate::ffi::nvtxNameCudaDeviceA(device, name.as_ptr()) }
600}
601
602#[cfg(feature = "cuda_runtime")]
603/// Name a CUDA Runtime device with a Unicode string.
604pub fn name_cuda_device_unicode(device: i32, name: &WideCStr) {
605    // SAFETY: `device` is passed through as the CUDA runtime device ID and `name` is valid.
606    unsafe { crate::ffi::nvtxNameCudaDeviceW(device, name.as_ptr().cast()) }
607}
608
609#[cfg(feature = "cuda_runtime")]
610/// Name a CUDA Runtime stream with an ASCII string.
611///
612/// # Safety
613/// This function is marked unsafe because of the pointer parameter referring to the CUDA stream.
614pub unsafe fn name_cuda_stream_ascii(stream: CudaStream, name: &CStr) {
615    // SAFETY: Caller guarantees `stream` is a valid CUDA runtime stream handle.
616    unsafe { crate::ffi::nvtxNameCudaStreamA(stream, name.as_ptr()) }
617}
618
619#[cfg(feature = "cuda_runtime")]
620/// Name a CUDA Runtime stream with a Unicode string.
621///
622/// # Safety
623/// This function is marked unsafe because of the pointer parameter referring to the CUDA stream.
624pub unsafe fn name_cuda_stream_unicode(stream: CudaStream, name: &WideCStr) {
625    // SAFETY: Caller guarantees `stream` is a valid CUDA runtime stream handle.
626    unsafe { crate::ffi::nvtxNameCudaStreamW(stream, name.as_ptr().cast()) }
627}
628
629#[cfg(feature = "cuda_runtime")]
630/// Name a CUDA Runtime event with an ASCII string.
631///
632/// # Safety
633/// This function is marked unsafe because of the pointer parameter referring to the CUDA event.
634pub unsafe fn name_cuda_event_ascii(event: CudaEvent, name: &CStr) {
635    // SAFETY: Caller guarantees `event` is a valid CUDA runtime event handle.
636    unsafe { crate::ffi::nvtxNameCudaEventA(event, name.as_ptr()) }
637}
638
639#[cfg(feature = "cuda_runtime")]
640/// Name a CUDA Runtime event with a Unicode string.
641///
642/// # Safety
643/// This function is marked unsafe because of the pointer parameter referring to the CUDA event.
644pub unsafe fn name_cuda_event_unicode(event: CudaEvent, name: &WideCStr) {
645    // SAFETY: Caller guarantees `event` is a valid CUDA runtime event handle.
646    unsafe { crate::ffi::nvtxNameCudaEventW(event, name.as_ptr().cast()) }
647}
648
649#[must_use]
650/// Create a new user-defined synchronization within a domain.
651pub fn domain_syncuser_create(domain: DomainHandle, attribs: SyncUserAttributes) -> SyncUserHandle {
652    SyncUserHandle {
653        // SAFETY: `domain` is valid and `attribs` lives across the FFI call.
654        handle: unsafe {
655            crate::ffi::nvtxDomainSyncUserCreate(
656                domain.handle,
657                core::ptr::addr_of!(attribs).cast_mut(),
658            )
659        },
660    }
661}
662
663/// Destroy a user-defined synchronization.
664///
665/// Created by [`domain_syncuser_create`].
666pub fn domain_syncuser_destroy(handle: SyncUserHandle) {
667    // SAFETY: `handle` was created by NVTX and is consumed by this destroy call.
668    unsafe { crate::ffi::nvtxDomainSyncUserDestroy(handle.handle) }
669}
670
671/// Indicate that a user-defined synchronization started to acquire.
672pub fn domain_syncuser_acquire_start(handle: SyncUserHandle) {
673    // SAFETY: `handle` is an opaque sync-user token created by NVTX.
674    unsafe { crate::ffi::nvtxDomainSyncUserAcquireStart(handle.handle) }
675}
676
677/// Indicate that a user-defined synchronization acquisition failed.
678///
679/// Note: this call is only valid after a call to [`domain_syncuser_acquire_start`].
680pub fn domain_syncuser_acquire_failed(handle: SyncUserHandle) {
681    // SAFETY: `handle` is an opaque sync-user token created by NVTX.
682    unsafe { crate::ffi::nvtxDomainSyncUserAcquireFailed(handle.handle) }
683}
684
685/// Indicate that a user-defined synchronization acquisition succeeded.
686///
687/// Note: this call is only valid after a call to [`domain_syncuser_acquire_start`].
688pub fn domain_syncuser_acquire_success(handle: SyncUserHandle) {
689    // SAFETY: `handle` is an opaque sync-user token created by NVTX.
690    unsafe { crate::ffi::nvtxDomainSyncUserAcquireSuccess(handle.handle) }
691}
692
693/// Indicate that a user-defined synchronization is released.
694///
695/// Note: this call is only valid after a call to [`domain_syncuser_acquire_success`].
696pub fn domain_syncuser_acquire_releasing(handle: SyncUserHandle) {
697    // SAFETY: `handle` is an opaque sync-user token created by NVTX.
698    unsafe { crate::ffi::nvtxDomainSyncUserReleasing(handle.handle) }
699}