← CuTe 笔记 / cute_make_tiled_mma_trace.cu · 下载原文件
1// Companion to cute_make_tiled_mma_walkthrough_zh.md.
2// Host coordinate checks only: no MMA instruction or GPU kernel is executed.
3// nvcc -std=c++17 -arch=sm_80 -Iinclude cute_make_tiled_mma_trace.cu \
4// -o /tmp/cute_make_tiled_mma_trace
5#include <cute/tensor.hpp>
6#include <cute/atom/mma_traits_sm80.hpp>
7#include <cstdio>
8#include <cstdlib>
9#include <vector>
10
11using namespace cute;
12using Op = SM80_16x8x16_F16F16F16F16_TN;
13
14void require(bool ok, char const* message) {
15 if (!ok) {
16 std::fprintf(stderr, "FAILED: %s\n", message);
17 std::exit(1);
18 }
19}
20
21template<class T>
22void show(char const* label, T const& x) {
23 std::printf("%s = ", label); print(x); print("\n");
24}
25
26template<class MMA>
27void show_c_steps(MMA const& mma) {
28 using AtomTV = typename MMA::AtomLayoutC_TV;
29 auto C = make_layout(make_shape(_32{},_16{}), make_stride(_16{},_1{}));
30 auto t = logical_divide(C, make_tile(mma.template permutation_mnk<0>(),
31 mma.template permutation_mnk<1>()));
32 auto c = zipped_divide(t, make_tile(make_layout(_16{}), make_layout(_8{})));
33 auto tv = c.compose(AtomTV{}, _);
34 auto th = zipped_divide(tv, make_tile(_, make_tile(make_layout(_2{}), make_layout(_2{}))));
35 print("\n[C partition construction, row-major 32x16]\n");
36 show("input C", C);
37 show("logical_divide", t);
38 show("Atom zipped_divide", c);
39 show("compose Atom TV", tv);
40 show("thread zipped_divide", th);
41 show("partition_C thread 0", mma.get_slice(0).partition_C(make_tensor((half_t*)nullptr,C)).layout());
42}
43
44// Independent expectations from the SM80 lane/value rules, including reuse.
45template<int M, int N, int K, int TM, int TN, int TK,
46 bool PermuteM = false, bool ReverseWarps = false, class MMA>
47void verify(char const* label, MMA const& mma) {
48 auto A = make_identity_tensor(make_shape(Int<M>{}, Int<K>{}));
49 auto B = make_identity_tensor(make_shape(Int<N>{}, Int<K>{}));
50 auto C = make_identity_tensor(make_shape(Int<M>{}, Int<N>{}));
51 constexpr int threads = 32*TM*TN*TK;
52 std::vector<int> coverA(M*K), coverB(N*K), coverC(M*N);
53 int checks = 0;
54 auto map_m = [](int m) {
55 if constexpr (PermuteM) return (m/32)*32 + 4*(m%8) + (m%32)/8;
56 else return m;
57 };
58 std::printf("\n[%s]\n", label);
59 show("ThrLayoutVMNK", mma.get_thr_layout_vmnk());
60 show("tile MNK", tile_shape(mma));
61 show("layoutA_TV", mma.get_layoutA_TV());
62 show("layoutB_TV", mma.get_layoutB_TV());
63 show("layoutC_TV", mma.get_layoutC_TV());
64 auto tvA = mma.get_layoutA_TV();
65 auto tvB = mma.get_layoutB_TV();
66 auto tvC = mma.get_layoutC_TV();
67 int tileM = int(tile_size<0>(mma));
68 int tileN = int(tile_size<1>(mma));
69 for (int t = 0; t < threads; ++t) {
70 int lane = t%32, warp = t/32;
71 int wm = ReverseWarps ? warp/TN : warp%TM;
72 int wn = ReverseWarps ? warp%TN : (warp/TM)%TN;
73 int wk = warp/(TM*TN);
74 auto thr = mma.get_slice(t);
75 auto a = thr.partition_A(A);
76 auto b = thr.partition_B(B);
77 auto c = thr.partition_C(C);
78 if (t == 0) {
79 show("partition_A shape", shape(a));
80 show("partition_B shape", shape(b));
81 show("partition_C shape", shape(c));
82 auto rA = thr.partition_fragment_A(make_tensor((half_t*)nullptr, make_layout(shape(A))));
83 auto rB = thr.partition_fragment_B(make_tensor((half_t*)nullptr, make_layout(shape(B))));
84 auto rC = thr.partition_fragment_C(C);
85 show("fragment_A layout", rA.layout());
86 show("fragment_B layout", rB.layout());
87 show("fragment_C layout", rC.layout());
88 }
89 require(int(size(a)) == 8*(M/(16*TM))*(K/(16*TK)), "A size");
90 require(int(size(b)) == 4*(N/(8*TN))*(K/(16*TK)), "B size");
91 require(int(size(c)) == 4*(M/(16*TM))*(N/(8*TN)), "C size");
92 for (int rm = 0; rm < M/(16*TM); ++rm)
93 for (int rk = 0; rk < K/(16*TK); ++rk)
94 for (int v = 0; v < 8; ++v) {
95 int m = map_m(lane/4 + 8*((v/2)%2) + 16*wm + 16*TM*rm);
96 int k = 2*(lane%4) + v%2 + 8*(v/4) + 16*wk + 16*TK*rk;
97 auto coord = a(v,rm,rk);
98 require(int(get<0>(coord)) == m && int(get<1>(coord)) == k, "A coordinate");
99 ++coverA[m+M*k]; ++checks;
100 if (M == tileM && K == int(tile_size<2>(mma)))
101 require(int(tvA(t,make_coord(v,make_coord(rm,rk)))) == m+M*k, "A TV");
102 }
103 for (int rn = 0; rn < N/(8*TN); ++rn)
104 for (int rk = 0; rk < K/(16*TK); ++rk)
105 for (int v = 0; v < 4; ++v) {
106 int n = lane/4 + 8*wn + 8*TN*rn;
107 int k = 2*(lane%4) + v%2 + 8*(v/2) + 16*wk + 16*TK*rk;
108 auto coord = b(v,rn,rk);
109 require(int(get<0>(coord)) == n && int(get<1>(coord)) == k, "B coordinate");
110 ++coverB[n+N*k]; ++checks;
111 if (N == tileN && K == int(tile_size<2>(mma)))
112 require(int(tvB(t,make_coord(v,make_coord(rn,rk)))) == n+N*k, "B TV");
113 }
114 for (int rm = 0; rm < M/(16*TM); ++rm)
115 for (int rn = 0; rn < N/(8*TN); ++rn)
116 for (int v = 0; v < 4; ++v) {
117 int m = map_m(lane/4 + 8*(v/2) + 16*wm + 16*TM*rm);
118 int n = 2*(lane%4) + v%2 + 8*wn + 8*TN*rn;
119 auto coord = c(v,rm,rn);
120 require(int(get<0>(coord)) == m && int(get<1>(coord)) == n, "C coordinate");
121 ++coverC[m+M*n]; ++checks;
122 if (M == tileM && N == tileN)
123 require(int(tvC(t,make_coord(v,make_coord(rm,rn)))) == m+M*n, "C TV");
124 }
125 }
126 for (int count : coverA) require(count == TN, "A coverage multiplicity");
127 for (int count : coverB) require(count == TM, "B coverage multiplicity");
128 for (int count : coverC) require(count == TK, "C coverage multiplicity");
129 std::printf("Verified %d coordinates; A/B/C multiplicity = %d/%d/%d.\n", checks, TN, TM, TK);
130}
131
132int main() {
133 auto base = make_tiled_mma(Op{});
134 auto four = make_tiled_mma(Op{}, Layout<Shape<_2,_2,_1>>{});
135 auto reverse = make_tiled_mma(Op{}, Layout<Shape<_2,_2,_1>,Stride<_2,_1,_0>>{});
136 auto larger = make_tiled_mma(Op{}, Layout<Shape<_2,_2,_1>>{}, Tile<_64,_32,_16>{});
137 using PermM = Layout<Shape<_8,_4>,Stride<_4,_1>>;
138 auto perm = make_tiled_mma(Op{}, Layout<Shape<_2,_2,_1>>{}, Tile<PermM,Underscore,Underscore>{});
139 auto split = make_tiled_mma(Op{}, Layout<Shape<_1,_1,_2>>{});
140 verify<16,8,16,1,1,1>("one warp", base);
141 verify<32,16,16,2,2,1>("four warps", four);
142 verify<64,32,32,2,2,1>("larger input", four);
143 verify<32,16,16,2,2,1,false,true>("reordered warps", reverse);
144 verify<64,32,16,2,2,1>("explicit tile extent", larger);
145 verify<32,16,16,2,2,1,true>("permuted M", perm);
146 verify<16,8,32,1,1,2>("K thread tiling", split);
147 show_c_steps(four);
148 // Separate real storage offsets from the identity-coordinate checks above.
149 auto rowC = make_tensor((half_t*)nullptr,
150 make_layout(make_shape(_64{},_32{}), make_stride(_32{},_1{})));
151 show("large row-major partition_C", four.get_slice(0).partition_C(rowC).layout());
152 print("All make_tiled_mma layout checks passed. No GPU kernel was launched.\n");
153}
154