Download code/tt_sceneseg/tt/kernels/mkt_writer.cpp from changh95/sceneseg-p150: direct link, hf CLI and curl.
- Browser
- Download file 9.29 kB
-
https://huggingface.co/changh95/sceneseg-p150/resolve/main/code/tt_sceneseg/tt/kernels/mkt_writer.cpp
- Command line
-
hf download hf://changh95/sceneseg-p150/code/tt_sceneseg/tt/kernels/mkt_writer.cpp
-
curl -L -o mkt_writer.cpp https://huggingface.co/changh95/sceneseg-p150/resolve/main/code/tt_sceneseg/tt/kernels/mkt_writer.cpp
9.29 kB
| // SPDX-License-Identifier: Apache-2.0 | |
| // MK-T writer (sceneseg-p150 OPT_PLAN 3.4, the D19 seg-tail module megakernel, tt/mkt.py), BRISC. | |
| // | |
| // D store (CB 6, the same L1 address on every core): slot s (0 .. n + 1) = image row ya - 1 + s of the bf16 | |
| // 64-channel decode_layer_9 map, 4 channel groups of RSB = (W + 2) * 32 bytes each: stick (pixel p, group g) at | |
| // slot + g * RSB + (p + 1) * 32 (pixels -1 and W are the zero padding sticks). | |
| // 0. zero the padding sticks of every slot, and the halo slot outside the image (slot 0 of core 0, slot n + 1 of | |
| // the last core). | |
| // 1. phase 1, per tile column x: the n x 2 bf16 tiles of compute (CB 16; tile (i, c) = pixels x0 .. x0 + 31 of row | |
| // ya + i, channels 32 c ..) -> slot i + 1 as four 512-byte face copies (face f = group 2c + (f & 1), pixels | |
| // x0 + 16 (f >> 1) ..); MKT_DBG >= 1 also writes them to the debug map. | |
| // 2. exchange (no multicast, no grid barrier): after its own rows have landed, each core increments semaphore 0 of | |
| // its neighbours c - 1 and c + 1, waits until its own semaphore 0 counts its neighbours (and resets it), copies | |
| // slot n(c - 1) of core c - 1 into its slot 0 and slot 1 of core c + 1 into its slot n + 1 (82 KB reads from the | |
| // neighbour's L1), then increments semaphore 1 of both neighbours (the "done reading" acknowledgement, waited on | |
| // before exit so no core leaves while a neighbour still reads its D store) and hands the reader a token (CB 7). | |
| // 3. phase 2, per tile column: the n fp32 margin tiles (CB 17: [0, m1, m2, pad] per pixel) -> the class of each | |
| // pixel exactly as K8 / ttnn.argmax(dim=1) (strict '>' in the SFPU's sign-magnitude order, lowest index on ties, | |
| // both-zero / subnormal compares equal) into n row buffers; after the last column the n uint8 rows (one W-byte | |
| // page each) are written. MKT_DBG 2 also writes the margin tiles. | |
| // Semaphores are self-cleaning (reset after each wait) for trace replays. | |
| // CT args: [0] H, [1] W, [2] NC, [3] GX, [4] RB, [5] RE, then the TensorAccessorArgs of the class map, the debug | |
| // decode_layer_9 map and the debug margins. Common RT args: [class map, dbg9, dbgm, NoC coords of cores 0 .. NC-1]. | |
| constexpr uint32_t H = get_compile_time_arg_val(0); | |
| constexpr uint32_t W = get_compile_time_arg_val(1); | |
| constexpr uint32_t NC = get_compile_time_arg_val(2); | |
| constexpr uint32_t GX = get_compile_time_arg_val(3); | |
| constexpr uint32_t RB = get_compile_time_arg_val(4); | |
| constexpr uint32_t RE = get_compile_time_arg_val(5); | |
| constexpr auto out_args = TensorAccessorArgs<6>(); | |
| constexpr auto d9_args = TensorAccessorArgs<out_args.next_compile_time_args_offset()>(); | |
| constexpr auto dm_args = TensorAccessorArgs<d9_args.next_compile_time_args_offset()>(); | |
| constexpr uint32_t XT = W / 32; | |
| constexpr uint32_t TB16 = 2048, TB32 = 4096, FACE = 512, STICK = 32; | |
| constexpr uint32_t RSB = (W + 2) * STICK; | |
| constexpr uint32_t SLOTB = 4 * RSB; | |
| constexpr uint32_t cb_d = 6, cb_sync = 7, cb_scr = 9, cb_d9 = 16, cb_m = 17; | |
| FORCE_INLINE uint64_t core_noc_addr(uint32_t c, uint32_t l1_addr) { | |
| const uint32_t packed = get_common_arg_val<uint32_t>(3 + c); | |
| return get_noc_addr(packed & 0xFFFFu, packed >> 16, l1_addr); | |
| } | |
| // SFPU gt(a, b) on fp32 bit patterns (no NaN in the margins): as K8 (epi_writer.cpp) | |
| FORCE_INLINE bool sfpu_gt(uint32_t a, uint32_t b) { | |
| if ((a & 0x7F800000u) == 0 && (b & 0x7F800000u) == 0) { | |
| return false; | |
| } | |
| const int32_t ka = (a & 0x80000000u) ? -(int32_t)(a & 0x7FFFFFFFu) : (int32_t)a; | |
| const int32_t kb = (b & 0x80000000u) ? -(int32_t)(b & 0x7FFFFFFFu) : (int32_t)b; | |
| return ka > kb; | |
| } | |
| void kernel_main() { | |
| const uint32_t core = get_absolute_logical_y() * GX + get_absolute_logical_x(); | |
| if (core >= NC) { | |
| return; | |
| } | |
| const uint32_t n = RB + (core < RE ? 1 : 0); | |
| const uint32_t ya = core * RB + (core < RE ? core : RE); | |
| const uint32_t d = get_write_ptr(cb_d); | |
| const uint32_t zero = (get_write_ptr(cb_scr) + 63u) & ~63u; | |
| const uint32_t rows = zero + FACE + 64; // n class-map rows of W bytes (64-aligned) | |
| { | |
| volatile tt_l1_ptr uint32_t* z = reinterpret_cast<volatile tt_l1_ptr uint32_t*>(zero); | |
| for (uint32_t i = 0; i < FACE / 4; ++i) { | |
| z[i] = 0; | |
| } | |
| asm volatile("" ::: "memory"); | |
| invalidate_l1_cache(); | |
| } | |
| const uint64_t zero_noc = get_noc_addr(zero); | |
| const uint32_t nr = n + 2; | |
| for (uint32_t s = 0; s < nr; ++s) { | |
| for (uint32_t g = 0; g < 4; ++g) { | |
| const uint32_t reg = d + s * SLOTB + g * RSB; | |
| noc_async_read(zero_noc, reg, STICK); | |
| noc_async_read(zero_noc, reg + (W + 1) * STICK, STICK); | |
| } | |
| } | |
| const bool first = core == 0, last = core == NC - 1; | |
| if (first || last) { | |
| const uint32_t reg = d + (first ? 0 : (n + 1)) * SLOTB; | |
| for (uint32_t o = 0; o < SLOTB; o += FACE) { | |
| noc_async_read(zero_noc, reg + o, (SLOTB - o) < FACE ? (SLOTB - o) : FACE); | |
| } | |
| if (first && last) { | |
| const uint32_t reg2 = d + (n + 1) * SLOTB; | |
| for (uint32_t o = 0; o < SLOTB; o += FACE) { | |
| noc_async_read(zero_noc, reg2 + o, (SLOTB - o) < FACE ? (SLOTB - o) : FACE); | |
| } | |
| } | |
| } | |
| noc_async_read_barrier(); | |
| // ---------------- phase 1: decode_layer_9 tiles into the D store | |
| const uint32_t no = 2 * n; | |
| const auto d9 = TensorAccessor(d9_args, get_common_arg_val<uint32_t>(1), TB16); | |
| for (uint32_t x = 0; x < XT; ++x) { | |
| cb_wait_front(cb_d9, no); | |
| const uint32_t src = get_read_ptr(cb_d9); | |
| for (uint32_t i = 0; i < n; ++i) { | |
| for (uint32_t c = 0; c < 2; ++c) { | |
| const uint32_t tile = src + (i * 2 + c) * TB16; | |
| const uint32_t slot = d + (i + 1) * SLOTB; | |
| for (uint32_t f = 0; f < 4; ++f) { | |
| const uint32_t dst = slot + (2 * c + (f & 1)) * RSB + (x * 32 + (f >> 1) * 16 + 1) * STICK; | |
| noc_async_read(get_noc_addr(tile + f * FACE), dst, FACE); | |
| } | |
| noc_async_write(tile, d9.get_noc_addr(((ya + i) * XT + x) * 2 + c), TB16); | |
| } | |
| } | |
| noc_async_read_barrier(); | |
| noc_async_write_barrier(); | |
| cb_pop_front(cb_d9, no); | |
| } | |
| // ---------------- exchange with the neighbour cores | |
| volatile tt_l1_ptr uint32_t* ready = reinterpret_cast<volatile tt_l1_ptr uint32_t*>(get_semaphore(0)); | |
| volatile tt_l1_ptr uint32_t* done = reinterpret_cast<volatile tt_l1_ptr uint32_t*>(get_semaphore(1)); | |
| const uint32_t nn = (first ? 0 : 1) + (last ? 0 : 1); | |
| if (!first) { | |
| noc_semaphore_inc(core_noc_addr(core - 1, get_semaphore(0)), 1); | |
| } | |
| if (!last) { | |
| noc_semaphore_inc(core_noc_addr(core + 1, get_semaphore(0)), 1); | |
| } | |
| if (nn) { | |
| noc_semaphore_wait(ready, nn); | |
| noc_semaphore_set(ready, 0); | |
| } | |
| if (!first) { | |
| const uint32_t nprev = RB + (core - 1 < RE ? 1 : 0); | |
| noc_async_read(core_noc_addr(core - 1, d + nprev * SLOTB), d, SLOTB); | |
| } | |
| if (!last) { | |
| noc_async_read(core_noc_addr(core + 1, d + SLOTB), d + (n + 1) * SLOTB, SLOTB); | |
| } | |
| noc_async_read_barrier(); | |
| if (!first) { | |
| noc_semaphore_inc(core_noc_addr(core - 1, get_semaphore(1)), 1); | |
| } | |
| if (!last) { | |
| noc_semaphore_inc(core_noc_addr(core + 1, get_semaphore(1)), 1); | |
| } | |
| cb_reserve_back(cb_sync, 1); | |
| cb_push_back(cb_sync, 1); | |
| // ---------------- phase 2: class decision | |
| const auto dm = TensorAccessor(dm_args, get_common_arg_val<uint32_t>(2), TB32); | |
| volatile tt_l1_ptr uint8_t* cls = reinterpret_cast<volatile tt_l1_ptr uint8_t*>(rows); | |
| for (uint32_t x = 0; x < XT; ++x) { | |
| cb_wait_front(cb_m, n); | |
| const uint32_t src = get_read_ptr(cb_m); | |
| for (uint32_t i = 0; i < n; ++i) { | |
| volatile tt_l1_ptr uint32_t* m = reinterpret_cast<volatile tt_l1_ptr uint32_t*>(src + i * TB32); | |
| for (uint32_t r = 0; r < 32; ++r) { | |
| const uint32_t w = (r >> 4) * 512 + (r & 15) * 16; | |
| uint32_t best = m[w]; | |
| uint8_t c = 0; | |
| const uint32_t m1 = m[w + 1], m2 = m[w + 2]; | |
| if (sfpu_gt(m1, best)) { | |
| best = m1; | |
| c = 1; | |
| } | |
| if (sfpu_gt(m2, best)) { | |
| c = 2; | |
| } | |
| cls[i * W + x * 32 + r] = c; | |
| } | |
| noc_async_write(src + i * TB32, dm.get_noc_addr((ya + i) * XT + x), TB32); | |
| } | |
| noc_async_write_barrier(); | |
| cb_pop_front(cb_m, n); | |
| } | |
| const auto out = TensorAccessor(out_args, get_common_arg_val<uint32_t>(0), W); | |
| for (uint32_t i = 0; i < n; ++i) { | |
| noc_async_write(rows + i * W, out.get_noc_addr(ya + i), W); | |
| } | |
| noc_async_write_barrier(); | |
| if (nn) { | |
| noc_semaphore_wait(done, nn); | |
| noc_semaphore_set(done, 0); | |
| } | |
| noc_async_atomic_barrier(); | |
| } | |