v4.2 tag release. (#2638)
This commit is contained in:
@@ -610,7 +610,6 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
grid=grid,
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=(*self.cluster_shape_mn, 1),
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
return
|
||||
@@ -797,7 +796,7 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
gC_mnl = cute.local_tile(
|
||||
mC_mnl, cute.slice_(self.mma_tiler, (None, None, 0)), (None, None, None)
|
||||
)
|
||||
k_block_cnt = cute.size(gA_mkl, mode=[3])
|
||||
k_tile_cnt = cute.size(gA_mkl, mode=[3])
|
||||
|
||||
#
|
||||
# Partition global tensor for TiledMMA_A/B/C
|
||||
@@ -946,17 +945,17 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
(None, mma_tile_coord_mnl[1], None, mma_tile_coord_mnl[2])
|
||||
]
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt
|
||||
ab_producer_state.reset_count()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
#
|
||||
# Tma load loop
|
||||
#
|
||||
for k_block in cutlass.range(0, k_block_cnt, 1, unroll=1):
|
||||
for k_tile in cutlass.range(0, k_tile_cnt, 1, unroll=1):
|
||||
# Conditionally wait for AB buffer empty
|
||||
ab_pipeline.producer_acquire(
|
||||
ab_producer_state, peek_ab_empty_status
|
||||
@@ -992,10 +991,10 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
mcast_mask=sfb_full_mcast_mask,
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt + k_block + 1
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt + k_tile + 1
|
||||
ab_producer_state.advance()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
@@ -1103,10 +1102,10 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
# (MMA, MMA_M, MMA_N)
|
||||
tCtAcc = tCtAcc_base[(None, None, None, acc_producer_state.index)]
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = 0
|
||||
# Peek (try_wait) AB buffer full for k_tile = 0
|
||||
ab_consumer_state.reset_count()
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt and is_leader_cta:
|
||||
if ab_consumer_state.count < k_tile_cnt and is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(
|
||||
ab_consumer_state
|
||||
)
|
||||
@@ -1125,7 +1124,7 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
#
|
||||
# Mma mainloop
|
||||
#
|
||||
for k_block in range(k_block_cnt):
|
||||
for k_tile in range(k_tile_cnt):
|
||||
if is_leader_cta:
|
||||
# Conditionally wait for AB buffer full
|
||||
ab_pipeline.consumer_wait(
|
||||
@@ -1154,44 +1153,44 @@ class Sm100BlockScaledPersistentDenseGemmKernel:
|
||||
)
|
||||
|
||||
# tCtAcc += tCrA * tCrSFA * tCrB * tCrSFB
|
||||
num_kphases = cute.size(tCrA, mode=[2])
|
||||
for kphase_idx in cutlass.range(num_kphases, unroll_full=True):
|
||||
kphase_coord = (
|
||||
num_kblocks = cute.size(tCrA, mode=[2])
|
||||
for kblock_idx in cutlass.range(num_kblocks, unroll_full=True):
|
||||
kblock_coord = (
|
||||
None,
|
||||
None,
|
||||
kphase_idx,
|
||||
kblock_idx,
|
||||
ab_consumer_state.index,
|
||||
)
|
||||
|
||||
# Set SFA/SFB tensor to tiled_mma
|
||||
sf_kphase_coord = (None, None, kphase_idx)
|
||||
sf_kblock_coord = (None, None, kblock_idx)
|
||||
tiled_mma.set(
|
||||
tcgen05.Field.SFA,
|
||||
tCtSFA[sf_kphase_coord].iterator,
|
||||
tCtSFA[sf_kblock_coord].iterator,
|
||||
)
|
||||
tiled_mma.set(
|
||||
tcgen05.Field.SFB,
|
||||
tCtSFB[sf_kphase_coord].iterator,
|
||||
tCtSFB[sf_kblock_coord].iterator,
|
||||
)
|
||||
|
||||
cute.gemm(
|
||||
tiled_mma,
|
||||
tCtAcc,
|
||||
tCrA[kphase_coord],
|
||||
tCrB[kphase_coord],
|
||||
tCrA[kblock_coord],
|
||||
tCrB[kblock_coord],
|
||||
tCtAcc,
|
||||
)
|
||||
|
||||
# Enable accumulate on tCtAcc after first kphase
|
||||
# Enable accumulate on tCtAcc after first kblock
|
||||
tiled_mma.set(tcgen05.Field.ACCUMULATE, True)
|
||||
|
||||
# Async arrive AB buffer empty
|
||||
ab_pipeline.consumer_release(ab_consumer_state)
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = k_block + 1
|
||||
# Peek (try_wait) AB buffer full for k_tile = k_tile + 1
|
||||
ab_consumer_state.advance()
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt:
|
||||
if ab_consumer_state.count < k_tile_cnt:
|
||||
if is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(
|
||||
ab_consumer_state
|
||||
|
||||
@@ -486,7 +486,6 @@ class DenseGemmKernel:
|
||||
grid=grid,
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=(*self.cluster_shape_mn, 1),
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
return
|
||||
@@ -660,7 +659,7 @@ class DenseGemmKernel:
|
||||
gC_mnl = cute.local_tile(
|
||||
mC_mnl, cute.slice_(self.mma_tiler, (None, None, 0)), (None, None, None)
|
||||
)
|
||||
k_block_cnt = cute.size(gA_mkl, mode=[3])
|
||||
k_tile_cnt = cute.size(gA_mkl, mode=[3])
|
||||
|
||||
#
|
||||
# Partition global tensor for TiledMMA_A/B/C
|
||||
@@ -788,19 +787,19 @@ class DenseGemmKernel:
|
||||
#
|
||||
# Pipelining TMA load A/B and MMA mainloop
|
||||
#
|
||||
prefetch_k_block_cnt = cutlass.min(self.num_ab_stage - 2, k_block_cnt)
|
||||
prefetch_k_tile_cnt = cutlass.min(self.num_ab_stage - 2, k_tile_cnt)
|
||||
|
||||
if warp_idx == 0:
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
#
|
||||
# Prefetch TMA load A/B
|
||||
#
|
||||
for prefetch_idx in cutlass.range(prefetch_k_block_cnt, unroll=1):
|
||||
for prefetch_idx in cutlass.range(prefetch_k_tile_cnt, unroll=1):
|
||||
# Conditionally wait for AB buffer empty
|
||||
ab_pipeline.producer_acquire(ab_producer_state, peek_ab_empty_status)
|
||||
|
||||
@@ -820,27 +819,27 @@ class DenseGemmKernel:
|
||||
mcast_mask=b_full_mcast_mask,
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt + k_block + 1
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt + k_tile + 1
|
||||
ab_producer_state.advance()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = 0
|
||||
# Peek (try_wait) AB buffer full for k_tile = 0
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt and is_leader_cta:
|
||||
if ab_consumer_state.count < k_tile_cnt and is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(ab_consumer_state)
|
||||
|
||||
#
|
||||
# MMA mainloop
|
||||
#
|
||||
for k_block in range(k_block_cnt):
|
||||
for k_tile in range(k_tile_cnt):
|
||||
# Conditionally wait for AB buffer empty
|
||||
ab_pipeline.producer_acquire(ab_producer_state, peek_ab_empty_status)
|
||||
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
# TMA load A/B
|
||||
cute.copy(
|
||||
tma_atom_a,
|
||||
@@ -862,35 +861,35 @@ class DenseGemmKernel:
|
||||
ab_pipeline.consumer_wait(ab_consumer_state, peek_ab_full_status)
|
||||
|
||||
# tCtAcc += tCrA * tCrB
|
||||
num_kphases = cute.size(tCrA, mode=[2])
|
||||
for kphase_idx in cutlass.range(num_kphases, unroll_full=True):
|
||||
kphase_coord = (None, None, kphase_idx, ab_consumer_state.index)
|
||||
num_kblocks = cute.size(tCrA, mode=[2])
|
||||
for kblock_idx in cutlass.range(num_kblocks, unroll_full=True):
|
||||
kblock_coord = (None, None, kblock_idx, ab_consumer_state.index)
|
||||
|
||||
cute.gemm(
|
||||
tiled_mma,
|
||||
tCtAcc,
|
||||
tCrA[kphase_coord],
|
||||
tCrB[kphase_coord],
|
||||
tCrA[kblock_coord],
|
||||
tCrB[kblock_coord],
|
||||
tCtAcc,
|
||||
)
|
||||
# Enable accumulate on tCtAcc after first kphase
|
||||
# Enable accumulate on tCtAcc after first kblock
|
||||
tiled_mma.set(tcgen05.Field.ACCUMULATE, True)
|
||||
|
||||
# Async arrive AB buffer empty
|
||||
ab_pipeline.consumer_release(ab_consumer_state)
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt + k_block + 1
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt + k_tile + 1
|
||||
ab_producer_state.advance()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = k_block + 1
|
||||
# Peek (try_wait) AB buffer full for k_tile = k_tile + 1
|
||||
ab_consumer_state.advance()
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt:
|
||||
if ab_consumer_state.count < k_tile_cnt:
|
||||
if is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(
|
||||
ab_consumer_state
|
||||
@@ -1009,8 +1008,8 @@ class DenseGemmKernel:
|
||||
# Wait A/B buffer empty
|
||||
#
|
||||
if warp_idx == 0:
|
||||
# Reverse prefetch_k_block_cnt times to next available buffer
|
||||
for i in range(prefetch_k_block_cnt):
|
||||
# Reverse prefetch_k_tile_cnt times to next available buffer
|
||||
for i in range(prefetch_k_tile_cnt):
|
||||
ab_producer_state.reverse()
|
||||
ab_pipeline.producer_tail(ab_producer_state)
|
||||
return
|
||||
|
||||
@@ -510,7 +510,6 @@ class PersistentDenseGemmKernel:
|
||||
grid=grid,
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=(*self.cluster_shape_mn, 1),
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
return
|
||||
@@ -669,7 +668,7 @@ class PersistentDenseGemmKernel:
|
||||
gC_mnl = cute.local_tile(
|
||||
mC_mnl, cute.slice_(self.mma_tiler, (None, None, 0)), (None, None, None)
|
||||
)
|
||||
k_block_cnt = cute.size(gA_mkl, mode=[3])
|
||||
k_tile_cnt = cute.size(gA_mkl, mode=[3])
|
||||
|
||||
#
|
||||
# Partition global tensor for TiledMMA_A/B/C
|
||||
@@ -774,17 +773,17 @@ class PersistentDenseGemmKernel:
|
||||
(None, mma_tile_coord_mnl[1], None, mma_tile_coord_mnl[2])
|
||||
]
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt
|
||||
ab_producer_state.reset_count()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
#
|
||||
# Tma load loop
|
||||
#
|
||||
for k_block in cutlass.range(0, k_block_cnt, 1, unroll=1):
|
||||
for k_tile in cutlass.range(0, k_tile_cnt, 1, unroll=1):
|
||||
# Conditionally wait for AB buffer empty
|
||||
ab_pipeline.producer_acquire(
|
||||
ab_producer_state, peek_ab_empty_status
|
||||
@@ -806,10 +805,10 @@ class PersistentDenseGemmKernel:
|
||||
mcast_mask=b_full_mcast_mask,
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt + k_block + 1
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt + k_tile + 1
|
||||
ab_producer_state.advance()
|
||||
peek_ab_empty_status = cutlass.Boolean(1)
|
||||
if ab_producer_state.count < k_block_cnt:
|
||||
if ab_producer_state.count < k_tile_cnt:
|
||||
peek_ab_empty_status = ab_pipeline.producer_try_acquire(
|
||||
ab_producer_state
|
||||
)
|
||||
@@ -877,10 +876,10 @@ class PersistentDenseGemmKernel:
|
||||
# (MMA, MMA_M, MMA_N)
|
||||
tCtAcc = tCtAcc_base[(None, None, None, acc_producer_state.index)]
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = 0
|
||||
# Peek (try_wait) AB buffer full for k_tile = 0
|
||||
ab_consumer_state.reset_count()
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt and is_leader_cta:
|
||||
if ab_consumer_state.count < k_tile_cnt and is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(
|
||||
ab_consumer_state
|
||||
)
|
||||
@@ -899,7 +898,7 @@ class PersistentDenseGemmKernel:
|
||||
#
|
||||
# Mma mainloop
|
||||
#
|
||||
for k_block in range(k_block_cnt):
|
||||
for k_tile in range(k_tile_cnt):
|
||||
if is_leader_cta:
|
||||
# Conditionally wait for AB buffer full
|
||||
ab_pipeline.consumer_wait(
|
||||
@@ -907,32 +906,32 @@ class PersistentDenseGemmKernel:
|
||||
)
|
||||
|
||||
# tCtAcc += tCrA * tCrB
|
||||
num_kphases = cute.size(tCrA, mode=[2])
|
||||
for kphase_idx in cutlass.range(num_kphases, unroll_full=True):
|
||||
kphase_coord = (
|
||||
num_kblocks = cute.size(tCrA, mode=[2])
|
||||
for kblock_idx in cutlass.range(num_kblocks, unroll_full=True):
|
||||
kblock_coord = (
|
||||
None,
|
||||
None,
|
||||
kphase_idx,
|
||||
kblock_idx,
|
||||
ab_consumer_state.index,
|
||||
)
|
||||
|
||||
cute.gemm(
|
||||
tiled_mma,
|
||||
tCtAcc,
|
||||
tCrA[kphase_coord],
|
||||
tCrB[kphase_coord],
|
||||
tCrA[kblock_coord],
|
||||
tCrB[kblock_coord],
|
||||
tCtAcc,
|
||||
)
|
||||
# Enable accumulate on tCtAcc after first kphase
|
||||
# Enable accumulate on tCtAcc after first kblock
|
||||
tiled_mma.set(tcgen05.Field.ACCUMULATE, True)
|
||||
|
||||
# Async arrive AB buffer empty
|
||||
ab_pipeline.consumer_release(ab_consumer_state)
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = k_block + 1
|
||||
# Peek (try_wait) AB buffer full for k_tile = k_tile + 1
|
||||
ab_consumer_state.advance()
|
||||
peek_ab_full_status = cutlass.Boolean(1)
|
||||
if ab_consumer_state.count < k_block_cnt:
|
||||
if ab_consumer_state.count < k_tile_cnt:
|
||||
if is_leader_cta:
|
||||
peek_ab_full_status = ab_pipeline.consumer_try_wait(
|
||||
ab_consumer_state
|
||||
|
||||
@@ -110,17 +110,6 @@ Constraints:
|
||||
"""
|
||||
|
||||
|
||||
class PipelineStateMinimal:
|
||||
"""
|
||||
Pipeline state contains an index and phase bit corresponding to the current position in the circular buffer.
|
||||
"""
|
||||
|
||||
def __init__(self, count, index, phase):
|
||||
self.count = count
|
||||
self.index = index
|
||||
self.phase = phase
|
||||
|
||||
|
||||
class DenseGemmKernel:
|
||||
"""
|
||||
This class implements batched matrix multiplication (C = A x B) with support for various data types
|
||||
@@ -497,7 +486,6 @@ class DenseGemmKernel:
|
||||
grid=grid,
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=(*self.cluster_shape_mn, 1),
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
return
|
||||
@@ -576,13 +564,19 @@ class DenseGemmKernel:
|
||||
pipeline.Agent.Thread, num_tma_producer
|
||||
)
|
||||
ab_pipeline = pipeline.PipelineTmaUmma.create(
|
||||
barrier_storage=storage.ab_full_mbar_ptr.data_ptr(),
|
||||
num_stages=self.num_ab_stage,
|
||||
producer_group=ab_pipeline_producer_group,
|
||||
consumer_group=ab_pipeline_consumer_group,
|
||||
tx_count=self.num_tma_load_bytes,
|
||||
barrier_storage=storage.ab_full_mbar_ptr.data_ptr(),
|
||||
cta_layout_vmnk=cluster_layout_vmnk,
|
||||
)
|
||||
ab_producer_state = pipeline.make_pipeline_state(
|
||||
pipeline.PipelineUserType.Producer, self.num_ab_stage
|
||||
)
|
||||
ab_consumer_state = pipeline.make_pipeline_state(
|
||||
pipeline.PipelineUserType.Consumer, self.num_ab_stage
|
||||
)
|
||||
|
||||
# Initialize acc_pipeline (barrier) and states
|
||||
acc_pipeline_producer_group = pipeline.CooperativeGroup(pipeline.Agent.Thread)
|
||||
@@ -590,10 +584,10 @@ class DenseGemmKernel:
|
||||
pipeline.Agent.Thread, self.threads_per_cta, self.threads_per_cta
|
||||
)
|
||||
acc_pipeline = pipeline.PipelineUmmaAsync.create(
|
||||
barrier_storage=storage.acc_full_mbar_ptr.data_ptr(),
|
||||
num_stages=self.num_acc_stage,
|
||||
producer_group=acc_pipeline_producer_group,
|
||||
consumer_group=acc_pipeline_consumer_group,
|
||||
barrier_storage=storage.acc_full_mbar_ptr.data_ptr(),
|
||||
cta_layout_vmnk=cluster_layout_vmnk,
|
||||
)
|
||||
acc_producer_state = pipeline.make_pipeline_state(
|
||||
@@ -665,7 +659,7 @@ class DenseGemmKernel:
|
||||
gC_mnl = cute.local_tile(
|
||||
mC_mnl, cute.slice_(self.mma_tiler, (None, None, 0)), (None, None, None)
|
||||
)
|
||||
k_block_cnt = cute.size(gA_mkl, mode=[3])
|
||||
k_tile_cnt = cute.size(gA_mkl, mode=[3])
|
||||
|
||||
#
|
||||
# Partition global tensor for TiledMMA_A/B/C
|
||||
@@ -793,24 +787,12 @@ class DenseGemmKernel:
|
||||
# ///////////////////////////////////////////////////////////////////////////////
|
||||
# MAINLOOP
|
||||
# ///////////////////////////////////////////////////////////////////////////////
|
||||
prefetch_k_block_cnt = cutlass.min(self.num_ab_stage - 2, k_block_cnt)
|
||||
prefetch_k_tile_cnt = cutlass.min(self.num_ab_stage - 2, k_tile_cnt)
|
||||
if warp_idx == 0:
|
||||
for k_block in cutlass.range(
|
||||
k_block_cnt,
|
||||
pipelining=self.num_ab_stage - 2,
|
||||
for k_tile in cutlass.range(
|
||||
k_tile_cnt,
|
||||
prefetch_stages=self.num_ab_stage - 2,
|
||||
):
|
||||
ab_producer_state = PipelineStateMinimal(
|
||||
k_block,
|
||||
k_block % self.num_ab_stage,
|
||||
cutlass.Int32((k_block // self.num_ab_stage) % 2) ^ 1,
|
||||
)
|
||||
|
||||
ab_consumer_state = PipelineStateMinimal(
|
||||
k_block,
|
||||
k_block % self.num_ab_stage,
|
||||
cutlass.Int32((k_block // self.num_ab_stage) % 2),
|
||||
)
|
||||
|
||||
# wait for AB buffer empty
|
||||
ab_pipeline.producer_acquire(ab_producer_state)
|
||||
|
||||
@@ -835,22 +817,26 @@ class DenseGemmKernel:
|
||||
ab_pipeline.consumer_wait(ab_consumer_state)
|
||||
|
||||
# tCtAcc += tCrA * tCrB
|
||||
num_kphases = cute.size(tCrA, mode=[2])
|
||||
for kphase_idx in cutlass.range(num_kphases, unroll_full=True):
|
||||
kphase_coord = (None, None, kphase_idx, ab_consumer_state.index)
|
||||
num_kblocks = cute.size(tCrA, mode=[2])
|
||||
for kblock_idx in cutlass.range(num_kblocks, unroll_full=True):
|
||||
kblock_coord = (None, None, kblock_idx, ab_consumer_state.index)
|
||||
|
||||
cute.gemm(
|
||||
tiled_mma,
|
||||
tCtAcc,
|
||||
tCrA[kphase_coord],
|
||||
tCrB[kphase_coord],
|
||||
tCrA[kblock_coord],
|
||||
tCrB[kblock_coord],
|
||||
tCtAcc,
|
||||
)
|
||||
# Enable accumulate on tCtAcc after first kphase
|
||||
# Enable accumulate on tCtAcc after first kblock
|
||||
tiled_mma.set(tcgen05.Field.ACCUMULATE, True)
|
||||
|
||||
# Async arrive AB buffer empty
|
||||
ab_pipeline.consumer_release(ab_consumer_state)
|
||||
|
||||
ab_producer_state.advance()
|
||||
ab_consumer_state.advance()
|
||||
|
||||
# Async arrive accumulator buffer full
|
||||
if is_leader_cta:
|
||||
acc_pipeline.producer_commit(acc_producer_state)
|
||||
@@ -964,12 +950,10 @@ class DenseGemmKernel:
|
||||
# Wait A/B buffer empty
|
||||
#
|
||||
if warp_idx == 0:
|
||||
ab_producer_state = PipelineStateMinimal(
|
||||
k_block_cnt,
|
||||
k_block_cnt % self.num_ab_stage,
|
||||
cutlass.Int32((k_block_cnt // self.num_ab_stage) % 2) ^ 1,
|
||||
)
|
||||
ab_pipeline.producer_acquire(ab_producer_state)
|
||||
# Reverse prefetch_k_tile_cnt times to next available buffer
|
||||
for i in range(prefetch_k_tile_cnt):
|
||||
ab_producer_state.reverse()
|
||||
ab_pipeline.producer_tail(ab_producer_state)
|
||||
return
|
||||
|
||||
def epilog_tmem_copy_and_partition(
|
||||
@@ -1579,7 +1563,6 @@ def run_dense_gemm(
|
||||
warmup_iterations: int = 0,
|
||||
iterations: int = 1,
|
||||
skip_ref_check: bool = False,
|
||||
measure_launch_overhead=False,
|
||||
):
|
||||
"""
|
||||
Prepare A/B/C tensors, launch GPU kernel, and reference checking.
|
||||
@@ -1725,7 +1708,7 @@ def run_dense_gemm(
|
||||
ref_c = ref
|
||||
elif c_dtype in {cutlass.Float8E5M2, cutlass.Float8E4M3FN}:
|
||||
# m major: (l, n, m) -> (m, n, l)
|
||||
# k major: (l, m, n) -> (m, n, l)
|
||||
# n major: (l, m, n) -> (m, n, l)
|
||||
permute_order = (1, 2, 0) if c_major == "n" else (2, 1, 0)
|
||||
shape = (l, m, n) if c_major == "n" else (l, n, m)
|
||||
f8_torch_tensor = cutlass_torch.create_and_permute_torch_tensor(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -475,7 +475,6 @@ class GroupedGemmKernel:
|
||||
grid=grid,
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=(*self.cluster_shape_mn, 1),
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
return
|
||||
@@ -785,7 +784,7 @@ class GroupedGemmKernel:
|
||||
)
|
||||
tensormap_init_done = cutlass.Boolean(False)
|
||||
# tile count we have searched
|
||||
total_k_block_cnt = cutlass.Int32(0)
|
||||
total_k_tile_cnt = cutlass.Int32(0)
|
||||
# group index of last tile
|
||||
last_group_idx = cutlass.Int32(-1)
|
||||
work_tile = tile_sched.initial_work_tile_info()
|
||||
@@ -795,7 +794,7 @@ class GroupedGemmKernel:
|
||||
cur_tile_coord,
|
||||
problem_sizes_mnkl,
|
||||
)
|
||||
cur_k_block_cnt = grouped_gemm_cta_tile_info.cta_tile_count_k
|
||||
cur_k_tile_cnt = grouped_gemm_cta_tile_info.cta_tile_count_k
|
||||
cur_group_idx = grouped_gemm_cta_tile_info.group_idx
|
||||
is_group_changed = cur_group_idx != last_group_idx
|
||||
# skip tensormap update if we're working on the same group
|
||||
@@ -861,17 +860,17 @@ class GroupedGemmKernel:
|
||||
(None, mma_tile_coord_mnl[1], None, mma_tile_coord_mnl[2])
|
||||
]
|
||||
|
||||
num_prev_k_blk = total_k_block_cnt
|
||||
total_k_block_cnt += cur_k_block_cnt
|
||||
num_prev_k_blk = total_k_tile_cnt
|
||||
total_k_tile_cnt += cur_k_tile_cnt
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt
|
||||
tma_wr_k_block = cutlass.Int32(0)
|
||||
smem_wr_buffer = (num_prev_k_blk + tma_wr_k_block) % self.num_ab_stage
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt
|
||||
tma_wr_k_tile = cutlass.Int32(0)
|
||||
smem_wr_buffer = (num_prev_k_blk + tma_wr_k_tile) % self.num_ab_stage
|
||||
tma_wr_ab_empty_phase = (
|
||||
num_prev_k_blk + tma_wr_k_block
|
||||
num_prev_k_blk + tma_wr_k_tile
|
||||
) // self.num_ab_stage % 2 ^ 1
|
||||
peek_ab_empty_status = cute.arch.mbarrier_conditional_try_wait(
|
||||
tma_wr_k_block < cur_k_block_cnt,
|
||||
tma_wr_k_tile < cur_k_tile_cnt,
|
||||
ab_empty_mbar_ptr + smem_wr_buffer,
|
||||
tma_wr_ab_empty_phase,
|
||||
)
|
||||
@@ -882,10 +881,10 @@ class GroupedGemmKernel:
|
||||
#
|
||||
# Tma load loop
|
||||
#
|
||||
for k_block in cutlass.range(0, cur_k_block_cnt, 1, unroll=1):
|
||||
tma_wr_k_block_next = tma_wr_k_block + 1
|
||||
for k_tile in cutlass.range(0, cur_k_tile_cnt, 1, unroll=1):
|
||||
tma_wr_k_tile_next = tma_wr_k_tile + 1
|
||||
smem_wr_buffer_next = (
|
||||
num_prev_k_blk + tma_wr_k_block_next
|
||||
num_prev_k_blk + tma_wr_k_tile_next
|
||||
) % self.num_ab_stage
|
||||
tma_wr_ab_empty_phase_next = (
|
||||
tma_wr_ab_empty_phase ^ 1
|
||||
@@ -911,7 +910,7 @@ class GroupedGemmKernel:
|
||||
# Load A/B with TMA
|
||||
cute.copy(
|
||||
tma_atom_a,
|
||||
tAgA_slice[(None, tma_wr_k_block)],
|
||||
tAgA_slice[(None, tma_wr_k_tile)],
|
||||
tAsA[(None, smem_wr_buffer)],
|
||||
tma_bar_ptr=smem_full_mbar_ptr,
|
||||
mcast_mask=a_full_mcast_mask,
|
||||
@@ -922,7 +921,7 @@ class GroupedGemmKernel:
|
||||
)
|
||||
cute.copy(
|
||||
tma_atom_b,
|
||||
tBgB_slice[(None, tma_wr_k_block)],
|
||||
tBgB_slice[(None, tma_wr_k_tile)],
|
||||
tBsB[(None, smem_wr_buffer)],
|
||||
tma_bar_ptr=smem_full_mbar_ptr,
|
||||
mcast_mask=b_full_mcast_mask,
|
||||
@@ -932,14 +931,14 @@ class GroupedGemmKernel:
|
||||
),
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer empty for k_block = prefetch_k_block_cnt + k_block + 1
|
||||
# Peek (try_wait) AB buffer empty for k_tile = prefetch_k_tile_cnt + k_tile + 1
|
||||
peek_ab_empty_status = cute.arch.mbarrier_conditional_try_wait(
|
||||
tma_wr_k_block_next < cur_k_block_cnt,
|
||||
tma_wr_k_tile_next < cur_k_tile_cnt,
|
||||
ab_empty_mbar_ptr + smem_wr_buffer_next,
|
||||
tma_wr_ab_empty_phase_next,
|
||||
)
|
||||
|
||||
tma_wr_k_block = tma_wr_k_block_next
|
||||
tma_wr_k_tile = tma_wr_k_tile_next
|
||||
smem_wr_buffer = smem_wr_buffer_next
|
||||
tma_wr_ab_empty_phase = tma_wr_ab_empty_phase_next
|
||||
|
||||
@@ -998,12 +997,12 @@ class GroupedGemmKernel:
|
||||
|
||||
work_tile = tile_sched.initial_work_tile_info()
|
||||
# tile count we have searched
|
||||
total_k_block_cnt = cutlass.Int32(0)
|
||||
total_k_tile_cnt = cutlass.Int32(0)
|
||||
while work_tile.is_valid_tile:
|
||||
cur_tile_coord = work_tile.tile_idx
|
||||
# MMA warp is only interested in number of tiles along K dimension
|
||||
(
|
||||
cur_k_block_cnt,
|
||||
cur_k_tile_cnt,
|
||||
cur_group_idx,
|
||||
) = group_gemm_ts_helper.search_cluster_tile_count_k(
|
||||
cur_tile_coord,
|
||||
@@ -1014,17 +1013,17 @@ class GroupedGemmKernel:
|
||||
# (MMA, MMA_M, MMA_N)
|
||||
tCtAcc = tCtAcc_base[(None, None, None, acc_buf_idx)]
|
||||
|
||||
num_prev_k_blk = total_k_block_cnt
|
||||
total_k_block_cnt += cur_k_block_cnt
|
||||
num_prev_k_blk = total_k_tile_cnt
|
||||
total_k_tile_cnt += cur_k_tile_cnt
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = 0
|
||||
mma_rd_k_block = cutlass.Int32(0)
|
||||
smem_rd_buffer = (num_prev_k_blk + mma_rd_k_block) % self.num_ab_stage
|
||||
# Peek (try_wait) AB buffer full for k_tile = 0
|
||||
mma_rd_k_tile = cutlass.Int32(0)
|
||||
smem_rd_buffer = (num_prev_k_blk + mma_rd_k_tile) % self.num_ab_stage
|
||||
need_check_rd_buffer_full = (
|
||||
mma_rd_k_block < cur_k_block_cnt and is_leader_cta
|
||||
mma_rd_k_tile < cur_k_tile_cnt and is_leader_cta
|
||||
)
|
||||
mma_rd_ab_full_phase = (
|
||||
(num_prev_k_blk + mma_rd_k_block) // self.num_ab_stage % 2
|
||||
(num_prev_k_blk + mma_rd_k_tile) // self.num_ab_stage % 2
|
||||
)
|
||||
peek_ab_full_status = cute.arch.mbarrier_conditional_try_wait(
|
||||
need_check_rd_buffer_full,
|
||||
@@ -1051,10 +1050,10 @@ class GroupedGemmKernel:
|
||||
#
|
||||
# Mma mainloop
|
||||
#
|
||||
for k_block in range(cur_k_block_cnt):
|
||||
mma_rd_k_block_next = cutlass.Int32(k_block + 1)
|
||||
for k_tile in range(cur_k_tile_cnt):
|
||||
mma_rd_k_tile_next = cutlass.Int32(k_tile + 1)
|
||||
smem_rd_buffer_next = (
|
||||
num_prev_k_blk + mma_rd_k_block_next
|
||||
num_prev_k_blk + mma_rd_k_tile_next
|
||||
) % self.num_ab_stage
|
||||
mma_rd_ab_full_phase_next = (
|
||||
mma_rd_ab_full_phase ^ 1
|
||||
@@ -1069,18 +1068,18 @@ class GroupedGemmKernel:
|
||||
)
|
||||
|
||||
# tCtAcc += tCrA * tCrB
|
||||
num_kphases = cute.size(tCrA, mode=[2])
|
||||
for kphase_idx in cutlass.range(num_kphases, unroll_full=True):
|
||||
kphase_coord = (None, None, kphase_idx, smem_rd_buffer)
|
||||
num_kblocks = cute.size(tCrA, mode=[2])
|
||||
for kblock_idx in cutlass.range(num_kblocks, unroll_full=True):
|
||||
kblock_coord = (None, None, kblock_idx, smem_rd_buffer)
|
||||
|
||||
cute.gemm(
|
||||
tiled_mma,
|
||||
tCtAcc,
|
||||
tCrA[kphase_coord],
|
||||
tCrB[kphase_coord],
|
||||
tCrA[kblock_coord],
|
||||
tCrB[kblock_coord],
|
||||
tCtAcc,
|
||||
)
|
||||
# Enable accumulate on tCtAcc after first kphase
|
||||
# Enable accumulate on tCtAcc after first kblock
|
||||
tiled_mma.set(tcgen05.Field.ACCUMULATE, True)
|
||||
|
||||
# Async arrive AB buffer empty
|
||||
@@ -1091,9 +1090,9 @@ class GroupedGemmKernel:
|
||||
self.cta_group,
|
||||
)
|
||||
|
||||
# Peek (try_wait) AB buffer full for k_block = k_block + 1
|
||||
# Peek (try_wait) AB buffer full for k_tile = k_tile + 1
|
||||
need_check_rd_buffer_full = (
|
||||
mma_rd_k_block_next < cur_k_block_cnt and is_leader_cta
|
||||
mma_rd_k_tile_next < cur_k_tile_cnt and is_leader_cta
|
||||
)
|
||||
|
||||
peek_ab_full_status = cute.arch.mbarrier_conditional_try_wait(
|
||||
@@ -1102,7 +1101,7 @@ class GroupedGemmKernel:
|
||||
mma_rd_ab_full_phase_next,
|
||||
)
|
||||
|
||||
mma_rd_k_block = mma_rd_k_block_next
|
||||
mma_rd_k_tile = mma_rd_k_tile_next
|
||||
smem_rd_buffer = smem_rd_buffer_next
|
||||
mma_rd_ab_full_phase = mma_rd_ab_full_phase_next
|
||||
|
||||
@@ -1201,7 +1200,7 @@ class GroupedGemmKernel:
|
||||
# wait tensormap initialization complete before update
|
||||
tensormap_manager.fence_tensormap_initialization()
|
||||
# tile count we have searched
|
||||
total_k_block_cnt = cutlass.Int32(0)
|
||||
total_k_tile_cnt = cutlass.Int32(0)
|
||||
# group index of last tile
|
||||
last_group_idx = cutlass.Int32(-1)
|
||||
while work_tile.is_valid_tile:
|
||||
@@ -1240,8 +1239,8 @@ class GroupedGemmKernel:
|
||||
grouped_gemm_cta_tile_info.cta_tile_idx_n,
|
||||
0,
|
||||
)
|
||||
cur_k_block_cnt = grouped_gemm_cta_tile_info.cta_tile_count_k
|
||||
total_k_block_cnt += cur_k_block_cnt
|
||||
cur_k_tile_cnt = grouped_gemm_cta_tile_info.cta_tile_count_k
|
||||
total_k_tile_cnt += cur_k_tile_cnt
|
||||
|
||||
#
|
||||
# Slice to per mma tile index
|
||||
@@ -1370,8 +1369,8 @@ class GroupedGemmKernel:
|
||||
#
|
||||
if warp_idx == self.epilog_warp_id[0]:
|
||||
cute.arch.mbarrier_wait(
|
||||
(ab_empty_mbar_ptr + ((total_k_block_cnt - 1) % self.num_ab_stage)),
|
||||
(((total_k_block_cnt - 1) // self.num_ab_stage) % 2),
|
||||
(ab_empty_mbar_ptr + ((total_k_tile_cnt - 1) % self.num_ab_stage)),
|
||||
(((total_k_tile_cnt - 1) // self.num_ab_stage) % 2),
|
||||
)
|
||||
|
||||
@cute.jit
|
||||
|
||||
@@ -622,7 +622,6 @@ class SSDKernel:
|
||||
block=[self.threads_per_cta, 1, 1],
|
||||
cluster=self.cluster_shape_mnk,
|
||||
min_blocks_per_mp=1,
|
||||
smem=self.shared_storage.size_in_bytes(),
|
||||
stream=stream,
|
||||
)
|
||||
|
||||
@@ -693,7 +692,7 @@ class SSDKernel:
|
||||
G = cute.size(tma_tensor_b, mode=[3])
|
||||
NGROUP_RATIO = EH // G
|
||||
|
||||
# Make tiledMma
|
||||
# Make TiledMma
|
||||
(
|
||||
tiled_mma_intra1,
|
||||
tiled_mma_intra2,
|
||||
@@ -1745,7 +1744,7 @@ class SSDKernel:
|
||||
cute.arch.fence_view_async_tmem_load()
|
||||
|
||||
# Combine INTER1_ACC/last_column/State
|
||||
exp_last_column = cute.arch.exp(last_column.ir_value())
|
||||
exp_last_column = cute.math.exp(last_column, fastmath=True)
|
||||
for reg_idx in range(0, cute.size(tTR_rP), 2):
|
||||
(
|
||||
tTR_rP[reg_idx],
|
||||
@@ -2267,9 +2266,11 @@ class SSDKernel:
|
||||
) = cute.arch.fma_packed_f32x2(
|
||||
(tTR_rInter[reg_idx], tTR_rInter[reg_idx + 1]),
|
||||
(
|
||||
cute.arch.exp(tTR_rDeltaA[reg_idx].ir_value()),
|
||||
cute.arch.exp(
|
||||
tTR_rDeltaA[reg_idx + 1].ir_value()
|
||||
cute.math.exp(
|
||||
tTR_rDeltaA[reg_idx], fastmath=True
|
||||
),
|
||||
cute.math.exp(
|
||||
tTR_rDeltaA[reg_idx + 1], fastmath=True
|
||||
),
|
||||
),
|
||||
(tTR_rIntra[reg_idx], tTR_rIntra[reg_idx + 1]),
|
||||
@@ -3072,14 +3073,19 @@ class SSDKernel:
|
||||
m, n = tCoord[subtile_idx]
|
||||
if m < n:
|
||||
tCompute[subtile_idx] = cutlass.Float32(-float("inf"))
|
||||
LOG2_E = cutlass.Float32(1.4426950408889634)
|
||||
for subtile_idx in cutlass.range(0, cute.size(tTR_rQ), 2, unroll_full=True):
|
||||
# TODO: use math.exp directly
|
||||
tCompute_log2e = cute.arch.mul_packed_f32x2(
|
||||
(tCompute[subtile_idx], tCompute[subtile_idx + 1]), (LOG2_E, LOG2_E)
|
||||
)
|
||||
(
|
||||
tCompute[subtile_idx],
|
||||
tCompute[subtile_idx + 1],
|
||||
) = cute.arch.mul_packed_f32x2(
|
||||
cute.arch.exp_packed_f32x2(
|
||||
(tCompute[subtile_idx], tCompute[subtile_idx + 1])
|
||||
(
|
||||
cute.math.exp2(tCompute_log2e[0], fastmath=True),
|
||||
cute.math.exp2(tCompute_log2e[1], fastmath=True),
|
||||
),
|
||||
(tCrDelta[subtile_idx], tCrDelta[subtile_idx + 1]),
|
||||
)
|
||||
@@ -3245,11 +3251,11 @@ class SSDKernel:
|
||||
for reg_idx in range(0, cute.size(tBrB_Compute), 2):
|
||||
tCompute[reg_idx], tCompute[reg_idx + 1] = cute.arch.mul_packed_f32x2(
|
||||
(
|
||||
cute.arch.exp(
|
||||
(last_column - tBrDeltaA_Compute[reg_idx]).ir_value()
|
||||
cute.math.exp(
|
||||
(last_column - tBrDeltaA_Compute[reg_idx]), fastmath=True
|
||||
),
|
||||
cute.arch.exp(
|
||||
(last_column - tBrDeltaA_Compute[reg_idx + 1]).ir_value()
|
||||
cute.math.exp(
|
||||
(last_column - tBrDeltaA_Compute[reg_idx + 1]), fastmath=True
|
||||
),
|
||||
),
|
||||
(tBrDelta_Compute[reg_idx], tBrDelta_Compute[reg_idx + 1]),
|
||||
|
||||
Reference in New Issue
Block a user