Skip to content

Measurements

NihilDigit edited this page Sep 28, 2026 · 2 revisions

Measurements

What PikPak was measured to do, with dates. Code may change around a Fact; the fact itself stands until measured again. The probes that produced most of these are in src/jvmTest and are opt-in; see Development.

Connection limits

Fact. One signed link accepts 8 concurrent connections and answers the ninth with 503, the excess matching n − 8 exactly. Two different links get 8 each, so the cap is per link or per edge host, not per client. Measured 2026-09-02 and again 2026-09-10.

Fact. A second, wider limit applies per account, not per host.

  • 2026-09-10, a 54-file pack over 12 edge hosts: 16 concurrent connections admitted with no refusal; 32, 64 and 96 requested all settled at exactly 20 admitted. The excess was refused two ways — 503, and a TLS handshake dropped before any status line. Caveat: an earlier run without cooldown between rungs saw 16 refused, because the CDN keeps counting a connection for a while after the client drops it; with 45 s between rungs 16 passed cleanly.
  • 2026-09-26, 720P transcodes of 12 files: 8 and 16 requested were all admitted; 24, 32 and 40 requested got 11, 13 and 9, the rest answered 503. Past the limit, asking for more got fewer — overshooting costs connections rather than merely wasting requests.

Hence DEFAULT_ACCOUNT_CONNECTION_BUDGET = 16: the largest round number under the ceiling, and it splits into playback holding 8 on one file while something else holds 8 on another. The per-link cap already stops one file from taking more than half; priority decides the rest.

Throughput

Fact. Per-connection throughput is bounded by the round trip, not by a server-side rate limit. An Amsterdam host that itself reaches 100 Mbit/s delivered 200 KB/s per connection to a client in China, while a Hong Kong line saturated on one connection — same account, same files. Two independent readings land near a 64 KB window (320 KB/s × 200 ms, 200 KB/s × 250 ms): the no-window-scaling ceiling.

Consequences:

  • More connections is the only lever. Larger requests do not help, since the window is the limit; the block size is chosen for latency and memory, not throughput.
  • The connection count is not adaptive. An earlier draft derived it from the round trip, estimated from the first read's time to first byte — the least reliable sample there is (TLS handshake, cold edge) — and estimating low on a bad link is exactly the failure the fan-out exists to prevent.

Fact. On a deliberately throttled link (2026-09-11), alternating one connection against eight on the same file, three rounds: ×4.7, ×4.7, ×5.7 — mean 0.27 MB/s against 1.34 MB/s. A 2 MiB download: 7077 ms against 2228 ms, ×3.2, lower because 2 MiB is too short to amortise the detail lookup and the TLS handshake. Playback on that link: first byte of a cold open 4.18 s, steady state 2.35 MB/s, a seek to mid-file 2.79 s. Alternating matters: single-connection samples on that link ranged 0.18 to 0.95 MB/s within one run.

Fact. On a fast route (2026-09-26, through a proxy): one file over 8 connections 6.77 MB/s; the account's total stayed at 6.1–6.8 MB/s however many files shared it — the line, not PikPak, was the limit.

Edge hosts

Fact, 2026-09-26. Each link names an edge host picked per mint (dl-z01a-00xx, dl-a10b-xxxx). A healthy host answers response headers in 300–500 ms, cold ranges no slower than warm, with eight requests in flight. A host that stops answering does so for every request — a minute later the socket times out — and one that cuts transfers short does it again on retry. The first-response deadline of 2 s is four times the healthy worst case.

The 2026-09-28 measurements below ran on one Windows machine in two ways, each named where it matters: through a fake-ip TUN proxy (mihomo, Singapore exit), which re-dials every connection by its SNI, and direct on a China Telecom line in Hebei, by binding sockets to the physical interface and resolving over DNS-over-HTTPS. Both between 16:00 and 18:00 local time, outside the evening peak. MirrorProbeTest reproduces them (Development).

Fact, 2026-09-28. A link is not bound to its host. The same path and query sent to another host of the link's family returned the same bytes (SHA-256 compared on a 64 KiB range): 20 of 26 dl-z01a hosts through the proxy, 21 direct; the rest failed the TLS handshake or reset the connection (0059–0062 both ways, 0055 through the proxy only). A tampered signature got 403 on the link's own host, so the signature is checked — it just does not cover the host. A host of the other family (dl-a10b) answered 404, and several dl-a10b names presented expired or mismatched certificates. Changing only the root domain of a link's host (dl-z01a-0044.mypikpak.net) also served it: same addresses, same bytes.

Fact, 2026-09-28. Minting again does not reach the pool. Twelve mints of one 1.4 GiB file named only four hosts, the same four in two runs (dl-z01a-0014, -0042, -0044, -0046). A slow host outside that set is never escaped by re-minting, nor one inside it reliably.

Fact, 2026-09-28. Host speed depends on the route, not only the host. One connection, two passes in opposite order, 3 MiB per sample, capped at 6 s:

Most hosts dl-z01a-0053, -0054 Eight connections
Through the proxy 18 hosts at 3.2–7.2 MB/s 0.17 MB/s in both passes 8.84 MB/s on a fast host, 1.28 MB/s on 0053
Direct 0.03–0.14 MB/s the two fastest (1.38 then 0.06, 0.27 then 0.07) 0.69 MB/s on 0053, 0.30 MB/s on 0041

