Skip to content

feat(nvtx): capture wide-char (*W) NVTX surface as UTF-8 - #540

Merged
rapids-bot[bot] merged 1 commit into
rapidsai:mainfrom
9prady9:nvtx-widechar-desync
Aug 7, 2026
Merged

feat(nvtx): capture wide-char (*W) NVTX surface as UTF-8#540
rapids-bot[bot] merged 1 commit into
rapidsai:mainfrom
9prady9:nvtx-widechar-desync

Conversation

@9prady9

@9prady9 9prady9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the NVTX *W (wide-char / Unicode) callback surface on Linux, where wchar_t is 32-bit UTF-32. Each code unit maps directly to a Unicode scalar value via char::from_u32; the result enters the event stream as a plain NvtxMessage::String — identical to the ASCII surface from the downstream perspective.

  • copy_wchar iterates a NUL-terminated wchar_t* and builds an owned UTF-8 String
  • All five CORE *W callbacks (MarkW, RangeStartW, RangePushW, NameCategoryW, NameOsThreadW) are now full implementations instead of warn-once stubs
  • NVTX_MESSAGE_TYPE_UNICODE in event attributes (nvtxDomainRangePushEx etc.) is handled in decode_message alongside the existing ASCII and registered-string cases
  • Only nvtx-injection is touched — nvtx-events, nvtx-bridge, and nvtx-analyzer are unchanged since wide strings arrive as NvtxMessage::String downstream

Test plan

  • pixi run cargo test -p nvtx-injection — 30 tests pass (5 new: copy_wchar for ASCII/Unicode/null, mark_w, range_push_w, range_start_w, unicode_message_type_in_event_attributes_is_decoded)
  • pixi run cargo test -p nvtx-analyzer -p nvtx-example — all pass, no downstream changes

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Wide-character NVTX messages now convert to UTF-8 and dispatch marker, range, category-name, and thread-name events. Wide range operations preserve synthesized IDs, nesting levels, thread IDs, and documented handling for unmatched operations.

Changes

NVTX wide-character decoding

Layer / File(s) Summary
Conversion helpers and Unicode event construction
integrations/nvtx/injection/src/convert.rs
Wide strings and Unicode messages now produce owned UTF-8 data. Wide event constructors preserve identifiers and handle null or invalid input. Tests cover conversion and event attributes.
Wide-character callback dispatch
integrations/nvtx/injection/src/callbacks.rs
Wide marker, range, category-name, and thread-name callbacks now dispatch converted events. Documentation describes unmatched range closes and uncaptured pops.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: feature request

Suggested reviewers: johanpel, dhruv9vats, mbrobbel

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: capturing wide-character NVTX callbacks as UTF-8.
Description check ✅ Passed The description explains the implementation and testing; omitted issue and screenshot sections are non-critical for this non-UI change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@johanpel

johanpel commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Is there a reason we couldn't just support the wide char APIs, e.g. using: https://github.com/VoidStarKat/widestring-rs to convert?

I have doubts about this work-around since the sentinel values clash with NVTX' spec (e.g. id uniqueness) and it adds complexity that doesn't need to exist if we were to simply support those APIs.

@9prady9

9prady9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Is there a reason we couldn't just support the wide char APIs, e.g. using: https://github.com/VoidStarKat/widestring-rs to convert?

I have doubts about this work-around since the sentinel values clash with NVTX' spec (e.g. id uniqueness) and it adds complexity that doesn't need to exist if we were to simply support those APIs.

Its not used anywhere in our current targets and it adds a lot more code which isn't used anywhere. Adding this when there is a consumer is easier with the tools we have now.

I have doubts about this work-around since the sentinel values clash with NVTX' spec (e.g. id uniqueness) and it adds complexity that doesn't need to exist if we were to simply support those APIs.

I didn't understand what you mean. Fix is to address the current behavior of no matching start/push for a end/pop, respectively.

@johanpel

johanpel commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Its not used anywhere in our current targets and it adds a lot more code which isn't used anywhere. Adding this when there is a consumer is easier with the tools we have now.

If the wide-character APIs are not used anywhere, what requires this workaround now?

I didn't understand what you mean. Fix is to address the current behavior of no matching start/push for a end/pop, respectively.

Is the missing captured start/push event caused by something outside our control, or by our choice of not dispatching an event for the *W callbacks?

@9prady9

9prady9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Its not used anywhere in our current targets and it adds a lot more code which isn't used anywhere. Adding this when there is a consumer is easier with the tools we have now.

If the wide-character APIs are not used anywhere, what requires this workaround now?

