Gpu concat kernel improvements - #5175
Conversation
There was a problem hiding this comment.
Pull request overview
Optimizes GPU concat for small, equal-width fast-axis inputs using an LDS-backed tiled kernel, with supporting kernel utilities and tests.
Changes:
- Adds tiled concat selection and execution.
- Extends kernel indexing, shape, debug, and preprocessor utilities.
- Expands GPU kernel and concat verification coverage.
Review performed as a single pass without agent fan-out.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/reduce_dims.cpp |
Enables reduction across differing fast dimensions. |
src/targets/gpu/compile_gen.cpp |
Exposes tile-factor computation. |
src/targets/gpu/include/migraphx/gpu/compile_gen.hpp |
Declares the tile-factor helper. |
src/targets/gpu/jit/concat.cpp |
Selects and launches tiled concat. |
src/targets/gpu/kernels/include/migraphx/kernels/concat.hpp |
Implements tiled and simple concat algorithms. |
src/targets/gpu/kernels/include/migraphx/kernels/debug.hpp |
Supports multi-argument source-location capture. |
src/targets/gpu/kernels/include/migraphx/kernels/functional.hpp |
Reorders helpers and simplifies arg_c<0>. |
src/targets/gpu/kernels/include/migraphx/kernels/index.hpp |
Adds ceiling group counts and block-stride traversal. |
src/targets/gpu/kernels/include/migraphx/kernels/pp.hpp |
Extends recursive preprocessor utilities. |
src/targets/gpu/kernels/include/migraphx/kernels/reduce.hpp |
Adapts reduction to the revised repeat macro. |
src/targets/gpu/kernels/include/migraphx/kernels/shape.hpp |
Asserts nonempty kernel shapes. |
src/targets/gpu/kernels/include/migraphx/kernels/tensor_view.hpp |
Adds multidimensional index construction. |
src/targets/gpu/kernels/include/migraphx/kernels/test.hpp |
Adds templated kernel-test macros. |
test/gpu/compile_gen.cpp |
Tests tile-factor behavior. |
test/gpu/kernels/functional.cpp |
Adds device functional-utility tests. |
test/gpu/kernels/index.cpp |
Tests block-stride traversal. |
test/gpu/kernels/main.cpp |
Discovers templated kernel tests. |
test/gpu/kernels/pp.cpp |
Adds device preprocessor tests. |
test/gpu/kernels/shape.cpp |
Adds device shape tests. |
test/reduce_dims.cpp |
Covers differing fast dimensions. |
test/verify/test_concat_axis_neg_1.cpp |
Exercises varied concat sizes and types. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| std::transform(is.begin(), is.end(), rstrides.begin(), [&](auto i) -> std::size_t { | ||
| if(lens[i] == s.lens()[i]) | ||
| { | ||
| rstrides[i] = stride; | ||
| stride *= lens[i]; | ||
| } | ||
| else if(lens[i] != 1 and s.lens()[i] != 1) | ||
| { | ||
| return shape{}; | ||
| } | ||
| } | ||
| return base.strides()[i]; | ||
| return 0; |
There was a problem hiding this comment.
This has been fixed and additional unit tests added.
| if(concat_axis == axis and max_elements_per_op < 64 and | ||
| max_elements_per_op == avg_elements_per_op) |
There was a problem hiding this comment.
Added a test for this and a check.
| #endif | ||
|
|
||
| constexpr auto ngroup() const { return nglobal() / max_nlocal(); } | ||
| constexpr auto ngroup() const { return (nglobal() + max_nlocal() - _c<1>) / max_nlocal(); } |
There was a problem hiding this comment.
Right now the test harness doesnt support launching with different launch params so its not possible to fully unit test the index class yet.
| // The name may be a template-id, so it can contain spaces and commas | ||
| // (`TEST_CASE_REGISTER(foo<unsigned long, int>)`); trim what that lets in trailing. |
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
format.py
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 520 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 527 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 539 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 546 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Lines 548 to 549 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 556 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Lines 558 to 559 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 566 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Lines 568 to 569 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/gpu/kernels/shape.cpp
Line 573 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/reduce_dims.cpp
Line 195 in c5df9f2
[format.py] reported by reviewdog 🐶
AMDMIGraphX/test/reduce_dims.cpp
Line 205 in c5df9f2
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Motivation
Concat kernels where the concatenation happens on the fast (last) axis with a small number of elements per input (< 64) perform poorly with the existing
simplealgorithm: each input writes a narrow slice of the output, so global writes are strided and uncoalesced, and the launch does little work per wavefront.This PR adds a
block_tilealgorithm to the concat JIT kernel that stages the concatenated output tile in LDS. Each workgroup processes a group of output slices: the per-op inputs (including any fused pointwise pre-ops) are written into a{ngroups, nops, max_size}LDS tile, and after a barrier the tile is written out contiguously in blocked form with the fused post-op applied. This turns the scattered per-op writes into coalesced output writes.Supporting this required generalizing
reduce_dimsto handle shape sets that differ along one axis (the concat axis), so the surrounding equal dimensions can still be collapsed, plus some kernel-infrastructure additions (multi-index subscripts ontensor_view, preprocessor enum machinery, and a blocked stride loop). The new unit-test coverage added along the way caught and fixed several bugs in the initial implementation.Technical Details
Kernel (
kernels/concat.hpp)concat::runis now parameterized on an algorithm.simplekeeps the previous behavior (global-strided writes directly to the output slice).block_tile<NGroups>stages results into a{NGroups, nops, max_size}LDS tile (allocated viauninitialized_buffer) duringrunand writes the output infinishafter__syncthreads(), usingblock_stride<per_block, 8>so each thread writes 8 contiguous elements.slice_schedule<per_block>(idx, slice_axes<-1>(), slice_group<NGroups>()); the group/element index of each slice element is derived with shape indexing (make_shape+multi) rather than ad-hoc arithmetic.Host compiler (
jit/concat.cpp,compile_gen)block_tileis selected when the concat axis is the fast axis, every op contributes the same number of elements (< 64), and the LDS tile (group * nops * max_size * type_size) fits in the 64KB workgroup limit; otherwise it falls back tosimple.tile::compute_factor(lens[axis - 1], 16)—compute_tile_factormoved into thetileclass, exported, and unit-tested (including its check-before-multiply overshoot behavior).reduce_dimsmask_shapeno longer gives up when shapes disagree on an axis with neither length being 1; the differing axis is masked with stride 0, which blocks merging across it while letting the equal dimensions on either side collapse (e.g.{64,16,160,160}/{64,48,160,160}→{64,16,25600}/{64,48,25600}).{1,3,224,224}vs{1,3,229,229}). TODO tests document the mergeable-but-unmerged dimensions this early exit leaves behind.Kernel infrastructure
index.hpp:ngroup()uses ceiling division; newblock_stride<Group, Block>iterates a range in per-thread blocks ofBlockcontiguous elements with a distributed tail.tensor_view.hpp: variadicindex_to_offsetconstructor enables multi-index subscripts (output[{group, depth, k}]), including underMIGRAPHX_DEBUGsource-location capture (debug.hppgenerates the forwarding constructors withMIGRAPHX_PP_ENUM).pp.hpp: addsMIGRAPHX_PP_ENUM,MIGRAPHX_PP_GENERATE,MIGRAPHX_PP_BOOL/NOT, deferred-expansion helpers, and data-carrying variants of the argument-transform macros;MIGRAPHX_PP_REPEATis now curried.functional.hpp:pack/pack_forwardare declared beforeunpack_each(fixes a declaration-order failure for non-ADL types);arg_cspecial-casesN == 0to reduce template instantiations.Testing
pp.hpp,functional.hpp,shape.hpp, andblock_stride(~180 cases), withTEST_CASE_TEMPLATE/TEST_CASE_REGISTERsupport added to the kernel test harness. Theblock_stridecoverage test (visit-each-element-exactly-once via a serial group emulator) is a regression test for a tail-loop bug it caught during development.tile::compute_factorunit tests intest_gpu_compile_gen; newreduce_dimstests for the differing-axis reductions, the incompatible-adjacency bail-out, and TODO cases.test_concat_axis_neg_1is templated over type/sizes to exerciseblock_tile(including a float instantiation), andtest_concat_lds_overflow(30 inputs × 60 elements × 16 groups = 115KB tile) is a regression test that the gate falls back tosimpleinstead of generating a kernel that exceeds the LDS limit.Changelog Category
Add a
CHANGELOG.mdentry for any option other thanNot ApplicableFollow the LLVM AI Tool Use Policy for contributions using AI.