@@ -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
0 commit comments