Skip to content

Exposes cuda::execution::guarantee#10022

Merged
elstehle merged 3 commits into
NVIDIA:mainfrom
elstehle:fea/guarantees
Jul 21, 2026
Merged

Exposes cuda::execution::guarantee#10022
elstehle merged 3 commits into
NVIDIA:mainfrom
elstehle:fea/guarantees

Conversation

@elstehle

Copy link
Copy Markdown
Contributor

Closes #10017

This PR pulls the guarantees mechanism out of #9278 so that upcoming work like runs_on (see #9814) can build on it, while the first concrete guarantee (with the future and shape of max_total_num_items still being discussed). The idea is that guarantee lets a caller promise properties about the problem that an algorithm may exploit.

The mechanism mirrors require, with two differences: guarantees may carry runtime state (e.g., a runtime bound), so guarantee(...) stores its arguments by value instead of discarding them, and, following review feedback on #9278, guarantee(...) is constexpr and noexcept.

@elstehle
elstehle requested a review from a team as a code owner July 20, 2026 18:08
@elstehle
elstehle requested a review from Jacobfaib July 20, 2026 18:08
@github-project-automation github-project-automation Bot moved this to Todo in CCCL Jul 20, 2026
@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Review in CCCL Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 179df5f4-b9e6-471d-be85-b1c99b82f1b2

📥 Commits

Reviewing files that changed from the base of the PR and between bbc82e8 and 4e74cde.

📒 Files selected for processing (2)
  • libcudacxx/include/cuda/__execution/guarantee.h
  • libcudacxx/test/libcudacxx/cuda/execution/guarantee.pass.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
  • libcudacxx/test/libcudacxx/cuda/execution/guarantee.pass.cpp
  • libcudacxx/include/cuda/__execution/guarantee.h

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Introduced CUDA execution guarantees to describe algorithm/device-wide supported properties.
    • Added a public guarantee API (cuda::execution::guarantee(...)) to bundle guarantee objects into execution properties and query them from an execution environment.
    • Ensures guarantees are preserved through wrapped/nested execution environments.
  • Tests
    • Added positive test coverage for bundling, querying (including multiple guarantees), value copying, and noexcept/compile-time behavior.
    • Added a compile-failure test to verify unsupported/unbundlable guarantee types are rejected.

Walkthrough

Adds cuda::execution guarantee abstractions, exposes them through public and umbrella headers, and adds passing and failing tests for guarantee bundling, querying, forwarding, and type validation.

Changes

Execution guarantees

Layer / File(s) Summary
Guarantee query and packaging contract
libcudacxx/include/cuda/__execution/guarantee.h
Defines __guarantee, __get_guarantees_t, the forwarding query, the __get_guarantees key, and guarantee(...) property construction with type and nothrow-copy validation.
Public header exposure
libcudacxx/include/cuda/execution.guarantee.h, libcudacxx/include/cuda/execution
Adds the public wrapper header and includes the guarantee implementation from the CUDA execution umbrella header.
Guarantee behavior validation
libcudacxx/test/libcudacxx/cuda/execution/guarantee.pass.cpp, libcudacxx/test/libcudacxx/cuda/execution/guarantee.fail.cpp
Tests valid and multiple guarantee queries, forwarding behavior, unrelated guarantee rejection, and invalid argument handling.

Assessment against linked issues