Without the surface API to capture these, the push/pops incorrectly get hold of any other push/pop and/or silently don't say anything. We surface a warning when we encounter these by providing the entry points at least.

I didn't understand what you mean. Fix is to address the current behavior of no matching start/push for a end/pop, respectively.

Is the missing captured start/push event caused by something outside our control, or by our choice of not dispatching an event for the *W callbacks?

These are actual nvtx API calls out of our control right, handling them incorrectly is a bug in this crate not the other way around.

@johanpel

johanpel commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

handling them incorrectly is a bug in this crate not the other way around.

Indeed, the bug is that we're not emitting events we're supposed to be emitting. Why is using sentinel values and an additional thread local stack to filter out events better than actually emitting those events?

@9prady9
9prady9 force-pushed the nvtx-widechar-desync branch from c4dc88c to cd76b7b Compare August 6, 2026 14:27
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@9prady9 9prady9 changed the title fix(nvtx): drop pop/end paired with an uncaptured wide-char range feat(nvtx): capture wide-char (*W) NVTX surface as UTF-8 Aug 6, 2026
@9prady9

9prady9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

handling them incorrectly is a bug in this crate not the other way around.

Indeed, the bug is that we're not emitting events we're supposed to be emitting. Why is using sentinel values and an additional thread local stack to filter out events better than actually emitting those events?

You're right, I got it wrong. Updated the PR — *W callbacks are now full implementations converting UTF-32 to UTF-8 via char::from_u32. Sentinel and suppression machinery gone.

@9prady9
9prady9 force-pushed the nvtx-widechar-desync branch from cd76b7b to 24983c0 Compare August 6, 2026 14:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
integrations/nvtx/injection/src/callbacks.rs (1)

241-244: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Implement event suppression for close events matching uncaptured push operations.

The documentation at lines 239–240 and 279–280 states that RangeEnd and RangePop events closing pushes not captured by the injection layer must be dropped. The code currently dispatches these events unconditionally. The suppression functions referenced in the comments (init::UNDECODABLE_RANGE_ID and init::pop_is_suppressed) do not exist.

Add tracking to distinguish ranges and pops initiated by the application from those initiated by the injection layer:

  • integrations/nvtx/injection/src/callbacks.rs#L241–244: Implement a guard that drops RangeEnd events for application-initiated range IDs before dispatch.
  • integrations/nvtx/injection/src/callbacks.rs#L281–287: Implement a guard that drops RangePop events for application-initiated pops before dispatch.

Preserve the nesting-level return values for faithful application-side semantics, but filter the dispatched events.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/nvtx/injection/src/callbacks.rs` around lines 241 - 244, The
callbacks must suppress dispatch of close events corresponding to
application-initiated, uncaptured pushes while preserving the NVTX nesting-level
return semantics. In integrations/nvtx/injection/src/callbacks.rs:241-244,
update on_range_end to guard application range IDs using the shared
undecodable-range tracking, dispatching only captured ranges; in
integrations/nvtx/injection/src/callbacks.rs:281-287, update on_range_pop to use
pop suppression tracking and dispatch only captured pops, while retaining each
callback’s existing return value behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@integrations/nvtx/injection/src/callbacks.rs`:
- Around line 241-244: The callbacks must suppress dispatch of close events
corresponding to application-initiated, uncaptured pushes while preserving the
NVTX nesting-level return semantics. In
integrations/nvtx/injection/src/callbacks.rs:241-244, update on_range_end to
guard application range IDs using the shared undecodable-range tracking,
dispatching only captured ranges; in
integrations/nvtx/injection/src/callbacks.rs:281-287, update on_range_pop to use
pop suppression tracking and dispatch only captured pops, while retaining each
callback’s existing return value behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: f734de27-368b-4340-983d-e73150081736

📥 Commits

Reviewing files that changed from the base of the PR and between 5db3659 and cd76b7b.

📒 Files selected for processing (3)
  • integrations/nvtx/injection/src/callbacks.rs
  • integrations/nvtx/injection/src/convert.rs
  • integrations/nvtx/injection/src/init.rs

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
integrations/nvtx/injection/src/callbacks.rs-238-240 (1)

238-240: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove stale suppression documentation.

The shown callbacks always construct and dispatch RangeEnd and RangePop events. The documented sentinel and suppression paths are not present in this dispatch flow.

  • integrations/nvtx/injection/src/callbacks.rs#L238-L240: Remove the claim that ends using init::UNDECODABLE_RANGE_ID are dropped.
  • integrations/nvtx/injection/src/callbacks.rs#L276-L280: Remove the claim that init::pop_is_suppressed drops pops.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/nvtx/injection/src/callbacks.rs` around lines 238 - 240, Remove
