MCPcopy Create free account
hub / github.com/DeepRec-AI/DeepRec / TryPack

Method TryPack

tensorflow/lite/experimental/ruy/trmul.cc:122–188  ·  view source on GitHub ↗

Tries to pack a block, without blocking. If the block was already packed, returns true. If the block was not started packing, packs it and returns true. If the block was being packed by another thread, returns false.

Source from the content-addressed store, hash-verified

120 // If the block was not started packing, packs it and returns true.
121 // If the block was being packed by another thread, returns false.
122 bool TryPack(Side side, int block, int start, int end, Tuning tuning) {
123 if (params->is_prepacked[side]) {
124 return true;
125 }
126 if (!local_packed[side][block]) {
127 if (need_atomics) {
128 // Explanation of this compare_exchange_strong operation:
129 // This atomically performs all of the following:
130 // 1. Read `status` with "acquire" memory order.
131 // * That this read uses "acquire" is because both memory orders
132 // specified have "acquire" as their read-component.
133 // 2. Compare (bitwise) with `exchanged_status`.
134 // 3. If equal, stores the value kInProgress to `status` with "release"
135 // memory order, and returns true, so we take this 'if' branch.
136 // * That this store uses "release" is because of the _rel part in
137 // memory_order_acq_rel passed as the first memory order argument.
138 // 4. If not equal, stores the loaded value of `status` to
139 // `exchanged_status` with "relaxed" semantics, and returns false,
140 // so we take the 'else' branch.
141 // * That this store uses "relaxed" is because the second memory
142 // order argument, memory_order_acquire, implies no particular
143 // store semantics. "relaxed" is acceptable here because this
144 // stores to a local stack variable.
145 //
146 // Rationale for compare_exchange_strong as opposed to
147 // compare_exchange_weak:
148 // The spurious-failure case with compare_exchange_weak will actually
149 // happen a lot here, because the atomic 'status' bytes are stored
150 // contiguously in arrays and neighboring values will be accessed
151 // by multiple threads concurrently. On a typical ARM CPU, an exclusives
152 // reservation granule is 64 bytes, so a lot of false-sharing may
153 // happen. Using compare_exchange_weak would thus result in often having
154 // TryPack return 'false' when it could instead have done the packing
155 // work and returned 'true'. Heuristically, that is not a good thing.
156 // Moreover, this changes the TryPack contract, loosening it and making
157 // it harder for the caller to reason about. Finally, the overhead of
158 // atomic operations is mitigated by the enclosing check on
159 // local_packed, so maybe the overhead of compare_exchange_strong isn't
160 // such a problem. But we don't really know for sure, that would be
161 // interesting to experiment more with.
162 PackingStatus exchanged_status = PackingStatus::kNotStarted;
163 std::atomic<PackingStatus>& status = packing_status[side][block];
164 if (status.compare_exchange_strong(
165 exchanged_status, PackingStatus::kInProgress,
166 std::memory_order_acq_rel, std::memory_order_acquire)) {
167 // In this branch, the status was kNotStarted and we just atomically
168 // changed it to kInProgress as we are about to handle the packing
169 // ourselves.
170 params->RunPack(side, tuning, start, end);
171 TraceRecordBlockPacked(thread_id, side, block, trace);
172 status.store(PackingStatus::kFinished, std::memory_order_release);
173 } else if (exchanged_status == PackingStatus::kInProgress) {
174 // Another thread is currently packing this block.
175 return false;
176 }
177 RUY_DCHECK(status.load(std::memory_order_acquire) ==
178 PackingStatus::kFinished);
179 } else {

Callers

nothing calls this directly

Calls 3

RunPackMethod · 0.80
TraceRecordBlockPackedFunction · 0.70
loadMethod · 0.45

Tested by

no test coverage detected