Objective Addressed Explanation
Expose cuda::execution::guarantees [#10017]

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (3)
libcudacxx/include/cuda/__execution/guarantee.h (1)

67-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Complete the Doxygen contract for guarantee. Add @param[in] documentation for __guarantees and @return documentation for the non-void result, including the by-value storage and noexcept behavior.

Source: Coding guidelines

libcudacxx/test/libcudacxx/cuda/execution/guarantee.pass.cpp (2)

45-71: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

suggestion: Assert the advertised constexpr and noexcept contract directly. static_assert(test()) covers constexpr evaluation, but add a static_assert(noexcept(exec::guarantee(...))) check and a mutation check proving bundled guarantees are stored by value.


31-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Use TEST_FUNC for these host/device test helpers instead of raw _CCCL_HOST_DEVICE. This keeps the test aligned with the harness’ portability and compiler-mode handling.

Sources: Coding guidelines, Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 909cf52e-48dd-43b4-93d0-c357293aeb0c

📥 Commits

Reviewing files that changed from the base of the PR and between 73a1a4b and bbc82e8.

📒 Files selected for processing (5)
  • libcudacxx/include/cuda/__execution/guarantee.h
  • libcudacxx/include/cuda/execution
  • libcudacxx/include/cuda/execution.guarantee.h
  • libcudacxx/test/libcudacxx/cuda/execution/guarantee.fail.cpp
  • libcudacxx/test/libcudacxx/cuda/execution/guarantee.pass.cpp

Comment thread libcudacxx/include/cuda/__execution/guarantee.h
Comment thread libcudacxx/include/cuda/__execution/guarantee.h
Comment thread libcudacxx/test/libcudacxx/cuda/execution/guarantee.fail.cpp

@Jacobfaib Jacobfaib 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.

Mostly minor nits


::cuda::std::execution::env<_Guarantees...> __env{__guarantees...};

return ::cuda::std::execution::prop{__get_guarantees_t{}, __env};

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.

Suggested change
return ::cuda::std::execution::prop{__get_guarantees_t{}, __env};
return ::cuda::std::execution::prop{__get_guarantees, __env};

May as well reuse the global here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was curious why we might follow the same __get_requirements_t{} for the requirements and consulted Claude, and the justification sounds reasonable - and something I wasn't aware of.

In device passes _CCCL_GLOBAL_CONSTANT is __device__ constexpr without inline. Copying it inside this inline host-device function would odr-use a per-TU object — the static-linkage device-memory emission #7682 is trying to get rid of, plus formally divergent inline-function definitions across TUs. Since prop only uses the key's type, the temporary gets the identical result without naming the object; same reason require.h/tune.h spell it this way.

I had also Claude verify that mere declaration does not, while odr-use will actually cause materialization:

Mere declaration costs nothing; only odr-use materializes the object. Here's the probe (clang CUDA, -fgpu-rdc, device pass):

struct CPO { __device__ void operator()() const noexcept {} };
__device__ constexpr CPO unused_cpo{};   // declared, never touched
__device__ constexpr CPO used_cpo{};     // called + address taken in a kernel

Result in the generated PTX:

- unused_cpo — absent entirely. No symbol, no storage, at any optimization level. A namespace-scope constexpr variable that's never odr-used doesn't have to exist as an object, and the compiler doesn't create it. So the declaration line in guarantee.h is free.
- used_cpo — .const .align 1 .b8 used_cpo[1]; — one byte of actual device storage, materialized because the code needed the object itself.

I'm leaving a comment in the code.

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.

Why do we need _CCCL_GLOBAL_CONSTANT and cannot just use constexpr inline?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Iirc, inline constexpr variables aren't accessible from device code.

[[nodiscard]] _CCCL_NODEBUG_API constexpr auto guarantee(_Guarantees... __guarantees) noexcept
{
static_assert((::cuda::std::is_base_of_v<__guarantee, _Guarantees> && ...),
"Only guarantees can be passed to guarantee");

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.

Even though the is_base_of hints at it quite strongly, we should be explicit here that being a "guarantee" means publicly subclassing from cuda::__guarantee (and consider dropping the __ then, it seems a bit weird to ask users to subclass a dunder class). Perhaps cuda::guarantee_base to mimic std::views::view_base.

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.

This base class is just a means to improve detecting wrong usage of the API, right? I would not need it public then, but it also does not hurt.

One argument could be that users could define their own guarantees if they had access to the base class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think if we want to allow users to define their own guarantees this makes sense. I would limit API surface for now and only open up for deriving from a guarantee_base in follow-up work, when there's demand or we deem it useful? What do you think?

@github-actions

This comment has been minimized.

Comment thread libcudacxx/include/cuda/__execution/guarantee.h
[[nodiscard]] _CCCL_NODEBUG_API constexpr auto guarantee(_Guarantees... __guarantees) noexcept
{
static_assert((::cuda::std::is_base_of_v<__guarantee, _Guarantees> && ...),
"Only guarantees can be passed to guarantee");

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.

This base class is just a means to improve detecting wrong usage of the API, right? I would not need it public then, but it also does not hurt.

One argument could be that users could define their own guarantees if they had access to the base class.

Comment thread libcudacxx/include/cuda/__execution/guarantee.h
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🥳 CI Workflow Results

🟩 Finished in 4h 56m: Pass: 100%/120 | Total: 4d 07h | Max: 2h 39m | Hits: 46%/1320699

See results here.

@elstehle
elstehle merged commit f1556e0 into NVIDIA:main Jul 21, 2026
268 of 278 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in CCCL Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Expose cuda::execution::guarantees

3 participants