Skip to content

Commit 1509423

Browse files
cyyevermeta-codesync[bot]
authored andcommitted
Fix DramKV race: hold rlock during inplace update writes (#5807)
Summary: Pull Request resolved: #5807 X-link: https://github.com/facebookresearch/FBGEMM/pull/2733 Previously the rlock was released after collecting hit/miss info, then block pointers were written to without the lock held. This allowed eviction to invalidate block pointers during writes. Fix by keeping the rlock held through the entire read-and-write phase using scoped lifetime. Pull Request resolved: #5536 Test Plan: Imported from GitHub, without a `Test Plan:` line. Split from D95983752 Reviewed By: r-barnes Differential Revision: D98427441 Pulled By: q10 fbshipit-source-id: f30a460b6b71c4963577135e742ef8c92c077105
1 parent f431b71 commit 1509423

1 file changed

Lines changed: 33 additions & 33 deletions

File tree

fbgemm_gpu/src/dram_kv_embedding_cache/dram_kv_inference_embedding.h

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -255,47 +255,47 @@ class DramKVInferenceEmbedding
255255
auto indices_data_ptr = indices.data_ptr<index_t>();
256256
auto weights_data_ptr = weights.data_ptr<weight_type>();
257257
{
258-
// 1st step, collect hit/miss per inplace update chunk
259258
// [tensor_offset, weight_addr]
260259
std::vector<std::tuple<int64_t, weight_type*>> hit_info;
261260
// [id, tensor_offset]
262261
std::vector<std::tuple<int64_t, int64_t>> miss_info;
263262
hit_info.reserve(indexes.size() / 2);
264263
miss_info.reserve(indexes.size() / 10);
265-
auto rlmap = kv_store_.by(shard_id).rlock();
266-
for (const auto& idx : indexes) {
267-
auto id = int64_t(indices_data_ptr[idx]);
268-
auto it = rlmap->find(id);
269-
if (it != rlmap->end()) {
270-
hit_info.emplace_back(idx, it->second);
271-
} else {
272-
miss_info.emplace_back(id, idx);
264+
{
265+
// 1st step, collect hit/miss per inplace update chunk
266+
auto rlmap = kv_store_.by(shard_id).rlock();
267+
for (const auto& idx : indexes) {
268+
auto id = int64_t(indices_data_ptr[idx]);
269+
auto it = rlmap->find(id);
270+
if (it != rlmap->end()) {
271+
hit_info.emplace_back(idx, it->second);
272+
} else {
273+
miss_info.emplace_back(id, idx);
274+
}
273275
}
274-
}
275-
rlmap.unlock();
276-
hit_cnt = hit_info.size();
277-
miss_cnt = miss_info.size();
278-
// 2nd step, no lock on update hits, it is possible that
279-
// inference read is accessing a weight being updated,
280-
// we assume it is fine for now, will iterate on it if
281-
// we find QE regress during inplace update
282-
for (auto& [tensor_offset, block] : hit_info) {
283-
auto* data_ptr =
284-
InferenceFixedBlockPool::data_ptr<weight_type>(
285-
block);
286-
std::copy(
287-
weights_data_ptr + tensor_offset * stride,
288-
weights_data_ptr + (tensor_offset + 1) * stride,
289-
data_ptr);
290-
// update provided ts for existing blocks
291-
if (feature_evict_config_.has_value() &&
292-
feature_evict_config_.value()->trigger_mode_ !=
293-
EvictTriggerMode::DISABLED &&
294-
feature_evict_ && inplace_update_ts.has_value()) {
295-
InferenceFixedBlockPool::set_timestamp(
296-
block, inplace_update_ts.value());
276+
hit_cnt = hit_info.size();
277+
miss_cnt = miss_info.size();
278+
// 2nd step, update hits while holding rlock to
279+
// prevent eviction from invalidating block pointers
280+
for (auto& [tensor_offset, block] : hit_info) {
281+
auto* data_ptr =
282+
InferenceFixedBlockPool::data_ptr<weight_type>(
283+
block);
284+
std::copy(
285+
weights_data_ptr + tensor_offset * stride,
286+
weights_data_ptr + (tensor_offset + 1) * stride,
287+
data_ptr);
288+
// update provided ts for existing blocks
289+
if (feature_evict_config_.has_value() &&
290+
feature_evict_config_.value()->trigger_mode_ !=
291+
EvictTriggerMode::DISABLED &&
292+
feature_evict_ &&
293+
inplace_update_ts.has_value()) {
294+
InferenceFixedBlockPool::set_timestamp(
295+
block, inplace_update_ts.value());
296+
}
297297
}
298-
}
298+
} // rlmap released here
299299

300300
// 3rd step, update misses in fixed block pool, we only
301301
// need mempool lock at this stage to avoid race

0 commit comments

Comments
 (0)