| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Includes tests for compile-time argument checks, scalar widening, pointer qualification, and backward compatibility. Negative compile tests validate incompatible arguments fail correctly. Updated CMakeLists to include new tests.
|
Sorry, the commits went out with my work email — I'm rewriting the history to use my personal address and will force-push. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Add type-safe kernel() overloads to cudaGraphBase and cudaGraphExecBase
Acknowledgement
First and foremost: a huge thank you to Dr. Tsung-Wei Huang and all contributors for building
and maintaining Taskflow. It is one of the most elegant and well-engineered C++ frameworks I
have encountered, and I rely on it in production code daily.
Background
I use Taskflow in a production pipeline that runs on both Linux and Windows. Over time I ran
into a platform-dependent crash that took a while to track down. The root cause turned out to
be a completely silent type mismatch in a cudaGraph::kernel() call:
On Linux this worked fine — GCC's stack layout happens to zero the upper 4 bytes of the
8-byte size_t slot, so the driver reads the correct value by accident. On Windows the upper
bytes contain garbage, and the CUDA driver interprets the argument as something like
0x????????00000100, causing the kernel to access memory far out of bounds and fail with
cudaErrorIllegalAddress.
To be clear: this is not a bug in Taskflow. The existing API is intentionally generic and
fully correct within the C++ rules. The mismatch lives entirely at the call site.
That said, I thought others might benefit from having these errors surface at compile time
rather than as hard-to-reproduce runtime crashes — especially in cross-platform codebases
where the Linux/Windows ABI difference means the bug is invisible during development and only
shows up in production.
What this PR adds
A new overload of kernel() for both cudaGraphBase and cudaGraphExecBase that accepts a
typed __global__ function pointer (void(*)(Params...)) instead of the generic
template<typename F> callable. Because the function pointer carries the exact parameter
types in its type, the compiler can enforce correct argument types before anything is packed
into the void* array.
New helper: tf::detail::kernelArgCast
Two cast strategies are used deliberately:
(e.g. size_t) is expected results in a widened, correct value. A genuinely incompatible
type (a struct, an unrelated enum) produces a compile error.
static_cast rejects in CUDA's augmented type system:
New overload in cudaGraphBase (cuda_graph.hpp)
The cast values are stored in a std::tuple — not addressed directly from the function
parameter pack — to guarantee that the void* pointers remain valid for the duration of
the cudaGraphAddKernelNode call. This avoids a subtle dangling-address issue that the
original naive pattern (void* arguments[] = { (void*)(&args)... }) is susceptible to when
a conversion creates a temporary.
New overload in cudaGraphExecBase (cuda_graph_exec.hpp)
Identical pattern, calling cudaGraphExecKernelNodeSetParams instead.
Overload resolution — no ambiguity, no breaking changes
The two overloads coexist cleanly:
When the caller passes a named __global__ function, its type is void(*)(Params...) —
Overload B matches more specifically via partial ordering ([temp.func.order]) and is
preferred. When the caller passes a lambda or functor, deduction for Overload B fails and
only Overload A is viable. No existing call site needs to change.
What this catches (and what it doesn't)
Pointer-to-incompatible-type mismatches (float* for int*) are intentionally outside
the protection boundary; they require compute-sanitizer or code review to detect.
Tests
A new test file unittests/cuda/test_cuda_type_safe_kernel.cu is added with 11 test cases:
Two negative-compile test files (test_compile_fail_arg_count.cu,
test_compile_fail_scalar_mismatch.cu) are wired into CMakeLists.txt via try_compile to
verify the static_assert and ill-formed static_cast paths actually reject bad code.
Files changed