Skip to content

Commit e500fee

Browse files
committed
[ET-VK][fix] Widen WAR barrier to a full memory dependency for reused tensors
`vTensorStorage::transition()` emitted the write-after-read (WAR) barrier with a read-only source access mask, which Vulkan treats as an execution-only dependency (no memory dependency). Some Adreno drivers drop this narrow `COMPUTE -> COMPUTE` dependency, letting the current write race the previous read. This surfaced as deterministic output corruption at the tile seams of the tiled im2col+GEMM conv2d path (the reused im2col scratch `TmpTensor`): the next tile's im2col overwrote the trailing rows of the scratch while the current tile's GEMM was still reading them. The Vulkan op impl was unchanged and passed previously only because other leased CI devices happened to serialize the tiles; a device/driver whose scheduling did not exposed the latent hazard. When the previous access was a genuine read-only (`prev_read && !prev_written && cur_written`), widen the barrier to a full `ALL_COMMANDS` execution + memory dependency so the driver reliably honors it. Scoped to the rare WAR transition, so the common first-write and RAW/WAW paths are untouched; widening a barrier is always correctness-safe. Fixes WAR hazards generically for all storage types, not just this conv. Differential Revision: [D111994459](https://our.internmc.facebook.com/intern/diff/D111994459/) ghstack-source-id: 402958244 Pull-Request: #20915
1 parent a6aaeff commit e500fee

1 file changed

Lines changed: 13 additions & 2 deletions

File tree

backends/vulkan/runtime/api/containers/Tensor.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -810,11 +810,22 @@ void vTensorStorage::transition(
810810
dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
811811
}
812812

813+
VkAccessFlags dst_access = vkapi::vk_access(cur_stage, cur_access);
814+
815+
// WAR hazard: the read-only source access mask yields an execution-only
816+
// dependency that some drivers may drop, so widen it to a full memory
817+
// barrier to keep the write from racing the prior read.
818+
const bool prev_read = (prev_access & vkapi::MemoryAccessType::READ) != 0;
819+
if (prev_read && !prev_written && cur_written) {
820+
src_stage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
821+
dst_stage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
822+
src_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
823+
dst_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
824+
}
825+
813826
pipeline_barrier.stage.src |= src_stage;
814827
pipeline_barrier.stage.dst |= dst_stage;
815828

816-
VkAccessFlags dst_access = vkapi::vk_access(cur_stage, cur_access);
817-
818829
if (image_) {
819830
pipeline_barrier.images.emplace_back(
820831
src_access, dst_access, cur_layout, new_layout, image_);

0 commit comments

Comments
 (0)