Repository navigation
iPad Safari: WebGPU inference drops 3x after ~10 s of sustained load; batching frames fixed it #33453
Unanswered
Tane van der Boon (pullmyleg)
asked this question in
Web Q&A
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.
I was testing a small real-time object detector in Safari on an iPad (A16, iPadOS 26.6) at home with
onnxruntime-web 1.30 and the WebGPU EP, and hit a pattern that took a while to pin down. Posting the
measurements and the fix in case it saves someone else the detour.
Setup: a ~5 MB fp16 YOLO-style detector (static 640x640 input, 1x84x8400 output, a couple of hundred
kernels), run in a Worker on a fixed image so the camera was out of the picture.
Symptom: 57 ms per run (14 fps) for the first 10 s, then a hard step to 185 ms (4.7 fps) that stays
for as long as you keep running. A 30 s pause restores 57 ms; it then degrades again after another
10 s. Recreating the session or the worker restores it only for a few seconds.
What it is not (each tested on the device, 2 minutes per run):
onnxruntime-web/webgpu(asyncify),/jspi(iPadOS 26.6 has JSPI) and theJSEP bundle all show the same step. The JSEP bundle is just slower from the start (138 ms).
(
Tensor.fromGpuBuffer,preferredOutputLocation: 'gpu-buffer') withenableGraphCapturegave thesame 54 ms and the same step.
So it looks like the SoC moving the GPU to a low-power state once the CPU plus GPU load from the
inference loop stays high for about 10 s. Single-frame runs were sustainable only up to 8 a second
(9 tripped after 30 s, 10 and 15 after 10 s).
The fix: because the per-run cost barely depends on how many pixels you feed it, I exported the
model with a static batch of 4 and run four captured frames per session.run. On the iPad that costs
198 ms per run, so 4 runs a second gives 15 frames a second, held flat for 5 minutes. At 480 input
batch 4 gives 18 frames a second. Result latency is up to ~0.4 s after capture, which is fine for
tracking. Mac Chrome for comparison: 20 ms for 1 frame, 46 ms for 4.
Practical notes:
session.inputMetadata[0].shape[0]rather than config so the model andthe pump cannot disagree.
queue.copyExternalImageToTexturefrom an ImageBitmap and a smallcompute shader writes the letterboxed CHW fp16 planes (
pack2x16float) into one buffer that iswrapped with
Tensor.fromGpuBufferonce and reused.process to background priority and a JS worker slows 9x, which looks exactly like the iPad problem
and is not.
Happy to share more numbers if useful.
All reactions