Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/Tensile/Components/Subtile/ClusterBarrier.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

153 lines
6.2 KiB
Python

# Copyright Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Cluster-scope barrier handshake for the subtile mainloop.
The handshake is split into a *signal* half and a *wait* half so the wait can be
moved away from the signal, hiding the cluster barrier's cross-CU latency behind
the WMMAs that issue in between instead of exposing it as a stall.
"""
from __future__ import annotations
from rocisa.code import Label, Module
from rocisa.container import sgpr
from rocisa.instruction import (SBarrier, BranchInstruction, SCBranchSCC0,
SCmpEQU32,
MFMAInstruction, MXMFMAInstruction)
_isWgBarrier = lambda x: isinstance(x, SBarrier) and "s_barrier_wait -1" in str(x)
def _findNextMFMA(items, start):
"""Index of the first MFMA at/after ``start``, or ``None`` if none follows."""
for j in range(start, len(items)):
if isinstance(items[j], (MFMAInstruction, MXMFMAInstruction)):
return j
return None
def subtileClusterBarrierSignal(writer, kernel) -> Module:
"""Wave-0-only cluster_barrier signal.
Wave 0 alone issues the cluster_barrier signal; all other waves branch over
it. Ends at the ``skipPreSignal`` label so all waves fall through to whatever
work follows; the matching wait is emitted later by ``subtileClusterBarrierWait``.
"""
mod = Module("subtile_cluster_barrier_signal")
skipPreSignal = Label(writer.labels.getUniqueNamePrefix("skipCBPreSignal"), "", 16)
# Elect wave 0 to issue the single cluster_barrier signal.
mod.add(SCmpEQU32(sgpr("WaveIdx"), 0, "wave 0?"))
mod.add(SCBranchSCC0(skipPreSignal.getLabelName(), "only wave 0 signals the cluster"))
mod.add(SBarrier(True, False, True, "cluster_barrier signal"))
mod.add(skipPreSignal)
return mod
def subtileClusterBarrierWait(writer, kernel) -> Module:
"""The all-waves cluster_barrier wait that closes the handshake."""
mod = Module("subtile_cluster_barrier_wait")
mod.add(SBarrier(True, True, True, "cluster_barrier wait"))
return mod
def insertClusterBarrier(module, writer, kernel):
"""Splice the cluster-scope barrier handshake into the post-schedule order.
No-op unless ``ClusterBarrier`` is enabled. The signal is spliced in right
after the mainloop's existing workgroup barrier (reusing that sync instead of
emitting a second one); the wait is appended at the end of the section, so the
barrier's cross-CU latency overlaps the whole macro tile's WMMAs before the
handshake is closed.
If no workgroup barrier is found in this section, the signal is prepended at
the start so the handshake is still opened (correctness over reuse).
Returns a rebuilt Module; the input is left untouched.
"""
if not kernel.get("ClusterBarrier"):
return module
signalItems = subtileClusterBarrierSignal(writer, kernel).flatitems()
waitItems = subtileClusterBarrierWait(writer, kernel).flatitems()
# ClusterBarrier is only supported on gfx1250.
assert writer.states.asmCaps.get("HasClusterBarrier", False), \
"ClusterBarrier requires the HasClusterBarrier asm capability"
# Place the wave-0-election branch right after a WMMA to hide branching
# latency: keep s_cmp before the next scheduled MFMA and emit the branch
# after it.
items = module.flatitems()
result = Module(module.name)
done = False
skip = set()
for i, inst in enumerate(items):
if i in skip:
continue
result.add(inst)
if not done and _isWgBarrier(inst):
done = True
mfmaIdx = _findNextMFMA(items, i + 1)
if mfmaIdx is None:
# No following MFMA to pin the branch to: emit the block intact
# (best-effort).
for s in signalItems:
result.add(s)
else:
# Split the signal block at the wave-0 election branch. The
# block is authored with exactly one conditional branch; assert
# it so a future change that adds another fails loudly here.
brIdxs = [k for k, s in enumerate(signalItems)
if isinstance(s, SCBranchSCC0)]
assert len(brIdxs) == 1, \
"signal block must contain exactly one wave-0 election branch"
brIdx = brIdxs[0]
pre, post = signalItems[:brIdx], signalItems[brIdx:]
# Everything up to the MFMA (incl. its s_set_vgpr_msb primer)
# keeps its order, then s_cmp, the MFMA, and the branch. SCC
# survives the MFMA and vgpr-msb is a persistent mode, so the
# intervening compare disturbs neither.
for k in range(i + 1, mfmaIdx):
result.add(items[k])
skip.add(k)
for s in pre:
result.add(s)
result.add(items[mfmaIdx])
skip.add(mfmaIdx)
for s in post:
result.add(s)
if not done: # no workgroup barrier: open the handshake at the start
head = Module(module.name)
head.add(SBarrier(True, False, False))
head.add(SBarrier(True, True, False, "workgroup barrier wait"))
for s in signalItems:
head.add(s)
for inst in result.flatitems():
head.add(inst)
result = head
# Second pass: place the wait before the first branch after the signal,
# so no exit path can skip it. Falls back to end-of-module if no branch follows.
signalInst = next(s for s in signalItems if isinstance(s, SBarrier))
items = result.flatitems()
patched = Module(result.name)
signalSeen = False
waitPlaced = False
for inst in items:
if inst is signalInst:
signalSeen = True
waitPlaced = False
if signalSeen and not waitPlaced and isinstance(inst, BranchInstruction):
for w in waitItems:
patched.add(w)
waitPlaced = True
signalSeen = False
patched.add(inst)
# Trailing wait for the last signal if no exit branch followed it.
if signalSeen and not waitPlaced:
for w in waitItems:
patched.add(w)
return patched