A pass reads one file at a time where upstream reads thirteen #36
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A pass reads one file at a time. Upstream reads several: its scheduler fans out
to
Environment.ProcessorCount - 3where the setting is unset, dropping tosequential only on three cores or fewer.
On the reference machine — sixteen cores,
LibraryScanFanoutConcurrencyunset— that is thirteen at once against our one.
The server is not busy while it scans. Sampled during a pass over the film
library,
jellyfin-serversits at 0.0% CPU: every second of it is spentwaiting on one
ffprobereading one file over the mount.Measured directly, three disjoint cold sets of 24 films and two of 24 episodes,
the same arguments a pass uses:
So about 2.5x, which is the mount saturating rather than the cores.
Against the library that matters — 284 films, 7904 episodes, 4889 tracks:
Reading is where a pass spends itself and the only place fanning out pays. The
writing is already batched and bounded (#22), and a rescan that reads nothing
is already fast.
Note that #19 proposed concurrency here and was closed without it, on the
measurement that probing was not latency-bound once #14 widened the probe
window. That measurement was taken on the reference library, whose files are
small; on the real one the widened window is exactly what makes each read long
enough to be worth overlapping. The numbers above supersede it.
Upstream's own policy is the one to copy, including the sequential case: a
scan that spawns thirteen
ffprobeprocesses on a two-core machine is worsethan one that spawns one.
Fixed in
2423758.What changed
A pass reads several files at once and files what it read in the order the
library resolved it — a folder before what is under it, and a chain naming
only rows already filed. How many at once is
max(4, cores - 3), or whatlibrary_scan_fanout_concurrencyasks for, which the dashboard can now set.Not upstream's rule, and the reason is the two regimes:
So the cores are right where the parsing is the cost, and say nothing where
the waiting is. The floor is what covers the second: a machine with few cores
and its library on a share is what
ProcessorCount - 3answers worst, and onefile at a time there costs hours. Recorded as D25.
While measuring: a picture was being read whole into memory to take its width
and height, which one read at a time hid.
Measured
/mnt/media— 284 films, 7904 episodes, 4889 tracks — against the upstreaminstance's own logs for the same media:
The rows are the same either way: 14573 paths against upstream's 14572 — the
one extra is a file added since upstream last scanned — differing only on 102
Namevalues that already differed for #27. The music library scanned bothserially and fanned out gives byte-identical rows.
What the link can do is 105 MB/s, and a single reader already reaches it. So
the fanout is not buying bandwidth; it is stopping the link idling while each
probe parses what it has. That is why this is 1.5x rather than 13x, and why
more than a handful buys nothing on a mount like this one.
Note on #19
That issue proposed concurrency here and was closed without it, on a
measurement that probing was not latency-bound once #14 widened the probe
window. The measurement was taken on the reference library, whose files are
small. On a real one the widened window is what makes each read long enough to
be worth overlapping. The numbers above supersede it.