Skip to content

Report whether XNNPACK packed weights fell back to heap - #22413

Open
doggeral wants to merge 1 commit into
pytorch:mainfrom
doggeral:export-D118206001
Open

Report whether XNNPACK packed weights fell back to heap#22413
doggeral wants to merge 1 commit into
pytorch:mainfrom
doggeral:export-D118206001

Conversation

@doggeral

@doggeral doggeral commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary:
When the mmap'd packed-weight cache file cannot be used, XNNPACK packs weights
into heap and compilation succeeds anyway. Every fallback branch in
XNNWeightsCache returns Error::Ok and at most writes an ET_LOG, which
does not reach a warehouse. So in production a fallback is indistinguishable
from a model that is simply larger — the only symptom is several hundred MiB of
extra dirty anonymous memory and no error anywhere.

This diff records the outcome inside the cache and exposes it; D118207xxx (the
child) consumes it and emits QPL. Split because the two halves have different
owners.

Byte accounting, not a status flag. The first cut of this reported a
tri-state "did the file open". That hides the case that matters most: a cache
that loads successfully but is only partial, so loaded_from_disk_ routes
every subsequent named pack to heap, never persists it, and re-packs it on
every launch — permanently, per device, while still reporting FileBacked.
reserve_space has five heap exits and only two were failures. So the cache
now counts bytes per reason and reports heap_bytes against mapped_bytes;
the ratio is the signal, and packed_cache_state is kept only to separate
"feature off" from "perfect cache hit, no new packs".

Counters are atomic and read without the instance mutex. That mutex is held
across the whole of xnn_create_runtime, so a telemetry read that waited on it
could stall an inference thread for the length of a model compile. The counters
are independent accumulators with no invariant spanning them, so relaxed
atomics are sufficient and aggregate_stats() takes no per-instance lock.

Exposed read-only through the existing backend-options channel
(packed_cache_state / _errno / _heap_mib / _mapped_mib /
_heap_reason / _file_mib) rather than new API surface.

errno is deliberately how this answers "was it disk space", instead of
sampling free space.
The disk-space APIs are on Apple's Required Reason API
list and would force a PrivacyInfo declaration on every iOS consumer of this
header — the same reason load_packed_cache already uses lseek over fstat.
ENOSPC needs no such API.

One behaviour change beyond telemetry: the open(O_RDWR|O_CREAT) failure
branch previously returned Error::Ok with no log at all — the branch most
likely to fire under disk pressure was the one silent branch. It now logs at
ERR like its siblings.

Differential Revision: D118206001

Summary:
When the mmap'd packed-weight cache file cannot be used, XNNPACK packs weights
into heap and compilation succeeds anyway. Every fallback branch in
`XNNWeightsCache` returns `Error::Ok` and at most writes an `ET_LOG`, which
does not reach a warehouse. So in production a fallback is indistinguishable
from a model that is simply larger — the only symptom is several hundred MiB of
extra dirty anonymous memory and no error anywhere.

This diff records the outcome inside the cache and exposes it; D118207xxx (the
child) consumes it and emits QPL. Split because the two halves have different
owners.

**Byte accounting, not a status flag.** The first cut of this reported a
tri-state "did the file open". That hides the case that matters most: a cache
that loads successfully but is only *partial*, so `loaded_from_disk_` routes
every subsequent named pack to heap, never persists it, and re-packs it on
every launch — permanently, per device, while still reporting `FileBacked`.
`reserve_space` has five heap exits and only two were failures. So the cache
now counts bytes per reason and reports `heap_bytes` against `mapped_bytes`;
the ratio is the signal, and `packed_cache_state` is kept only to separate
"feature off" from "perfect cache hit, no new packs".

**Counters are atomic and read without the instance mutex.** That mutex is held
across the whole of `xnn_create_runtime`, so a telemetry read that waited on it
could stall an inference thread for the length of a model compile. The counters
are independent accumulators with no invariant spanning them, so relaxed
atomics are sufficient and `aggregate_stats()` takes no per-instance lock.

Exposed read-only through the existing backend-options channel
(`packed_cache_state` / `_errno` / `_heap_mib` / `_mapped_mib` /
`_heap_reason` / `_file_mib`) rather than new API surface.

**`errno` is deliberately how this answers "was it disk space", instead of
sampling free space.** The disk-space APIs are on Apple's Required Reason API
list and would force a PrivacyInfo declaration on every iOS consumer of this
header — the same reason `load_packed_cache` already uses `lseek` over `fstat`.
`ENOSPC` needs no such API.

One behaviour change beyond telemetry: the `open(O_RDWR|O_CREAT)` failure
branch previously returned `Error::Ok` with no log at all — the branch most
likely to fire under disk pressure was the one silent branch. It now logs at
ERR like its siblings.

Differential Revision: D118206001
@pytorch-bot

pytorch-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/22413

Note: Links to docs will display an error until the docs builds have been completed.

❌ 8 New Failures, 2 Unrelated Failures

As of commit 4099fe4 with merge base 0c6ecea (image):

NEW FAILURES - The following jobs have failed:

FLAKY - The following jobs failed but were likely due to flakiness present on trunk:

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 1, 2026
@meta-codesync

meta-codesync Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

@doggeral has exported this pull request. If you are a Meta employee, you can view the originating Diff in D118206001.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant