
总述Layout本质上是一个映射将多维坐标映射成一维索引。IntegersCuTe有静态和动态integer之分它们之间的区别很简单动态integer就是C定义的整型比如int, size_t, uint64_t。将这些类型代入std::is_integralT::value的T将返回true。静态integer本质上是CuTe定义的一种类型并不是整型因此将静态integer代入std::is_integralT::value的T将返回false。静态integer常见的写法有Int1, Int2, Int3或_1, _2, _3。std::is_integralint::value true std::is_integralcute::_3::value false (_3 is C3, a class type) cute::is_std_integralcute::_3 false cute::is_integralcute::_3 true cute::is_integralint true cute::is_staticcute::_3 true cute::is_staticint false sizeof(cute::_3) 1, cute::_3::value 3 sizeof(int) 4 n 4 _3 n 7 (dynamic result) _2 * _3 6 (still a static integer: C6)cute::_3没有非静态成员在C中被认为是一个empty object它的size是1byte有别于int的4 bytesIntTuplesrank打开最外层括号后用逗号分成了几块例子rank(5) 1 // 没逗号就是它自己rank((3,4)) 2 // 1个逗号2项rank((3,4,5)) 3 // 2个逗号3项rank((3,(4,5))) 2 // 最外层只有1个逗号3 和 (4,5) 这两项depth嵌套深度例子depth(5) 0 // 单个整数没有嵌套是叶子depth((3,4)) 1 // 一层tuple里面都是整数depth((3,(4,5))) 2 // 最深处嵌套了2层size(IntTuple) 所有叶子节点数值相乘的总数代表这个 IntTuple 描述的总元素个数。t1 int{2} rank(t1) 1 depth(t1) 0 # 叶子节点的depth是0但是(2)作为一个tuple则是一个子树depth是1 size(t1) 2 get0(t1) 2 t2 Int3{} rank(t2) 1 depth(t2) 0 size(t2) 3 get0(t2) 3 t3 make_tuple(int{2}, Int3{}) rank(t3) 2 depth(t3) 1 size(t3) 6 get0(t3) 2 get1(t3) 3 t4 make_tuple(uint16_t{42}, make_tuple(Int1{}, int32_t{3}), Int17{}) rank(t4) 3 depth(t4) 2 size(t4) 2142 get0(t4) 42 get1(t4) tuple, rank 2, depth 1 get1,0(t4) 1 get1,1(t4) 3 get2(t4) 17 a 6 rank(a) 1, depth(a) 0, size(a) 6 b (2) rank(b) 1, depth(b) 1, size(b) 2 c (4,3) rank(c) 2, depth(c) 1, size(c) 12 d (3,(6,2),8) rank(d) 3, depth(d) 2, size(d) 288 get0(d) 3 get1(d) tuple, rank 2, depth 1, size 12 get1,0(d) 6 get1,1(d) 2 get2(d) 8LayoutLayout (Shape, Stride)Layout可以跟数据组成Tensor通过Stride可以把Shape坐标映射为一个一维的index这个index可以用来访问数据硬件上数据排布都是一维的。rankLayout rank Shape rank 最外层的括号被逗号分隔成几块。getI(Layout):同时从Shape和Stride中取第I个维度拼成一个新的Layout。cosize(Layout):size是「有多少个元素」cosize是「这些元素铺开后要占多长的一段地址」。j0 j1 j2i0 [ 0 ] [ 4 ] [ 8 ]i1 [ 1 ] [ 5 ] [ 9 ]内存一维展开idx: 0 1 2 3 4 5 6 7 8 9┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐│██│██│░░│░░│██│██│░░│░░│██│██│└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘└───── cosize 9 1 10 ─────┘██ range真正被映射到的 6 个位置→ size 6░░ 空洞没有任何坐标映射到这里但地址被圈进来了转indexShape : ( 2 , ( 3 , 4 ) )↕ ↕ ↕Coord : ( i , ( j , k ) ) i∈[0,2) j∈[0,3) k∈[0,4)↕ ↕ ↕Stride: ( 1 , ( 2 , 3 ) )index i*1 j*2 k*3LayoutLeft LayoutRightmake_shape函数在不填写Stride的情况下默认用LayoutLeft。也可声明LayoutRight官方文档上将这种stride描述为“exclusive prefix product”例LayoutLeft从左往右填充stride最先填充的是最左侧的1这个1是固定的不需要过度思考shape :2341x21x2x3stride: (1 , 2 , 6)LayoutRight从右往左填充stride最先填充的是最右侧的1这个1是固定的不需要过度思考shape : 2341x4x31x4stride: (12 ,4, 1)LayoutLeft是col-major最左边的mode拿stride 1 最左边的下标i变化最快LayoutRight是row-major最右边的mode拿stride 1 最右边的下标k变化最快--- observers on s2xh4 (2,(2,2)):(4,(2,1)) --- rank(s2xh4) 2 depth(s2xh4) 2 size(s2xh4) 8 cosize(s2xh4) 8 shape(s2xh4) (2,(2,2)) stride(s2xh4) (4,(2,1)) get0(s2xh4) 2:4 get1(s2xh4) (2,2):(2,1) s2xh4(size-1) 1 8 ( cosize) --- hierarchical access on s2xh4 --- get1,0(s2xh4) 2:2 get1,1(s2xh4) 2:1 rank1(s2xh4) 2 depth1(s2xh4) 1 shape0(s2xh4) 2 shape1(s2xh4) (2,2) size0(s2xh4) 2 size1(s2xh4) 4 size1,0(s2xh4) 2 # 第二个2