Skip to content

Commit 5fd50d1

Browse files
q10meta-codesync[bot]
authored andcommitted
Fix test_lru_cache_insert_large_grid associativity on ROCm wavefront64 (#5899)
Summary: Pull Request resolved: #5899 `test_lru_cache_insert_large_grid` (added by D105282095) hardcodes the LXU cache associativity as `32`. The split-embeddings LXU cache is set-associative with associativity == warp size == `DEFAULT_ASSOC` (32 on NVIDIA, 64 on AMD). On AMD wavefront64 (gfx942 / MI300) `lru_cache_insert_kernel` strides cache rows by `kWarpSize = 64` and writes `lxu_cache_state` / `lxu_cache_weights` / `lru_state` for `slot` in `[0, 64)`, indexing past the 32-wide test allocations -> out-of-bounds -> non-deterministic memory corruption -> flaky `assertEqual(lru_state != time_stamp, 0)` failures in OSS ROCm CI (see P2378242263). On NVIDIA (32 == 32) the allocation matches the kernel, so the test passed. Fix (test-only; no kernel/production change): - Size the three cache tensors and assertions by `DEFAULT_ASSOC` instead of the literal `32`, matching the established pattern in `lxu_cache_test.py` and `nbit_cache_test.py`, so the allocation width matches the kernel's `kWarpSize` associativity on both platforms. - Fix `torch.accelerator.current_accelerator("cuda")` -> `current_accelerator()` (the string was silently coerced to `check_available=True`; flagged by ai_diff_reviewer). - Generalize the docstring's NVIDIA-specific (32) grid math. Reviewed By: henrylhtsang Differential Revision: D108540654 fbshipit-source-id: ccdcc7d18b64dadfe78abd38b353e3bcd8e2ef84
1 parent 0fb6911 commit 5fd50d1

1 file changed

Lines changed: 20 additions & 11 deletions

File tree

fbgemm_gpu/test/tbe/cache/cache_test.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
)
2525
from fbgemm_gpu.split_table_batched_embeddings_ops_training import (
2626
ComputeDevice,
27+
DEFAULT_ASSOC,
2728
MultiPassPrefetchConfig,
2829
SplitTableBatchedEmbeddingBagsCodegen,
2930
)
@@ -1041,10 +1042,12 @@ def test_lru_cache_insert_large_grid(self) -> None:
10411042
(split_embeddings_cache/lru_cache_populate.cu, lock_cache_line=False
10421043
branch).
10431044
1044-
Block: dim3(kWarpSize=32, kMaxThreads/kWarpSize=32) = 1024 threads.
1045-
Grid: div_round_up(N, kMaxThreads / kWarpSize) = ceil(N / 32).
1046-
Total threads ~= N * kWarpSize = 32 * N. For N >= 2**27, total
1047-
threads exceed the HIP 2**32 limit, causing FBGEMM_LAUNCH_KERNEL ->
1045+
Block: dim3(kWarpSize, kMaxThreads/kWarpSize) = 1024 threads
1046+
(kWarpSize = 32 on NVIDIA, 64 on AMD; cache associativity ==
1047+
kWarpSize == DEFAULT_ASSOC).
1048+
Grid: div_round_up(N, kMaxThreads / kWarpSize). Total threads
1049+
~= N * kWarpSize. For N >= 2**27 this exceeds the HIP 2**32 limit
1050+
on both warp sizes, causing FBGEMM_LAUNCH_KERNEL ->
10481051
KernelLauncher::checkThreadCountNotExceeded to TORCH_CHECK-fail
10491052
on ROCm.
10501053
@@ -1055,7 +1058,7 @@ def test_lru_cache_insert_large_grid(self) -> None:
10551058
"""
10561059
N = (1 << 27) + 1
10571060
D = 4
1058-
device = torch.accelerator.current_accelerator("cuda")
1061+
device = torch.accelerator.current_accelerator()
10591062

10601063
# T=1 table with E = N entries so all unique linear cache indices
10611064
# are valid hash keys. cache_hash_size_cumsum has shape (T+1,).
@@ -1071,16 +1074,22 @@ def test_lru_cache_insert_large_grid(self) -> None:
10711074
# kernel grid size.
10721075
linear_cache_indices = torch.arange(N, dtype=torch.int64, device=device)
10731076
# Small cache -> tiny lxu_cache_state / weights / lru_state.
1077+
# Cache associativity == warp size (DEFAULT_ASSOC: 32 on NVIDIA,
1078+
# 64 on AMD). The insert kernel strides cache rows by kWarpSize, so
1079+
# the slot dimension MUST match or the kernel indexes out of bounds
1080+
# on wavefront-64 hardware.
10741081
num_cache_sets = 1024
10751082
lxu_cache_state = torch.full(
1076-
(num_cache_sets, 32), -1, dtype=torch.int64, device=device
1083+
(num_cache_sets, DEFAULT_ASSOC), -1, dtype=torch.int64, device=device
10771084
)
10781085
# Flat weights tensor for the single table.
10791086
weights = torch.zeros(N * D, dtype=torch.float32, device=device)
10801087
lxu_cache_weights = torch.zeros(
1081-
(num_cache_sets * 32, D), dtype=torch.float32, device=device
1088+
(num_cache_sets * DEFAULT_ASSOC, D), dtype=torch.float32, device=device
1089+
)
1090+
lru_state = torch.zeros(
1091+
(num_cache_sets, DEFAULT_ASSOC), dtype=torch.int64, device=device
10821092
)
1083-
lru_state = torch.zeros((num_cache_sets, 32), dtype=torch.int64, device=device)
10841093

10851094
torch.ops.fbgemm.lru_cache_populate(
10861095
weights,
@@ -1102,14 +1111,14 @@ def test_lru_cache_insert_large_grid(self) -> None:
11021111
)
11031112
# Tier C structural invariants on the populated cache:
11041113
# 1. shape preserved.
1105-
self.assertEqual(lxu_cache_state.shape, (num_cache_sets, 32))
1106-
# 2. Cache is fully populated. With N >> num_cache_sets * 32 = 32K,
1114+
self.assertEqual(lxu_cache_state.shape, (num_cache_sets, DEFAULT_ASSOC))
1115+
# 2. Cache is fully populated. With N >> num_cache_sets * DEFAULT_ASSOC,
11071116
# every cache slot should hold a valid key (not the -1 sentinel)
11081117
# after the insert kernel runs. Pre-fix the kernel never runs;
11091118
# post-fix it grid-strides over all N indices and populates
11101119
# every slot.
11111120
num_filled = int((lxu_cache_state != -1).sum().item())
1112-
self.assertEqual(num_filled, num_cache_sets * 32)
1121+
self.assertEqual(num_filled, num_cache_sets * DEFAULT_ASSOC)
11131122
# 3. Every populated slot holds a valid linear cache index in
11141123
# [0, N). This catches "kernel wrote wrong key" bugs.
11151124
populated = lxu_cache_state[lxu_cache_state != -1]

0 commit comments

Comments
 (0)