-
Notifications
You must be signed in to change notification settings - Fork 91
Implement CUDA event pool to minimize runtime resource allocation overhead (libcurl multi poll-based backend 2/n) #919
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
Merged
Merged
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
08dd7f9
Implement event pool
kingcrimsontianyu 3948400
Fix stream race condition
kingcrimsontianyu 43a38d9
Make ctor dtor private. Remove inner NVTX
kingcrimsontianyu bf20744
Initial impl of event pool
kingcrimsontianyu 7e0c71f
Set a get() overload to private
kingcrimsontianyu 74e6740
Add Doxygen comments
kingcrimsontianyu 812c8a9
Remove get(ctx, tid) and move its content to get()
kingcrimsontianyu c9d7acd
Merge branch 'fix-stream-bug' into event-pool
kingcrimsontianyu d878f79
Log exception msg
kingcrimsontianyu df8a4a8
Update cpp/src/detail/event.cpp
kingcrimsontianyu 9d73727
Update name for clarity
kingcrimsontianyu b71c857
Update
kingcrimsontianyu dab118e
Update
kingcrimsontianyu 3103863
Silly bug fixes
kingcrimsontianyu 4208e5c
Update
kingcrimsontianyu badc794
Merge branch 'main' into event-pool
kingcrimsontianyu 075dbd8
Merge branch 'main' into event-pool
kingcrimsontianyu 64ee425
Add event query
kingcrimsontianyu 87e8fe2
Merge branch 'main' into event-pool
kingcrimsontianyu e741a51
Merge branch 'main' into event-pool
kingcrimsontianyu c323302
Merge branch 'main' into event-pool
kingcrimsontianyu a97196b
Improve event pool impl. Add tests
kingcrimsontianyu 4f820a3
Add cuCtxCreate/Destroy to shim to improve event pool testing
kingcrimsontianyu d1609a0
Improve naming a bit
kingcrimsontianyu ad87ea0
Rename Event* to CudaEvent*
kingcrimsontianyu 5d22b95
Update doc for event is_done method
kingcrimsontianyu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include <mutex> | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
| #include <kvikio/shim/cuda.hpp> | ||
|
|
||
| namespace kvikio::detail { | ||
| /** | ||
| * @brief Thread-safe singleton pool for reusable CUDA events | ||
| * | ||
| * Manages a pool of CUDA events organized by CUDA context. Events are retained and reused across | ||
| * calls to minimize allocation overhead. Each context maintains its own separate pool of events | ||
| * since CUDA events are context-specific resources. | ||
| * | ||
| * All events are created with `CU_EVENT_DISABLE_TIMING` for minimal overhead. | ||
| * | ||
| * Call `EventPool::instance().get()` to acquire an event that will be automatically returned to the | ||
| * pool when it goes out of scope (RAII). | ||
| * | ||
| * @note The destructor intentionally leaks events to avoid CUDA cleanup issues when static | ||
| * destructors run after CUDA context destruction. @sa BounceBufferPool | ||
| */ | ||
| class EventPool { | ||
| public: | ||
| class Event { | ||
| friend class EventPool; | ||
|
|
||
| private: | ||
| CUevent _event{nullptr}; | ||
| CUcontext _context{nullptr}; | ||
|
|
||
| /** | ||
| * @brief Construct an Event wrapping a CUDA event handle | ||
| * | ||
| * @param event The CUDA event handle to wrap | ||
| * @param context The CUDA context associated with this event | ||
| */ | ||
| explicit Event(CUevent event, CUcontext context) noexcept; | ||
|
|
||
| public: | ||
| ~Event() noexcept; | ||
|
|
||
| // Move-only | ||
| Event(Event const&) = delete; | ||
| Event& operator=(Event const&) = delete; | ||
| Event(Event&& other) noexcept; | ||
| Event& operator=(Event&& other) noexcept; | ||
|
|
||
| /** | ||
| * @brief Get the underlying CUDA event handle | ||
| * | ||
| * @return The CUevent handle wrapped by this object | ||
| */ | ||
| [[nodiscard]] CUevent get() const noexcept; | ||
|
|
||
| /** | ||
| * @brief Get the CUDA context associated with this event | ||
| * | ||
| * @return The CUcontext this event belongs to | ||
| */ | ||
| [[nodiscard]] CUcontext context() const noexcept; | ||
|
|
||
| /** | ||
| * @brief Record the event on a CUDA stream | ||
| * | ||
| * Records the event to capture the current state of the stream. The event will be signaled when | ||
| * all preceding operations on the stream have completed. | ||
| * | ||
| * @param stream The CUDA stream to record the event on (must belong to the same context as this | ||
| * event) | ||
| */ | ||
| void record(CUstream stream); | ||
|
|
||
| /** | ||
| * @brief Block the calling thread until the event has been signaled | ||
| * | ||
| * Waits for all work captured by a preceding record() call to complete. | ||
| * | ||
| * @exception CudaError if the synchronize operation fails | ||
| */ | ||
| void synchronize(); | ||
| }; | ||
|
|
||
| private: | ||
| std::mutex mutable _mutex; | ||
| // Per-context pools of free events | ||
| std::unordered_map<CUcontext, std::vector<CUevent>> _pools; | ||
|
|
||
| EventPool() = default; | ||
|
|
||
| // Intentionally leak events during static destruction. @sa BounceBufferPool | ||
| ~EventPool() noexcept = default; | ||
|
|
||
| public: | ||
| // Non-copyable, non-movable singleton | ||
| EventPool(EventPool const&) = delete; | ||
| EventPool& operator=(EventPool const&) = delete; | ||
| EventPool(EventPool&&) = delete; | ||
| EventPool& operator=(EventPool&&) = delete; | ||
|
|
||
| /** | ||
| * @brief Acquire a CUDA event from the pool | ||
| * | ||
| * Returns a cached event for the current CUDA context if available, otherwise creates a new one. | ||
| * The returned Event object will automatically return the event to the pool when it goes out of | ||
| * scope. | ||
| * | ||
| * @return RAII Event object wrapping the acquired CUDA event | ||
| * @exception CudaError if no CUDA context is current or event creation fails | ||
| */ | ||
| [[nodiscard]] Event get(); | ||
|
|
||
| /** | ||
| * @brief Return an event to the pool for reuse | ||
| * | ||
| * Typically called automatically by Event's destructor. Adds the event to the pool associated | ||
| * with its context for future reuse. | ||
| * | ||
| * @param event The CUDA event handle to return | ||
| * @param context The CUDA context associated with the event | ||
| */ | ||
| void put(CUevent event, CUcontext context) noexcept; | ||
|
|
||
| /** | ||
| * @brief Get the number of free events for a specific context | ||
| * | ||
| * @param context The CUDA context to query | ||
| * @return The number of events available for reuse in that context's pool | ||
| */ | ||
| [[nodiscard]] std::size_t num_free_events(CUcontext context) const; | ||
|
|
||
| /** | ||
| * @brief Get the total number of free events across all contexts | ||
| * | ||
| * @return The total count of events available for reuse | ||
| */ | ||
| [[nodiscard]] std::size_t total_free_events() const; | ||
|
|
||
| /** | ||
| * @brief Get the singleton instance of the event pool | ||
| * | ||
| * @return Reference to the singleton EventPool instance | ||
| */ | ||
| static EventPool& instance(); | ||
| }; | ||
| } // namespace kvikio::detail | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include <map> | ||
| #include <mutex> | ||
| #include <thread> | ||
|
|
||
| #include <kvikio/shim/cuda.hpp> | ||
|
|
||
| namespace kvikio::detail { | ||
| /** | ||
| * @brief Singleton cache that provides one CUDA stream per (context, thread) pair. | ||
| * | ||
| * This class manages CUDA streams used for host-device memory transfers. Each unique combination of | ||
| * CUDA context and calling thread is assigned a dedicated stream, which is created lazily on first | ||
| * access and reused for subsequent calls. | ||
| * | ||
| * The cache is thread-safe and handles concurrent access from multiple threads. | ||
| * | ||
| * @note CUDA streams are intentionally leaked on program termination rather than destroyed in the | ||
| * destructor. This avoids undefined behavior that can occur when destroying CUDA resources during | ||
| * static destruction, and prevents crashes (segmentation faults) if clients call | ||
| * cuDevicePrimaryCtxReset() or cudaDeviceReset() before program termination. See: | ||
| * https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#initialization | ||
| */ | ||
| class StreamCachePerThreadAndContext { | ||
| private: | ||
| std::map<std::pair<CUcontext, std::thread::id>, CUstream> _streams; | ||
| std::mutex mutable _mutex; | ||
|
|
||
| private: | ||
| StreamCachePerThreadAndContext() = default; | ||
| ~StreamCachePerThreadAndContext() = default; | ||
|
|
||
| public: | ||
| /** | ||
| * @brief Get or create a CUDA stream for the specified context and thread. | ||
| * | ||
| * If a stream already exists for the given (context, thread) pair, it is returned. Otherwise, a | ||
| * new stream is created, cached, and returned. | ||
| * | ||
| * @param ctx The CUDA context. If null, the null stream is returned. | ||
| * @param thd_id The thread identifier. | ||
| * @return The CUDA stream associated with this (context, thread) pair, or nullptr if @p ctx is | ||
| * null. | ||
| */ | ||
| KVIKIO_EXPORT static CUstream get(CUcontext ctx, std::thread::id thd_id); | ||
|
|
||
| /** | ||
| * @brief Get or create a CUDA stream for the current context and thread. | ||
| * | ||
| * Convenience overload that uses the current CUDA context and calling thread's ID. | ||
| * | ||
| * @return The CUDA stream associated with the current (context, thread) pair, or nullptr if no | ||
| * CUDA context is current. | ||
| */ | ||
| static CUstream get(); | ||
|
|
||
| StreamCachePerThreadAndContext(StreamCachePerThreadAndContext const&) = delete; | ||
| StreamCachePerThreadAndContext& operator=(StreamCachePerThreadAndContext const&) = delete; | ||
| StreamCachePerThreadAndContext(StreamCachePerThreadAndContext&& o) = delete; | ||
| StreamCachePerThreadAndContext& operator=(StreamCachePerThreadAndContext&& o) = delete; | ||
| }; | ||
| } // namespace kvikio::detail |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Consider naming them
CudaEventPoolandCudaEvent.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.
Sure! Done!