Download code/tt_meteor/tt/kernels/argmax_rows2.cpp from changh95/meteor-p150: direct link, hf CLI and curl.
- Browser
- Download file 4.98 kB
-
https://huggingface.co/changh95/meteor-p150/resolve/main/code/tt_meteor/tt/kernels/argmax_rows2.cpp
- Command line
-
hf download hf://changh95/meteor-p150/code/tt_meteor/tt/kernels/argmax_rows2.cpp
-
curl -L -o argmax_rows2.cpp https://huggingface.co/changh95/meteor-p150/resolve/main/code/tt_meteor/tt/kernels/argmax_rows2.cpp
4.98 kB
| // SPDX-License-Identifier: Apache-2.0 | |
| // ARGMAX v2 (meteor-p150 OPT2 round 4 R4.2, tt/argmax.py, METEOR_ARGMAX=fast): argmax_rows.cpp with the same data | |
| // movement and the same compare (ArgMaxNC semantics: fp32 values, strict `>` in channel order, first maximum on ties, | |
| // -0.0 == +0.0), only the per-row reduction rewritten. v1 spent ~32 RISC cycles per element (the per-element face index | |
| // arithmetic and a branchy key transform); the reads are not the limit (the kernel is RISC-bound: 42 MB in 1.9 ms). | |
| // - the key transform is branchless: z = (b << 1) ? b : 0 (-0.0 -> +0.0), key = z ^ ((int32(z) >> 31) | 0x80000000) | |
| // (sign set: ~z; sign clear: z | 0x80000000): the monotone unsigned order of the floats, as v1's key_of; | |
| // - the channels of one row are walked face by face (16 contiguous words), the loop bounds are compile-time (C); | |
| // - two rows (r and r + 16: the same word offsets in face rows 0 and 1) are reduced together, so their loads and | |
| // compares interleave. | |
| // Work unit, work split, CT args, common RT args and CBs: as argmax_rows.cpp (no per-core RT args, probe P3; reads | |
| // and writes on one RISC / NOC, SYS-1419). | |
| constexpr uint32_t NU = get_compile_time_arg_val(0); | |
| constexpr uint32_t NC = get_compile_time_arg_val(1); | |
| constexpr uint32_t GX = get_compile_time_arg_val(2); | |
| constexpr uint32_t C = get_compile_time_arg_val(3); | |
| constexpr uint32_t CT = get_compile_time_arg_val(4); | |
| constexpr auto in_args = TensorAccessorArgs<5>(); | |
| constexpr auto out_args = TensorAccessorArgs<in_args.next_compile_time_args_offset()>(); | |
| constexpr uint32_t TB = 4096; // fp32 tile bytes | |
| constexpr uint32_t SLOT = CT * TB; | |
| constexpr uint32_t OB = 128; // one output row: 32 uint32 | |
| constexpr uint32_t NF = (C + 15) / 16; // faces (16-channel groups) per row | |
| FORCE_INLINE uint32_t key_of(uint32_t b) { | |
| const uint32_t z = (b << 1) ? b : 0u; // -0.0 == +0.0 | |
| return z ^ (static_cast<uint32_t>(static_cast<int32_t>(z) >> 31) | 0x80000000u); | |
| } | |
| // channels [16 g, 16 g + n) of rows r (word offset `a` of face row 0) and r + 16 (a + 512) | |
| template <uint32_t G> | |
| FORCE_INLINE void face(const uint32_t* src, uint32_t a, uint32_t& k0, uint32_t& b0, uint32_t& k1, uint32_t& b1) { | |
| constexpr uint32_t n = (C - 16 * G < 16) ? C - 16 * G : 16; | |
| constexpr uint32_t off = (G >> 1) * 1024 + (G & 1) * 256; // tile G / 2, face column G % 2 | |
| const uint32_t* p = src + off + a; | |
| for (uint32_t j = (G == 0 ? 1 : 0); j < n; ++j) { | |
| const uint32_t x0 = key_of(p[j]); | |
| const uint32_t x1 = key_of(p[j + 512]); | |
| if (x0 > k0) { | |
| k0 = x0; | |
| b0 = 16 * G + j; | |
| } | |
| if (x1 > k1) { | |
| k1 = x1; | |
| b1 = 16 * G + j; | |
| } | |
| } | |
| } | |
| template <uint32_t G> | |
| FORCE_INLINE void faces(const uint32_t* src, uint32_t a, uint32_t& k0, uint32_t& b0, uint32_t& k1, uint32_t& b1) { | |
| if constexpr (G < NF) { | |
| face<G>(src, a, k0, b0, k1, b1); | |
| faces<G + 1>(src, a, k0, b0, k1, b1); | |
| } | |
| } | |
| void kernel_main() { | |
| const uint32_t core = get_absolute_logical_y() * GX + get_absolute_logical_x(); | |
| if (core >= NC) { | |
| return; | |
| } | |
| constexpr uint32_t B = NU / NC, E = NU % NC; | |
| const uint32_t u0 = core * B + (core < E ? core : E); | |
| const uint32_t nu = B + (core < E ? 1 : 0); | |
| if (nu == 0) { | |
| return; | |
| } | |
| const auto in = TensorAccessor(in_args, get_common_arg_val<uint32_t>(0), TB); | |
| const auto out = TensorAccessor(out_args, get_common_arg_val<uint32_t>(1), OB); | |
| const uint32_t ibuf = get_write_ptr(0); | |
| const uint32_t obuf = get_write_ptr(1); | |
| auto issue_reads = [&](uint32_t u, uint32_t buf) { | |
| for (uint32_t k = 0; k < CT; ++k) { | |
| noc_async_read(in.get_noc_addr(u * CT + k), buf + k * TB, TB); | |
| } | |
| }; | |
| issue_reads(u0, ibuf); | |
| for (uint32_t i = 0; i < nu; ++i) { | |
| const uint32_t ib = ibuf + (i & 1) * SLOT; | |
| const uint32_t ob = obuf + (i & 1) * OB; | |
| noc_async_read_barrier(); | |
| if (i + 1 < nu) { | |
| issue_reads(u0 + i + 1, ibuf + ((i + 1) & 1) * SLOT); | |
| } | |
| if (i >= 2) { | |
| noc_async_writes_flushed(); // the write of unit i - 2 (same slot) is out | |
| } | |
| const uint32_t* src = reinterpret_cast<const uint32_t*>(ib); | |
| uint32_t* dst = reinterpret_cast<uint32_t*>(ob); | |
| for (uint32_t r = 0; r < 16; ++r) { | |
| const uint32_t a = r * 16; // row r of face row 0; row r + 16 at a + 512 | |
| uint32_t k0 = key_of(src[a]), b0 = 0; | |
| uint32_t k1 = key_of(src[a + 512]), b1 = 0; | |
| faces<0>(src, a, k0, b0, k1, b1); | |
| dst[r] = b0; | |
| dst[r + 16] = b1; | |
| } | |
| noc_async_write(ob, out.get_noc_addr(u0 + i), OB); | |
| } | |
| noc_async_write_barrier(); | |
| } | |