The two hosts slowest through the proxy were among the fastest direct. A list of good hosts written into a client would be wrong for someone; the comparison has to be made on the client's own line, which is what the reader's steering does. Single samples on the direct line swing by an order of magnitude, hence medians and a 4× margin before acting.

Fact, 2026-09-28. Steering, end to end. Eight background reads of 1 MiB, through the proxy, on a link pinned to dl-z01a-0053: with steering off, 24–56 MiB in 60 s (0.38 and 0.93 MB/s in two runs), all from 0053. With steering on, 96 MiB in 29.3 s (3.27 MB/s): 24 MiB from 0053 before moving, the rest from 0014 and 0015. With the exploration interval at 10 s instead of 5 s, 42 MiB came from the slow host first and the 96 MiB took 47 s.

Root domains

Fact, 2026-09-28. api-drive and user under mypikpak.com, mypikpak.net, pikpak.me and pikpakdrive.com all resolve (the last two through a CNAME to the apex) — to different addresses per root within one provider's range (43.160.x), while an edge host (dl-z01a-0047, dl-a10b-0861) resolves to the identical addresses under every root — and present a valid wildcard certificate for their own root. The same access token got identical quota, profile and file details under all four; a refresh-token exchange and a captcha refresh succeeded under mypikpak.net. A file detail fetched under a root hands out its link under that root. Unauthenticated, both hosts answer HTTP 401 with error_code 16 on every root. PikPak's web client lists exactly these four as its API roots.

Fact, 2026-09-28. No speed difference between roots, either way: through the proxy, per-root samples on one host ran 3.2–5.8 MB/s with no root ahead in both rounds, and probeDomain found every root's warm request at 84–95 ms; direct, every root ran 0.02–0.07 MB/s. A difference would have to come from something on the path treating names or those addresses differently — plausible at the evening peak, not measured.

API addresses

Fact, 2026-09-28. A community list of twelve addresses for api-drive and user, measured direct with the SNI of each host. Every address that answered presented a valid *.mypikpak.com certificate, but that was not enough: 8.222.208.40 served user and answered 404 for api-drive — another service behind the same certificate — and 149.129.129.1 and 149.129.132.58 did not accept a connection. Authenticated about, median of five fresh connections: 43.160.168.77, the address DNS returned, 90 ms connect, 371 ms connect and TLS, 481 ms total; the best listed address, 8.210.96.68, 55, 266 and 455 ms; the rest 673 ms to 4.6 s. Through the proxy the question has no answer: the proxy re-dials by SNI, so a connection to 1.1.1.1 with PikPak's SNI came back with PikPak's certificate.

The region check

Fact, 2026-09-28. https://access.<root>/access_controller/v1/area_accessible answers accessible: true with the country for an address it accepts, and for one in mainland China accessible: false with a prompt ("PikPak is currently unable to provide services to users in Mainland China…"). PikPak's web client asks it on every route change, for all four roots at once, and shows its block page unless one answers accessible — or all fail, or none answers within five seconds, in which case it lets the user in. It is only that: from the direct line, which it reports as mainland China, the authenticated drive and user APIs, file details, captcha/init and ranged CDN reads all answered normally, with no region error anywhere. Password sign-in and a refresh-token exchange from such an address were not tried.

Latency of API calls

  • A file detail (getFile): about 180 ms. A rebuild from the gcid (create, then detail): about 380 ms.
  • resolveMagnet: 150–314 ms; learning that PikPak does not know a magnet: 146 ms.
  • instantCreate: about 200 ms.
  • Magnet in, first CDN byte out: 1.0–1.2 s. An offline download of content PikPak already holds: 5–10 s.

Listing lag

Fact, 2026-09-27. A folder listing trails the mutation that changed it. A restored folder took 0.8 s to be listed again; a trash, a move, a rename, a create or a delete showed after 0.1–0.4 s. A listing read immediately after the call can still show the old state, and the live tests poll for it.

Background requests and playback

Fact. On a saturated 50 Mbit/s line across eight connections, background requests of 1 MiB made playback wait up to three seconds for a slot; 512 KiB requests brought the worst wait under one. Priority cannot take back a slot, so request size is what bounds the wait — hence single blocks for a throttled background file.

Open: the cold open

4.18 s to first byte on the throttled link against a 2.35 MB/s steady state, and 2.79 s for a seek. Roughly one detail round trip, a TLS handshake, then 256 KiB at single-connection speed. In descending order of what they are worth:

  • Warming the link at the call site (handle.prewarm(), or a link passed in from a detail already fetched) removes the detail round trip — the largest part, and it needs no code in the SDK.
  • A smaller first block. Not expressible as "make the first block small": a slot is offset / blockSize and the cache is keyed on it. What would work is a smaller block with more blocks per fetch once settled — a fetch already spans contiguous blocks in one request, so 64 KiB × 4 is the same request as 256 KiB × 1 while a cold 64 KiB is four times quicker to first byte. It costs four times the slots, and the cache's headroom check has to use the new maximum.
  • The rest of that seek. A seek needs no detail lookup and should reuse a connection, so the arithmetic above explains about a second of it. Nobody has instrumented the gap; do that before touching the block size.

Clone this wiki locally