-
Notifications
You must be signed in to change notification settings - Fork 487
Integrate decoupled lookahead warpspeed scan #6811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fa7bafe
911b1a2
fa84d4a
adae228
fd59bd9
b200e77
e431418
28f0da6
3e7c20f
e58b529
4c8fa48
461a895
58b9685
6255fc1
91c0928
a25dff4
ba48326
2623a76
4062ce1
34d7c8a
20e82b0
9c465ed
abc09cb
4c3b0d2
fbbc5b7
f0cb49b
1842de0
e671ef4
43ca945
7706421
0ee6b75
78dd8fb
a99203c
de02615
8815cb4
c7f3265
fa9f20f
13ab486
c99b28b
3fad68c
7aab0a4
890efcc
0a1cc36
c482bed
e0e0ee4
0a4ccd4
a485d13
74a67f4
f1fd762
6ce8959
b5aed38
3f94333
1c242f9
26b05c9
0790765
1fdc5d6
0375a7c
169d9ab
fabd246
4bce11b
5750e0d
2b8f25b
12b4fbe
4e3d11d
732ed8c
e850de7
ef4944c
09c4975
949a7ff
8d88d07
5d6a9d8
ddaa14d
158d1fc
485dc6e
b6fe368
ed056b4
b3466ef
b0f3f53
24744dd
41d6124
7df7c7a
e1333ad
2e1df2e
8581029
718bb61
5f64ad7
fdbf4e3
f6fa140
b789dca
08ed34c
8be951d
e281b10
81a5fe6
25ccf5a
5e20e9c
343f14c
71bbb07
7eba0bf
894f1dc
92306f1
274d643
88e6eaf
aa7c974
75a67f1
b374162
db74281
1067030
2e2b8a7
322cf01
3f21b69
97b6a95
75244fc
c2d2b7a
f04f8b5
a3219bb
30124b7
5834de8
8b8f65a
99f544a
1bef8a8
9c69a87
0b2d594
8bf54ed
4bfb525
02bf755
a39d83f
e08daa6
db8f0b4
9027e3a
8a297b9
4921f06
cf2fb5c
82338d7
8c4660b
3b1fec5
a20ad2c
a238489
2e8b6b8
b900464
85695cc
47a3e52
bd4ed36
18e7f16
b179d44
cfd405e
bfda186
6623671
ce100e4
04ad78c
53d1d95
68ad875
781e488
1152bae
f0e885a
24ac8b0
99dc2cf
a8acef8
6c203f4
a85bd05
be22c77
1efe870
aae1436
9a7bf03
93b988c
d807c57
15fe49a
a146677
d9e6d50
daaf795
ca19ca0
97f5730
fc3bb6b
c19c8c9
a407389
1f7e914
d4f8adc
aed948a
3e06335
fd8d9e0
7db74ef
a856424
563f712
d20a272
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -97,6 +97,29 @@ struct TripleChevronFactory | |||||
|
|
||||||
| return cudaDeviceGetAttribute(&max_shared_memory, cudaDevAttrMaxSharedMemoryPerBlock, device); | ||||||
| } | ||||||
|
|
||||||
| template <typename Kernel> | ||||||
| _CCCL_HIDE_FROM_ABI CUB_RUNTIME_FUNCTION ::cudaError_t | ||||||
| max_dynamic_smem_size_for(int& max_dynamic_smem_size, [[maybe_unused]] Kernel kernel_ptr) | ||||||
| { | ||||||
| NV_IF_ELSE_TARGET(NV_IS_HOST, // | ||||||
| ({ return MaxPotentialDynamicSmemBytes(max_dynamic_smem_size, kernel_ptr); }), | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
| ({ | ||||||
| ::cudaFuncAttributes func_attrs{}; | ||||||
| if (const auto error = CubDebug(::cudaFuncGetAttributes(&func_attrs, kernel_ptr))) | ||||||
| { | ||||||
| return error; | ||||||
| } | ||||||
| max_dynamic_smem_size = func_attrs.maxDynamicSharedSizeBytes; | ||||||
| return cudaSuccess; | ||||||
| })) | ||||||
| } | ||||||
|
|
||||||
| template <typename Kernel> | ||||||
| _CCCL_HIDE_FROM_ABI CUB_RUNTIME_FUNCTION ::cudaError_t set_max_dynamic_smem_size_for(Kernel kernel_ptr, int smem_size) | ||||||
| { | ||||||
| return CubDebug(::cudaFuncSetAttribute(kernel_ptr, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size)); | ||||||
| } | ||||||
| }; | ||||||
| } // namespace detail | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
| // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. | ||||||
| #pragma once | ||||||
|
|
||||||
| #include <cub/config.cuh> | ||||||
|
|
||||||
| #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) | ||||||
| # pragma GCC system_header | ||||||
| #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) | ||||||
| # pragma clang system_header | ||||||
| #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) | ||||||
| # pragma system_header | ||||||
| #endif // no system header | ||||||
|
|
||||||
| #include <cub/detail/warpspeed/optimize_smem_ptr.cuh> | ||||||
|
|
||||||
| #include <cuda/std/__type_traits/is_constant_evaluated.h> | ||||||
| #include <cuda/std/cstdint> | ||||||
|
|
||||||
| #include <nv/target> | ||||||
|
|
||||||
| CUB_NAMESPACE_BEGIN | ||||||
|
|
||||||
| namespace detail::warpspeed | ||||||
| { | ||||||
| struct SmemAllocator | ||||||
| { | ||||||
| ::cuda::std::uint32_t mPtrSmem32 = 0; | ||||||
| int mAllocatedSize = 0; | ||||||
|
|
||||||
| _CCCL_API constexpr SmemAllocator() noexcept | ||||||
| { | ||||||
| // we only need the real pointer at runtime in device code | ||||||
| if (!::cuda::std::is_constant_evaluated()) | ||||||
| { | ||||||
| NV_IF_TARGET(NV_IS_DEVICE, mPtrSmem32 = dynamic_smem_base();) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| [[nodiscard]] _CCCL_DEVICE_API static ::cuda::std::uint32_t dynamic_smem_base() noexcept | ||||||
| { | ||||||
| extern __shared__ char warpSpeedDynamicSmemBase[]; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I start to get confused by the code convention for variable names. Should not be snake_style?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. The whole part of this PR that does not touch CUB has been written in the style that @ahendriksen chose. I am still not sure whether we want to change it, since warpspeed is also intended to be used outside CCCL. Not sure.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just adapt to the library that I am contributing to. Warpspeed uses a convention from a different library. It wasn't originally developed for scan. So if it has to adapt for CUB, then we should adapt. I would advise to make those changes in a separate PR in one go though. Making changes to all files in this PR just creates churn for no good reason.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, let's file the style fix as a separate PR. |
||||||
| return __cvta_generic_to_shared(warpSpeedDynamicSmemBase); | ||||||
| } | ||||||
|
|
||||||
| // SmemAllocator is a non-copyable, non-movable type. It must be passed by | ||||||
| // (mutable) reference to be useful. | ||||||
| SmemAllocator(const SmemAllocator&) = delete; // Delete copy constructor | ||||||
| SmemAllocator(SmemAllocator&&) = delete; // Delete move constructor | ||||||
| SmemAllocator& operator=(const SmemAllocator&) = delete; // Delete copy assignment | ||||||
| SmemAllocator& operator=(SmemAllocator&&) = delete; // Delete move assignment | ||||||
|
|
||||||
| [[nodiscard]] _CCCL_API constexpr void* alloc(::cuda::std::uint32_t size, ::cuda::std::uint32_t align = 0) | ||||||
| { | ||||||
| // Align mPtrSmem32 to requested alignment (round-up) | ||||||
| ::cuda::std::uint32_t ptrAllocation32 = (mPtrSmem32 + (align - 1)) & ~(align - 1); | ||||||
|
|
||||||
| // Move base pointer and update allocated size | ||||||
| mAllocatedSize += size + ptrAllocation32 - mPtrSmem32; | ||||||
| mPtrSmem32 = ptrAllocation32 + size; | ||||||
|
|
||||||
| // we only need the pointer at runtime in device code | ||||||
| if (!::cuda::std::is_constant_evaluated()) | ||||||
| { | ||||||
| NV_IF_TARGET( | ||||||
| NV_IS_DEVICE, | ||||||
| ( | ||||||
| // Convert allocated smem address to generic pointer | ||||||
| void* mPtrAllocation = __cvta_shared_to_generic(ptrAllocation32); | ||||||
| // Ensure alignment calculation does not move down into rest of kernel code. | ||||||
| return optimizeSmemPtr(mPtrAllocation);)) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We haven't established the convention (yet) that CUB should also (fully) qualify function calls. Here, we call a function from the same namespace and do not rely on ADL. |
||||||
| } | ||||||
| return nullptr; | ||||||
| } | ||||||
|
|
||||||
| [[nodiscard]] _CCCL_API constexpr ::cuda::std::uint32_t sizeBytes() const | ||||||
| { | ||||||
| return mAllocatedSize; | ||||||
| } | ||||||
| }; | ||||||
| } // namespace detail::warpspeed | ||||||
|
|
||||||
| CUB_NAMESPACE_END | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. | ||
| #pragma once | ||
|
|
||
| #include <cub/config.cuh> | ||
|
|
||
| #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) | ||
| # pragma GCC system_header | ||
| #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) | ||
| # pragma clang system_header | ||
| #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) | ||
| # pragma system_header | ||
| #endif // no system header | ||
|
|
||
| #include <cuda/std/cassert> | ||
|
|
||
| /* | ||
| * _WS_CONSTANT_ASSERT: an assertion that is intended to be verified at compile time. | ||
| * | ||
| * A _WS_CONSTANT_ASSERT asserts something that the compiler (optimizer) can verify | ||
| * at compile time. Therefore, it does not result in an actual call to assert in | ||
| * the compiled binary. This allows checking various properties that cannot be | ||
| * verified using static_assert. | ||
| * | ||
| * To ensure that all _WS_CONSTANT_ASSERTs are in fact eliminated, compile with | ||
| * -D_WARPSPEED_FORCE_ASSERT_AT_COMPILE_TIME. With this macro defined, any | ||
| * _WS_CONSTANT_ASSERT failure will output illegal PTX containing the error message. | ||
| * As a result, compilation will fail. | ||
| * | ||
| * Compiling with -D_WARPSPEED_FORCE_ASSERT_AT_COMPILE_TIME has the additional | ||
| * advantage that violating any of the assertions can be detected at compile | ||
| * time and before even running the code. | ||
| * | ||
| */ | ||
|
|
||
| #if defined(_WARPSPEED_FORCE_ASSERT_AT_COMPILE_TIME) && defined(__CUDA_ARCH__) | ||
| // When _WARPSPEED_FORCE_ASSERT_AT_COMPILE_TIME is defined and compiling for device, output illegal PTX. | ||
| // This causes the compilation to fail. | ||
| # define _WS_CONSTANT_ASSERT(expr, msg) \ | ||
| do \ | ||
| { \ | ||
| if (!(expr)) \ | ||
| { \ | ||
| asm volatile(".pragma \"\n" __FILE__ "(" _CCCL_TO_STRING( \ | ||
| __LINE__) "): %0" \ | ||
| ": error: constant assertion failed with '" msg "'\n\";" ::"C"(__func__)); \ | ||
| } \ | ||
| } while (0) | ||
| #else | ||
| // Host or !_WARPSPEED_FORCE_ASSERT_AT_COMPILE_TIME | ||
| # define _WS_CONSTANT_ASSERT(expr, msg) (assert((expr) && (msg))) | ||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT:
same for other occurrences
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we should always fully qualify in production code