Skip to content

Commit 399af4f

Browse files
msluszniakbarhanc
authored andcommitted
fix(fetcher): stop reporting progress before file sizes are known (#1415)
## Description Progress jumped to a large value in the first second of a download and then froze there. An LLM config fetches a model plus its tokenizer files. HEAD lookups are started but deliberately not awaited, so every uncached file begins at size 0 and falls back to an equal weight. The tokenizer finishes long before the model's HEAD returns, so its completion reported a big share of the job, and the monotonic guard held the bar there until the model genuinely caught up. Wait for every length lookup to settle before reporting a ratio over them. A lookup that comes back empty still counts as settled, so a failed HEAD cannot stall the other files, and the fallback weight is now recomputed per report so a file measured mid-flight stops counting as an estimate. Stacked on #1414. ### Introduces a breaking change? - [ ] Yes - [x] No ### Type of change - [x] Bug fix (change which fixes an issue) - [ ] New feature (change which adds functionality) - [ ] Documentation update (improves or adds clarity to existing documentation) - [ ] Other (chores, tests, code style improvements etc.) ### Tested on - [ ] iOS - [x] Android ### Testing instructions 1. Build `apps/nlp` or similar and open it. 2. Download any LLM model. 3. The bar stays near 0 while the lengths resolve, then climbs. Before this it jumped to roughly 50 percent immediately and sat there. ### Related issues Found while testing the example apps from #1414 on a Galaxy S26 Ultra. ### Checklist - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [x] My changes generate no new warnings
1 parent 5ac8202 commit 399af4f

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

  • packages/react-native-executorch/src/fetcher

packages/react-native-executorch/src/fetcher/fetcher.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -902,12 +902,23 @@ export async function download<T>(source: T, options: DownloadOptions = {}): Pro
902902
// that is corrected the moment its transfer reports a real length.
903903
const weights = measured.map((m) => m.size);
904904
const fractions: number[] = measured.map((m) => (m.cached ? 1 : 0));
905-
const known = weights.filter((weight) => weight > 0);
906-
const fallbackWeight = known.length ? known.reduce((a, b) => a + b, 0) / known.length : 1;
905+
// A length lookup still in flight is not the same as one that failed. While
906+
// any is outstanding every unmeasured file weighs the fallback, so the first
907+
// small file to finish reads as a large share of the job: a tokenizer landing
908+
// before a 3 GB model's HEAD comes back reported half the download complete,
909+
// and the monotonic guard below then pinned the bar there until the model
910+
// genuinely caught up. Say nothing until the sizes are actually in.
911+
const settled = measured.map((m) => !m.pending);
907912

908913
let reported = 0;
909914
const report = () => {
910915
if (!options.onProgress) return;
916+
if (!settled.every(Boolean)) return;
917+
// Recomputed per report rather than once: a file measured mid-flight has to
918+
// stop counting as the fallback, and only files that stayed unmeasurable
919+
// keep it.
920+
const known = weights.filter((weight) => weight > 0);
921+
const fallbackWeight = known.length ? known.reduce((a, b) => a + b, 0) / known.length : 1;
911922
let done = 0;
912923
let total = 0;
913924
for (let i = 0; i < weights.length; i++) {
@@ -929,10 +940,12 @@ export async function download<T>(source: T, options: DownloadOptions = {}): Pro
929940
// the HEAD, for a file whose download has not started yet.
930941
measured.forEach((m, i) => {
931942
m.pending?.then((size) => {
932-
if (size > 0 && weights[i] === 0) {
933-
weights[i] = size;
934-
report();
935-
}
943+
if (size > 0 && weights[i] === 0) weights[i] = size;
944+
// Settles either way: a HEAD that came back empty has still answered, and
945+
// holding every other file's progress hostage to it would be worse than
946+
// weighting this one by the fallback.
947+
settled[i] = true;
948+
report();
936949
});
937950
});
938951

0 commit comments

Comments
 (0)