PILOT is not stealing bandwidth — it is fair-sharing a pie that sometimes cannot grow #758
terrizoaguimor
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
docs/tuning.mdsays ofPILOT: "On disk-saturated hosts hint-only PILOT can be net negative— measure on yours." I wanted to know what makes a host one of those, so I measured it instead
of reasoning about it. The answer came out to be a single device property, which is why I am
raising it here rather than sending a patch: if it holds up, the engine could decide this for
itself and the knob would not need an operator.
The thing I assumed, which was wrong
I started from the theory that speculative reads hurt demand reads disproportionately — that
prefetches starve the critical path and PILOT therefore needs admission control. That is not
what happens. One demand reader plus k speculative readers on the same NVMe, and the demand
stream gets almost exactly its fair
1/(1+k)share of whatever the device delivers at thatqueue depth:
No starvation and no queue pathology. A speculative read is just an ordinary reader.
What does decide it
One property: does the device return more total bytes when you ask for more concurrency?
Same benchmark, same block size, twice — once on the bare NVMe, once with the device capped to
300 MB/s through a cgroup v2
IOReadBandwidthMax, which is a crude stand-in for a saturated orshared disk.
That is the whole mechanism. On the scaling device the speculation costs the demand path 59%
of its throughput but the system moves 90% more bytes overall — and with the 71.6% router
recall your own docs report, most of those extra bytes are ones you were going to want. On the
capped device the demand path pays 81% and the system moves nothing extra, because there
was nothing extra to move. Same fair sharing, opposite verdict.
The idea
Not admission control, which is what I set out to build and no longer think is needed. A
startup probe: the engine already reads gigabytes of dense weights at load time. Read one
part of that at queue depth 1 and another at depth 4, compare the two rates, and let the ratio
pick PILOT's default. Devices that scale get the prefetch; devices that do not, do not. It
turns "measure on yours" into something nobody has to do by hand, and it costs nothing extra
because the reads happen anyway.
Caveats, including one that bothers me
Run-to-run variance is larger than I would like. Two passes of the same single-class
measurement, median-of-3 each, disagreed by 36% at 2 threads (11.24 vs 15.32 GB/s). The likely
cause is that the first pass ran immediately after
dd-ing the 24 GB test file, and the drivewas still doing garbage collection — which would mean that pass is depressed, so "the device
scales" is if anything understated. But I have not proven that, and it means any comparison
across passes is soft. The numbers above are all within-pass comparisons for that reason, and
the fair-share ratio is consistent across four points spanning 2 to 9 threads, which is the
main reason I believe it.
Other limits: one device class (DO premium Intel, virtio — which incidentally reports
rotational=1); synthetic 19 MB O_DIRECT reads, not the engine itself; and a cgroup cap is notthe same thing as a genuinely slow disk. I did not run
colibriend to end because I have noGLM-scale model on hand.
Everything is reproducible:
iobench.cfrom the tree for the single-class arms, a two-classvariant I wrote for the rest, fixed seeds, page cache dropped between arms, environment and
commit recorded. Happy to attach the scripts and raw output.
What I would like your opinion on
or was that a different failure — cache thrash from prefetched experts evicting warm ones,
say, rather than bandwidth?
explicit and operator-set?
need its own pass?
All reactions