NVIDIA Tools Extension Library (NVTX)

repository·dev·Indexed 19 days ago

https://github.com/nvidia/nvtx

A cross-platform API for annotating source code with metadata to visualize execution timelines, profile code ranges, and track resource usage in developer tools like NVIDIA Nsight Systems. It provides a header-only C/C++ library (v3) and a Python code annotation library (v0.2.16), supporting markers, push/pop ranges, start/end ranges, and resource naming for OS threads and CUDA streams.

Tokens
33.2K
Snippets
66
Records
131
Agent score
68%

What's inside NVTX

  1. What is NVTX and how does it work?

    dev

    NVTX (NVIDIA Tools Extension Library) is a cross-platform API used to annotate source code with contextual information. This information is consumed by developer tools (like NVIDIA Nsight Systems) to provide meaningful insights during profiling.

    Key Behavior: By default, NVTX API calls do nothing. They only become active when the program is launched from a developer tool that implements the NVTX API. When active, these calls can be used to:

    • Record traces on a timeline.
    • Build statistical profiles of time spent in specific code sections.
    • Print messages to the console.
    • Enable/disable specific tool features based on the current execution context.
  2. Supported NVIDIA tools for NVTX

    dev

    NVTX annotations are natively supported by several NVIDIA profiling and analysis tools:

    • Nsight Systems: Logs NVTX calls and displays them on a timeline alongside driver, OS, and hardware events.
    • Nsight Compute: Uses NVTX ranges to focus deep-dive GPU performance analysis on specific code sections.
    • Nsight Graphics: Uses NVTX ranges to set bounds for range profiling within the Frame Debugger.
    • CUPTI API: Supports recording traces of NVTX calls.
  3. What is NVTXW and when to use it

    dev

    NVTXW ("NVTX Writer") is an offline C API used to deliver pre-collected trace data (events, counters, and timing information) to tools via an NVTXW backend.

    Unlike standard NVTX, which performs online instrumentation by intercepting calls during a live process, NVTXW is designed for programmatic offline import.

    Use NVTXW when:

    • You have custom profiler/framework data that you want to render on a tool's timeline (e.g., Nsight Systems).
    • You need to replay a previously captured trace.
    • You are converting third-party trace files (like OTF2) into NVTX reports.
    • You want to merge foreign trace data into an existing profiler report.
    • You are building a synthetic-report generator for testing or demos.

    In the NVTXW model, you supply timestamps explicitly rather than relying on the tool to capture them at the moment of the API call.

  4. Understand NVTXW thread safety guarantees

    dev

    NVTXW provides specific thread-safety guarantees that producers must follow:

    • Concurrent Writes: Distinct streams can be written to concurrently from different threads without requiring producer-side synchronization.
    • Single Stream Writes: You should not assume that concurrent writes to a single stream are safe.
    • Lifecycle and Registration: Calls related to lifecycle and registration (e.g., SessionBegin, StreamOpen, StreamClose, SessionEnd, and all *Register functions) are not assumed to be thread-safe. These must be serialized and should not overlap with data writes.
  5. How the NVTXW (NVTX Writer) Loader works

    dev

    The NVTXW API (nvtxw3/nvtxw3.h) is used to ingest data produced outside the live NVTX injection path. The actual writing is handled by a backend library (e.g., libnvtxw3.so) loaded at runtime.

    The Reference Loader

    The nvtxw3-loader is a small, compiled static library (not header-only) that provides a convenient way to locate and load the backend. It is exposed via the CMake target nvtxw3-loader (or nvtx3::nvtxw3-loader).

    Loading Priority for nvtxwLoad:

    1. The NVTXW3_LIBRARY environment variable.
    2. The library argument passed to the function (filename/path).
    3. Default search (executable directory, standard library paths, and CWD) if the argument is NULL.

    Integration

    • With CMake: Link against nvtxw3-loader. This target transitively links nvtx3-c and the platform's dynamic loader library (like dl).
    • Without CMake: Manually compile src/nvtxw3_loader.c and include the include/ directory, linking against the dynamic-loader library (e.g., -ldl).

    Note: The loader is a reference implementation. You can implement your own loading mechanism as long as you resolve the nvtxwGetInterface symbol and call it with the correct version (e.g., NVTXW_INTERFACE_VERSION).

    add_executable(my_writer main.c)
    target_link_libraries(my_writer PRIVATE nvtx3::nvtxw3-loader)
  6. Understand schema finalization logic

    dev

    Schemas are finalized eagerly when inserted into NvtxPayloadRegistry::AddSchema.

    Requirements & Constraints:

    • Dependency Order: All nested schema dependencies must be registered and finalized before they are referenced.
    • No Cycles: Cyclic dependencies are not supported.
    • Failure Handling: If finalization fails (due to invalid layout or unresolved dependencies), registration returns 0 and the schema is not stored.

    What finalization computes:

    1. Array layout classification: Maps flags to PayloadArrayLayout (None, FixedSize, LengthIndex, ZeroTerminated).
    2. Element sizes: Resolves sizes from nvtxPayloadEntryTypeInfo_t or built-in defaults. For nested static schemas, it uses the staticPayloadSize of the child.
    3. Implicit offset resolution: Computes offsets for entries where offset is 0, respecting alignment and the schema's packAlign value.
    4. Schema alignment: Determines the schema's overall alignment based on the maximum member alignment.
    5. Static payload size: Ensures the total size covers all entries; auto-adjusts upward if the user-specified size is too small.
    6. Length-source marking: Marks entries used as length indices for NVTX_PAYLOAD_ENTRY_FLAG_ARRAY_LENGTH_INDEX arrays.
    7. Entry kind resolution: Classifies custom type IDs as NestedSchema, Enum, or Unknown.
  7. Supported platforms and architectures for NVTX

    dev

    NVTX is designed for the following environments:

    • Operating Systems: Windows, Linux, and other POSIX-like platforms (including cygwin), and Android.
    • Process Bit-width: Both 64-bit and 32-bit processes are supported.
    • CPU Architecture: No restrictions.

    Important Limitations:

    • No GPU Support: NVTX is not supported in GPU code (e.g., __device__ functions in CUDA). For efficient instrumentation of CUDA GPU code, use the pmevent PTX instruction.
    • Dynamic Library Requirement: NVTX requires the platform's standard API to load a dynamic library (.dll or .so).
  8. Understanding NVTX overhead and initialization

    dev

    Overhead Behavior

    • When no tool is present: The first NVTX call initializes the library and disables all functions. Subsequent calls become lightweight, inlined instructions that jump over the disabled call.
    • When a tool is present: Initialization configures the API to jump directly into the tool's implementation. The overhead is then determined by the tool itself.

    Managing Initialization Latency

    The first NVTX call can incur significant overhead while loading the tool. If your program is latency-sensitive (e.g., a game), this first call might cause unexpected behavior. To avoid this, use the nvtxInitialize C API function to force-initialize NVTX at a convenient time during program startup.

  9. Configure Stream Ordering and Skid

    dev

    You can optimize backend processing by describing how sorted your stream data is using nvtxwStreamAttributes_t. These settings are applied during StreamOpen.

    Interleaving

    Set orderInterleaving to define the scope of ordering:

    • NVTXW_STREAM_ORDER_INTERLEAVING_NONE: Ordering applies to the entire stream.
    • NVTXW_STREAM_ORDER_INTERLEAVING_SCOPE: Ordering applies only within sequences of the same scope.

    Ordering Type

    Set orderingType to define what "sorted" means:

    • NVTXW_STREAM_ORDERING_TYPE_UNKNOWN: No ordering guarantee (default).
    • NVTXW_STREAM_ORDERING_TYPE_STRICT: Entries are written in exact timestamp order.
    • NVTXW_STREAM_ORDERING_TYPE_PACKED_RANGE_START: Ranges are ordered by their begin time.
    • NVTXW_STREAM_ORDERING_TYPE_PACKED_RANGE_END: Ranges are ordered by their end time.

    Skid

    If the stream is only partially sorted, use orderingSkid and orderingSkidAmount to describe the deviation:

    • NVTXW_STREAM_ORDERING_SKID_NONE: Ordering is exact.
    • NVTXW_STREAM_ORDERING_SKID_TIME_NS: Entries may move backward by at most a fixed number of nanoseconds.
    • NVTXW_STREAM_ORDERING_SKID_EVENT_COUNT: At most a fixed number of following entries may have an earlier timestamp.
  10. Isolate library annotations using NVTX domains

    dev

    To prevent annotation data from different libraries from clashing, each library should create and use its own dedicated nvtx.Domain. This allows profiling tools to group data by library and enables users to enable or disable specific library annotations during execution.

    Use hierarchical category names (e.g., filesystem/path/to/category) within a domain to organize annotations into a logical tree structure that tools can navigate.

  11. Use the Streaming Visitor model to process payloads

    dev

    The NVTX parser uses a Streaming Visitor model via the PayloadStreamVisitor interface. Instead of building an intermediate data structure, it emits a depth-first stream of typed events. This ensures constant memory usage regardless of payload complexity and allows for incremental output generation.

    To implement a custom processor, you can implement the PayloadStreamVisitor interface and handle the following event sequence:

    OnBeginPayloads(count)
      OnPayloadBegin(index, schemaId, size, name)
        OnFieldBegin(name, description)
          [OnArrayBegin(length)]
            OnSignedInteger / OnUnsignedInteger / OnFloatingPoint / 
            OnString / OnRawBytes / 
            OnObjectBegin ... OnObjectEnd
          [OnArrayEnd]
        OnFieldEnd
        ...
      OnPayloadEnd
      ...
    OnEndPayloads
    OnBeginPayloads(count)
      OnPayloadBegin(index, schemaId, size, name)
        OnFieldBegin(name, description)
          [OnArrayBegin(length)]
            OnSignedInteger / OnUnsignedInteger / OnFloatingPoint /
            OnString / OnRawBytes /
            OnObjectBegin ... OnObjectEnd
          [OnArrayEnd]
        OnFieldEnd
        ...
      OnPayloadEnd
      ...
    OnEndPayloads
  12. How the NVTX Payload Parser works

    dev

    The NvtxPayloadParser::ProcessPayloads method is the entry point for decoding NVTX payloads. It processes nvtxPayloadData_t elements by:

    1. Validating the payload pointer, size, and schema ID.
    2. Resolving SIZE_MAX payloads for null-terminated C-string types by scanning for the terminator.
    3. Routing predefined types (where schema ID is < NVTX_PAYLOAD_SCHEMA_ID_STATIC_START) to EmitPredefinedTypePayload. If the payload size is a multiple of the element size, it is automatically detected as a fixed-size array.
    4. Looking up registered and finalized schemas for custom IDs, then iterating through fields via VisitSchemaFields.