Fix BlockTopK +/-0.0 handling#9470
Conversation
Instead of inverting the key, reverse the histogram index.
Additional data generation infrastructure was needed to catch it deterministically.
SummaryThis PR fixes negative zero ( ChangesCore algorithm fix
Test coverage
Walkthrough
Changesblock_topk_air SelectDirection correctness and test coverage
Suggested reviewers
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 39b7f3ca-5295-4397-8077-40d5d40d05f5
📒 Files selected for processing (4)
cub/cub/block/specializations/block_topk_air.cuhcub/test/catch2_test_block_topk.cucub/test/catch2_test_block_topk_common.cuhcub/test/catch2_test_device_segmented_topk_keys.cu
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
🥳 CI Workflow Results🟩 Finished in 6h 02m: Pass: 100%/287 | Total: 2d 07h | Max: 52m 21s | Hits: 98%/199242See results here. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cub/test/catch2_test_block_topk_common.cuh (1)
30-30: 🧹 Nitpick | 🔵 Trivial | 💤 Low valuesuggestion: Include uses quote syntax; coding guidelines require angle brackets for all header inclusions.
-#include "catch2_test_device_topk_common.cuh" +#include <catch2_test_device_topk_common.cuh>Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 64ebd300-52f8-4527-8659-6045c59ee53f
📒 Files selected for processing (2)
cub/test/catch2_test_block_topk.cucub/test/catch2_test_block_topk_common.cuh
🚧 Files skipped from review as they are similar to previous changes (1)
- cub/test/catch2_test_block_topk.cu
Description
Cause
The bug is caused by combining
detail::radix::traits_t<KeyT>::bit_ordered_inversion_policy::inverse()andBFEDigitExtractor<KeyT>{}.Digit(key)as well as comparing non-digit-extracted keys with a mask built from extracted digits.In
BlockTopKwe handle -0.0 manually and get rid of the corresponding bit-pattern which keeps the bug from appearing in themincase. But in themaxcase we invert the keys after that transformation which means that instead of both 0.0 and -0.0 being mapped to the 0.0 bit-pattern, they both get mapped to the -0.0 bit pattern.The digit-extractor has built-in negative-zero handling for FP (it extracts the 0.0 bit pattern even from -0.0). But this handling conflicts with our use of the extracted digit to build up a prefix mask b/c we compare the mask directly with the key which still has the -0.0 bit-pattern. So keys that were registered in the histogram-pass as 0.0-bit-pattern wont be filtered correctly later.
This issue can be reproduced by having input data with tied keys being 0.0 or -0.0 and using the
maxselect-direction. This causes the candidate bin to count all the 0.0/-0.0 keys but none of them participating in the next histogram pass since they do not compare equal with the prefix mask.Fix
The actual fix is just 14 lines of code. All the rest is testing infrastructure I brought over from #9066 to make sure the bug is fixed and remains fixed. I found and fixed the bug there originally but the PR was de-prioritized to focus on #9077. So to still get this fix in, I extracted it into its own PR.
While one could also fix the issue by first inverting and then doing the -0.0 to 0.0 mapping, I decided to get rid of the bit pattern inversion completely. Instead, we reverse the histogram index for the
max-direction (and undo the reversal when transforming the bin index into the prefix mask). This is also what other radix-ranking facilities seem to be doing (even though they don't have the same issue of building up a mask and comparing it to the keys). It feels less bug-prone, easier to understand/review and seemed to have a neutral to positive effect in benchmarks (in the context of my bigger PR #9066, I did not re-benchmark this PR).In a follow-up PR we should look into getting a digit-extractor w/o the -0.0 handling to avoid the unnecessary conditional (dead code) introduced by it due to our manual handling of -0.0.
Checklist