DEV Community

Cover image for Why MTP Batch Transfers Slow Down Between Files
hiyoyo
hiyoyo

Posted on

Why MTP Batch Transfers Slow Down Between Files

All tests run on an 8-year-old MacBook Air.

You're transferring a batch of large files over MTP. The first one flies at 45 MB/s. Then the second file starts — and you're at 30 MB/s. The third is slower still.

Nothing changed. Same cable, same device, same app. So what's happening?


The Cause Is in the Protocol Itself

Between every file, MTP requires a full negotiation cycle — SendObjectInfo followed by SendObject. This isn't an implementation detail you can optimize away. It's how MTP works.

During that gap, a few things happen in sequence:

  • The Android device's flash controller is still committing the previous file to storage
  • The USB pipe is flushed and re-established for the next object
  • The device's MTP stack is processing metadata before it's ready to receive data again

The result is a speed dip at every file boundary. The longer the previous file, the longer the device needs to catch up.


What I Tried

Building HiyokoMTP, I went through the obvious candidates:

  • Tokio thread pool exhaustion — sync Read/Write calls blocking async threads were a real issue. Fixing it improved overall stability, but didn't eliminate the inter-file dip.
  • Chunk size tuning — adjusting the USB bulk transfer buffer (up to 4 MB per chunk) helped peak throughput, but not the boundary behavior.
  • Intentional cooldown between files — adding a short pause actually helped in some cases, giving the device's flash controller time to breathe before the next transfer starts.

Why It Can't Be Fully Fixed

The inter-file overhead is structural. MTP was designed as a stateful, command-response protocol — not a streaming pipeline. Every file is a discrete transaction with its own negotiation. There's no mechanism to pre-stage the next file while the current one is still writing.

Non-async bulk transfer pipelining (similar to io_uring or Zero Copy USB) could theoretically reduce this, but it would require deep nusb-level changes and device-side support that most Android MTP stacks don't expose.


MTP vs ADB: A Fair Comparison

It's worth comparing MTP to ADB push, since both are common transfer methods:

MTP ADB
Peak single-file speed Fast Moderate
Inter-file overhead Higher (protocol negotiation) Lower
Batch transfer efficiency Drops between files More consistent

ADB has lower overhead per file, but its raw transfer speed on large single files tends to be slower than MTP. Neither is universally better — it depends on what you're transferring.


The inter-file dip is unavoidable, but HiyokoMTP minimizes it to the extent the protocol allows. If you're hitting this wall, you're not doing anything wrong — MTP just works this way.

One-time purchase, no subscription.

https://hiyokomtp.lemonsqueezy.com/checkout/buy/2e966b64-554e-42a0-b865-4240281978a1

Have you found a way to squeeze more speed out of MTP batch transfers?

Top comments (1)

Collapse
 
hiyoyok profile image
hiyoyo

TL;DR: MTP batch transfers slow down between files because of protocol-level negotiation overhead — it's structural, not a bug, and can't be fully eliminated.