-
Notifications
You must be signed in to change notification settings - Fork 480
[DOC] Add temp_storage_bytes usage guide #6208
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 1 commit
11abc08
9e41f03
a6bea9a
fea7cc4
c1ab064
ab8b7a8
827c606
5feb2de
8078542
bdf13c2
8245a3a
2c26c96
a151a44
c0f595b
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 | ||
|---|---|---|---|---|
|
|
@@ -11,6 +11,47 @@ Device-Wide Primitives | |||
| ../api/device | ||||
|
|
||||
|
|
||||
| Determining Temporary Storage Requirements | ||||
| ++++++++++++++++++++++++++++++++++++++++++++++++++ | ||||
|
|
||||
| **Two-Phase API** (Traditional) | ||||
|
|
||||
| Most CUB device-wide algorithms follow a two-phase usage pattern: | ||||
|
|
||||
| 1. **Query Phase**: Call the algorithm with ``d_temp_storage = nullptr`` to determine required temporary storage size | ||||
|
Aminsed marked this conversation as resolved.
Outdated
|
||||
| 2. **Execution Phase**: Allocate storage and call the algorithm again to perform the actual operation | ||||
|
|
||||
| **What arguments are needed during the query phase?** | ||||
|
|
||||
| * **Required**: Data types (via template parameters and iterator types) and problem size (``num_items``) | ||||
| * **Can be nullptr/uninitialized**: All input/output pointers (``d_in``, ``d_out``, etc.) | ||||
| * **Note**: The algorithm does not access input data during the query phase | ||||
|
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. Are we actually providing this guarantee? Can you point at a place from which you derive this fact? Hypothetical scenario: we could determine the temporary storage based on the alignment of another input pointer. AFAIK we don't do that, but currently, we could. However, since we seem to be vage about what's required on all parameters that are not taking part in the query phase, maybe we should just define what's being suggested here. But that requires some broader approval and probably a review of all existing APIs. @gevtushenko what do you think?
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. @bernhardmgruber Thanks for flagging this great point. I re-audited the device-wide dispatch layer to make sure we're not overpromising. Every dispatcher we ship ( exits immediately when
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 don't think we should list the specific implementations, but rather provide a general guarantee. @gevtushenko can we agree that any arguments, except for the temporary storage pointer and size reference, are not inspected during a size query call of a CUB device API?
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. @bernhardmgruber Thanks! I’ve trimmed the doc to state the general guarantee. Happy to adjust further once we hear back from @gevtushenko.
Collaborator
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. @Aminsed thank you for the contribution! It's a long overdue on our end to provide an overview of two-phase interface. We do receive questions regarding it, and I'm glad there'll be a single source of truth going forward. Access to the iterators during temp storage query stage is one of these frequent questions, so we should document it. Iterator Access
Each device-level algorithm says something like "the required allocation size is written to Users frequently have to estimate the temporary storage size before they have data, so it's common and valid use to estimate temp storage with So the only comment I'd have is that current phrasing is a bit limiting: "The algorithm does not access input data during the query phase". It shouldn't be specific to input data, since we won't access output data as well. Maybe we can rephrase it in the lines of driver use / work etc. or at least relax phrazing to "does not access iterators". SuggestionsDoxygen AliasTo make this section more easily discoverable, consider adding a reference to it in the doxygen aliases: Line 74 in 93e1f87
This way, a link to this section will appear on each algorithm using Current GPUAnother underspecified aspect is that current GPU probably shouldn't change between the phases. Say, in reduce, temp storage size depends on the occupancy, which might vary between GPUs. For radix sort, some architectures might use onesweep approach, while others would use legacy scheme. I think it's safer to have a requirement that same current GPU is used between phases by default and relax it on per-algorithm basis when needed. @elstehle, @bernhardmgruber what do you think?
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. Thank you for the clarifications @gevtushenko! I would then word the requirement on the query phase something like this: The query phase must use the same template instantiation than the execution phase of a two-step CUB API. That is, all template arguments are equal. Except for the first two function arguments (temporary storage pointer and size) as well as any problem size arguments (e.g.
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. The requirement that the GPU is not allowed to be changed between query and execution phase is definitely should definitely be added as well! So let's also add: The temporary storage size queried for a CUB algorithm is only valid for a CUB algorithm execution that is using the same current CUDA device as the query call.
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. Thanks @gevtushenko @bernhardmgruber for the detailed guidance. I’ve adopted that wording, query calls use the same template instantiation, only touch temp-storage/problem-size args (others may be indeterminate), and now note the same-current-device requirement. Happy to adjust further if needed.
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. Agree with Georgii's assessment here. This, to me, is a very strong argument:
Thanks, Bernhard. I think this is very concise. Just a nit, I would replace
Regarding current GPU: |
||||
|
|
||||
| Example pattern: | ||||
|
|
||||
| .. code-block:: c++ | ||||
|
Aminsed marked this conversation as resolved.
|
||||
|
|
||||
| // Determine temporary storage requirements | ||||
| void* d_temp_storage = nullptr; | ||||
| size_t temp_storage_bytes = 0; | ||||
|
|
||||
| cub::DeviceReduce::Sum( | ||||
| d_temp_storage, temp_storage_bytes, | ||||
| nullptr, nullptr, num_items); // Input/output pointers can be null | ||||
|
|
||||
| // Allocate temporary storage | ||||
| cudaMalloc(&d_temp_storage, temp_storage_bytes); | ||||
|
|
||||
| // Run the actual algorithm with real pointers | ||||
| cub::DeviceReduce::Sum( | ||||
| d_temp_storage, temp_storage_bytes, | ||||
| d_in, d_out, num_items); | ||||
|
|
||||
| **Single-Phase API** (Environment-Based) | ||||
|
|
||||
| Some algorithms provide environment-based overloads that eliminate the two-phase call pattern. | ||||
| These APIs accept an execution environment parameter. See the individual algorithm documentation for availability. | ||||
|
Aminsed marked this conversation as resolved.
Outdated
|
||||
|
|
||||
| CUB device-level single-problem parallel algorithms: | ||||
|
|
||||
| * :cpp:struct:`cub::DeviceAdjacentDifference` computes the difference between adjacent elements residing within device-accessible memory | ||||
|
|
||||
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.
would be nice to also mention the single-phase API