| 61 | local_packed{nullptr, nullptr} {} |
| 62 | |
| 63 | void Run() override { |
| 64 | TraceRecordThreadStart(thread_id, trace); |
| 65 | |
| 66 | for (Side side : {Side::kLhs, Side::kRhs}) { |
| 67 | if (!params->is_prepacked[side]) { |
| 68 | const int size = NumBlocksPerSide(side, block_map); |
| 69 | local_allocator->Allocate(size, &local_packed[side]); |
| 70 | memset(local_packed[side], 0, size * sizeof(bool)); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | const int num_blocks = NumBlocks(block_map); |
| 75 | |
| 76 | const Tuning tuning = tuning_resolver->Resolve(); |
| 77 | |
| 78 | TraceRecordThreadLoopStart(thread_id, trace); |
| 79 | |
| 80 | SidePair<int> block; |
| 81 | SidePair<int> start; |
| 82 | SidePair<int> end; |
| 83 | |
| 84 | // Each thread starts by initially reserving the block whose id |
| 85 | // is the thread id. |
| 86 | int block_id = thread_id; |
| 87 | TraceRecordBlockReserved(thread_id, block_id, trace); |
| 88 | |
| 89 | while (block_id < num_blocks) { |
| 90 | // Reserve the next block to handle. In order to hide the latency |
| 91 | // (typically comparable to an access to the level of data cache that |
| 92 | // is shared among CPU cores, e.g. 60 cycles on an ARM CPU as of 2019) |
| 93 | // of this atomic operation, we structure this code so as to avoid |
| 94 | // immediately depending on the `next_n` result. |
| 95 | const int next_block_id = |
| 96 | atomic_block_id->fetch_add(1, std::memory_order_relaxed); |
| 97 | TraceRecordBlockReserved(thread_id, next_block_id, trace); |
| 98 | // Get coordinates of the current block to handle, in "block space". |
| 99 | GetBlockByIndex(block_map, block_id, &block); |
| 100 | // Get coordinates of the current block to handle, in matrix space. |
| 101 | GetBlockMatrixCoords(block_map, block, &start, &end); |
| 102 | // Maybe pack the current LHS/RHS block, if not already packed. |
| 103 | EnsurePacked(block, start, end, tuning); |
| 104 | // Actually do matrix multiplication work |
| 105 | params->RunKernel(tuning, start, end); |
| 106 | TraceRecordBlockFinished(thread_id, block_id, trace); |
| 107 | // Move on to the next block as obtained by the atomic increment |
| 108 | // at the start of this while loop iteration. |
| 109 | block_id = next_block_id; |
| 110 | } |
| 111 | |
| 112 | local_allocator->FreeAll(); |
| 113 | |
| 114 | TraceRecordThreadEnd(thread_id, trace); |
| 115 | } |
| 116 | |
| 117 | private: |
| 118 | // Tries to pack a block, without blocking. |
nothing calls this directly
no test coverage detected