Skip to content

Commit eb7473b

Browse files
authored
Auto-save XNNPACK packed cache trailer at compile end
Differential Revision: D108347127 Pull Request resolved: #20295
1 parent 71cbe9f commit eb7473b

2 files changed

Lines changed: 38 additions & 11 deletions

File tree

backends/xnnpack/runtime/XNNWeightsCache.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ Result<std::vector<std::string>> XNNWeightsCache::finalize_for_runtime() {
233233
}
234234
#endif
235235

236+
// Auto-trigger save_packed_index when this compile session added new
237+
// packed entries to the file.
238+
if (!packed_cache_path_.empty() &&
239+
mmap_regions_.size() > mmap_regions_at_last_save_) {
240+
(void)save_packed_index();
241+
}
242+
236243
return packed_data_names;
237244
}
238245

@@ -600,13 +607,21 @@ Error XNNWeightsCache::save_packed_index() {
600607
}
601608

602609
mmap_regions_at_last_save_ = mmap_regions_.size();
603-
604-
// Close the fd so the next init re-enters load_packed_cache and reads
605-
// the trailer we just wrote.
606-
if (close(packed_file_fd_) != 0) {
607-
ET_LOG(Error, "close of packed cache fd failed (errno=%d)", errno);
608-
}
609-
packed_file_fd_ = -1;
610+
// Advance packed_file_used_ PAST the trailer we just wrote. Without
611+
// this, the next reserve_space (e.g. another PTE's compile inheriting
612+
// this path) would write at index_start, overwriting the trailer we
613+
// just wrote and breaking cross-process cache reuse (next launch's
614+
// load_packed_cache reads garbage at file end → invalid magic →
615+
// ftruncate(0) → all data lost). The old trailer becomes orphan dead
616+
// bytes; the new save will write a new trailer at end of the new
617+
// packs, keeping the trailer always at file end.
618+
packed_file_used_ = index_start + buf.size();
619+
620+
// Keep fd open. Subsequent finalize_for_runtime calls auto-trigger
621+
// save, which needs a live fd. Closing here would force every init to
622+
// re-enter load_packed_cache + open_locked round-trip — unnecessary
623+
// since the fd remains valid for both reads and writes through the
624+
// process lifetime.
610625
#endif
611626
return Error::Ok;
612627
}
@@ -723,9 +738,17 @@ bool XNNWeightsCache::load_packed_cache() {
723738
name_to_packed_data_metadata_[name] = meta;
724739
}
725740

726-
packed_file_used_ = index_start;
741+
// Start writing new packs AFTER the existing trailer (not at the
742+
// trailer's offset). Writing at index_start would overwrite the
743+
// valid trailer this PTE just loaded, breaking cross-process reuse
744+
// (next launch reads garbage at file end → magic invalid →
745+
// ftruncate(0) → all data lost). The old trailer becomes orphan
746+
// bytes in the middle of the file; save_packed_index writes a new
747+
// trailer at the new end including all entries (old + new).
748+
packed_file_used_ = file_size;
727749
// In-memory state matches the on-disk trailer; the next save would be
728-
// a no-op. Initialize watermark so save_packed_index short-circuits.
750+
// a no-op until new packs arrive. Initialize watermark so
751+
// save_packed_index short-circuits.
729752
mmap_regions_at_last_save_ = mmap_regions_.size();
730753
return true;
731754
#else

backends/xnnpack/test/runtime/test_xnn_weights_cache.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,13 @@ TEST_F(XNNWeightsCacheTest, PackedWeightsToMmapFile) {
330330
ASSERT_EQ(::stat(cache_path.c_str(), &st), 0);
331331
ASSERT_GT(st.st_size, 0);
332332

333-
// delete_packed_data should release the mmap region without crashing.
333+
// delete_packed_data on entries that have been persisted to disk
334+
// (from_load=true after the auto-save in finalize_for_runtime) is a
335+
// ref_count decrement, not a metadata erase. The entries remain so a
336+
// subsequent loadModel can look them up without re-packing — matches
337+
// production semantics where cache survives unload/reload.
334338
weight_cache.delete_packed_data(weight_cache.get_packed_data_names());
335-
ASSERT_EQ(weight_cache.get_packed_data_names().size(), 0);
339+
ASSERT_GT(weight_cache.get_packed_data_names().size(), 0);
336340

337341
::unlink(cache_path.c_str());
338342
}

0 commit comments

Comments
 (0)