the stale suppression claims from the callback documentation: in
integrations/nvtx/injection/src/callbacks.rs lines 238-240, remove the statement
that init::UNDECODABLE_RANGE_ID ends are dropped; at lines 276-280, remove the
statement that init::pop_is_suppressed drops pops. No dispatch logic changes are
needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Other comments:
In `@integrations/nvtx/injection/src/callbacks.rs`:
- Around line 238-240: Remove the stale suppression claims from the callback
documentation: in integrations/nvtx/injection/src/callbacks.rs lines 238-240,
remove the statement that init::UNDECODABLE_RANGE_ID ends are dropped; at lines
276-280, remove the statement that init::pop_is_suppressed drops pops. No
dispatch logic changes are needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 617e93e7-a944-4c3c-aeb7-75218587df18

📥 Commits

Reviewing files that changed from the base of the PR and between 5db3659 and 24983c0.

📒 Files selected for processing (2)
  • integrations/nvtx/injection/src/callbacks.rs
  • integrations/nvtx/injection/src/convert.rs

On Linux wchar_t is 32-bit (UTF-32), so each code unit is a Unicode
scalar value. copy_wchar iterates the NUL-terminated sequence and builds
an owned UTF-8 String that enters the event stream as a plain
NvtxMessage::String — identical to the ASCII surface from the
downstream perspective. No changes to nvtx-events, the analyzer, or
the bridge.

Previously the *W callbacks were stubs that warned once and returned
sentinel values / suppressed matching close events to avoid orphaning
the stream. That approach violated the nvtxRangeId_t uniqueness
contract (u64::MAX returned for every RangeStartW call) and added more
machinery than it saved. Replacing the stubs with real implementations
removes the suppression thread-local, the sentinel constant, and the
guards in on_range_end / on_range_pop.

The NVTX_MESSAGE_TYPE_UNICODE attribute path (domain-scoped *Ex calls
with messageType=UNICODE) is also handled in decode_message alongside
the existing ASCII and RegisteredHandle cases.

Five new convert tests cover the wchar conversion directly:
copy_wchar for ASCII, Unicode code points (U+1F600), and null;
mark_w, range_push_w, range_start_w for the default-domain surface;
and unicode_message_type_in_event_attributes_is_decoded for the
domain-scoped attribute path.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@9prady9
9prady9 force-pushed the nvtx-widechar-desync branch from 24983c0 to eade0a2 Compare August 6, 2026 14:36
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
integrations/nvtx/injection/src/convert.rs (1)

1260-1282: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for invalid UTF-32 scalar values.

copy_wchar replaces invalid scalar values with char::REPLACEMENT_CHARACTER, but the tests cover only valid values and null. Add a surrogate-value case to preserve this FFI conversion behavior.

Proposed test
+    #[test]
+    fn copy_wchar_replaces_invalid_unicode_scalar_values() {
+        let wide = [0xD800 as libc::wchar_t, 0];
+        // SAFETY: `wide` is a valid NUL-terminated wchar_t array.
+        let s = unsafe { copy_wchar_pub(wide.as_ptr()) };
+        assert_eq!(s, "\u{FFFD}");
+    }

As per coding guidelines, “New Rust components must include accompanying tests.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/nvtx/injection/src/convert.rs` around lines 1260 - 1282, Add a
test alongside the existing copy_wchar tests that constructs a NUL-terminated
wide string containing a surrogate code point, invokes copy_wchar_pub, and
asserts the invalid scalar is converted to char::REPLACEMENT_CHARACTER while
surrounding valid text remains intact.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@integrations/nvtx/injection/src/convert.rs`:
- Around line 1260-1282: Add a test alongside the existing copy_wchar tests that
constructs a NUL-terminated wide string containing a surrogate code point,
invokes copy_wchar_pub, and asserts the invalid scalar is converted to
char::REPLACEMENT_CHARACTER while surrounding valid text remains intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: a2855a84-67e9-4e9d-b002-fce5afd287e4

📥 Commits

Reviewing files that changed from the base of the PR and between 5db3659 and eade0a2.

📒 Files selected for processing (2)
  • integrations/nvtx/injection/src/callbacks.rs
  • integrations/nvtx/injection/src/convert.rs

@johanpel johanpel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks for adding wide char support @9prady9!

@9prady9

9prady9 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 6f4b9c6 into rapidsai:main Aug 7, 2026
20 checks passed
@9prady9
9prady9 deleted the nvtx-widechar-desync branch August 7, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants