-
Notifications
You must be signed in to change notification settings - Fork 47
Fix lock/flags array size validation in matmul_reduce_scatter and all_reduce #482
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
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 | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -169,3 +169,96 @@ def test_all_reduce_two_shot_distribution(distribution, dtype=torch.float32, M=1 | |||||||||||||||||||||||||||||||||
| import gc | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| gc.collect() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def test_all_reduce_spinlock_lock_too_small(): | ||||||||||||||||||||||||||||||||||
| """Test that ValueError is raised when the spinlock lock array is too small for current tile count. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Scenario: workspace is prepared with larger block sizes (fewer tiles), then all_reduce | ||||||||||||||||||||||||||||||||||
| is called with smaller block sizes (more tiles). workspace.matches() skips the preamble, | ||||||||||||||||||||||||||||||||||
| and the undersized lock array is detected. | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
| if not dist.is_initialized(): | ||||||||||||||||||||||||||||||||||
| pytest.skip("torch.distributed not initialized") | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| heap_size = 2**33 | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| heap_size = 2**33 | |
| heap_size = 2**26 |
Copilot
AI
Mar 26, 2026
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.
This logic can produce nonstandard block_size_n values (e.g., world_size=3 yields 126 and 63). If the all-reduce ring kernels/config validation expect specific block sizes (common in tiled kernels), this can make the test unexpectedly fail or behave inconsistently across environments. Recommendation (moderate): restrict the test to the intended “use 64 and 128” case by skipping unless world_size divides both 64 and 128 (e.g., 64 % world_size == 0 and 128 % world_size == 0), and then set block_size_n_large=128, block_size_n_small=64.
| # Choose block_size_n values divisible by world_size for both configs | |
| # Use 128 and 64 which are divisible by typical world sizes (1, 2, 4, 8) | |
| block_size_n_large = (128 // world_size) * world_size | |
| block_size_n_small = (64 // world_size) * world_size | |
| if block_size_n_large == 0 or block_size_n_small == 0 or block_size_n_large == block_size_n_small: | |
| del shmem | |
| pytest.skip(f"Cannot create two distinct block sizes divisible by world_size={world_size}") | |
| # Restrict to the intended case: use block_size_n values 128 and 64, | |
| # and only run the test when both are exactly divisible by world_size. | |
| if 128 % world_size != 0 or 64 % world_size != 0: | |
| del shmem | |
| pytest.skip( | |
| f"Skipping: world_size={world_size} does not divide both 128 and 64 for block_size_n" | |
| ) | |
| block_size_n_large = 128 | |
| block_size_n_small = 64 |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -175,3 +175,45 @@ def test_matmul_reduce_scatter_semantics(dtype, atol, rtol): | |||||||
| import gc | ||||||||
|
|
||||||||
| gc.collect() | ||||||||
|
|
||||||||
|
|
||||||||
| def test_matmul_reduce_scatter_lock_too_small(): | ||||||||
| """Test that ValueError is raised when the lock array is too small for current tile count. | ||||||||
|
|
||||||||
| Scenario: workspace is prepared with larger block sizes (fewer tiles), then the | ||||||||
| preamble is called again with smaller block sizes (more tiles). The undersized | ||||||||
| lock array is detected and a ValueError is raised. | ||||||||
| """ | ||||||||
| if not dist.is_initialized(): | ||||||||
| pytest.skip("torch.distributed not initialized") | ||||||||
|
|
||||||||
| heap_size = 2**33 | ||||||||
|
||||||||
| heap_size = 2**33 | |
| # Use a moderately sized heap sufficient for this test without stressing CI resources. | |
| heap_size = 2**24 |
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.
The new error message instructs users to “pre-allocate workspace with the smallest block sizes”, which implies keeping a larger-than-needed lock array around for later reuse. However, the subsequent
!= total_tilescondition will shrink an oversizedworkspace.locksby allocating a new smaller array. In symmetric-heap scenarios this can also increase allocation churn and heap growth (old allocations may not be reclaimed), and it undermines the “pre-allocate small blocks once” guidance by potentially making the next small-block call fail. Recommendation (mandatory): only (re)allocate whenworkspace.locksisNoneorworkspace.locks.numel() < total_tiles; when the array is larger, keep it and just zero it (optionally only the prefix used bytotal_tilesif supported).