iPerf

iPerf3 Parallel Streams and TCP Window Size (-P and -w)

Why fast links benchmark slow: bandwidth-delay product, a real 78% throughput collapse from a 64K window at 104 ms RTT, and how parallel streams buy it back.
iPerf3 parallel streams and TCP window feature image with window collapse capture
In: iPerf, Networking

Two iPerf3 flags separate people who run throughput tests from people who understand them: -P (parallel streams) and -w (TCP window size). Together they explain the most common head-scratcher in network testing - a fast link that benchmarks slow the moment latency enters the picture. We reproduced that exact failure on a live Cisco Modeling Labs topology with 100 ms of injected round-trip time, so every number below is real. This article is part of our complete iPerf guide.

The Bandwidth-Delay Product, Quickly

TCP can only keep a window's worth of unacknowledged data in flight. Once the window is full, the sender stops and waits for ACKs, and ACKs take a round trip. So the ceiling on any single TCP flow is:

max throughput = window size / round-trip time

Flip it around and you get the bandwidth-delay product (BDP), the window you need to fill a given path:

BDP = bandwidth x RTT
35 Mbit/sec x 0.104 sec = ~3.6 Mbit = ~455 KB

Our lab path carries about 35 Mbit/sec with 104 ms RTT, so a single flow needs roughly 455 KB of window to fill it. Hold that number; you are about to watch what happens when TCP has far less.

The Experiment: Same Path, Three Windows

First, the path with negligible latency (RTT around 3.6 ms). A default iPerf3 run lands at 34.6 Mbit/sec - the path's natural ceiling. Then we added 50 ms of one-way delay on the WAN link (104 ms RTT, confirmed by ping) and ran three tests.

Default window, 104 ms RTT

client:~$ iperf3 -c 10.0.20.10
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  5.00 MBytes  41.9 Mbits/sec    5    539 KBytes
[  5]   3.00-4.00   sec  2.75 MBytes  23.1 Mbits/sec    0    318 KBytes
[  5]   6.00-7.00   sec  2.75 MBytes  23.0 Mbits/sec    0    321 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5]   0.00-10.00  sec  31.4 MBytes  26.3 Mbits/sec   39            sender
[  5]   0.00-10.11  sec  27.8 MBytes  23.0 Mbits/sec                  receiver

Linux autotuning grows the window past 300 KB and recovers most of the throughput: 26.3 Mbit/sec. Not bad. Watch the Cwnd column doing exactly what the BDP math predicts it must.

Forced 64 KB window, same path

client:~$ iperf3 -c 10.0.20.10 -w 64K
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   640 KBytes  5.24 Mbits/sec    0    161 KBytes
[  5]   4.00-5.00   sec   768 KBytes  6.29 Mbits/sec    0    112 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[  5]   0.00-10.00  sec  6.88 MBytes  5.77 Mbits/sec   11            sender
[  5]   0.00-10.10  sec  6.88 MBytes  5.71 Mbits/sec                  receiver

Same link, same routers, same everything - 5.77 Mbit/sec. The math checks out almost exactly: 64 KB per 104 ms round trip is about 5 Mbit/sec. Nothing is broken. TCP is simply spending most of its time waiting for ACKs. This is what legacy applications with small fixed socket buffers experience on every long-haul path, and it is why "the link is 1 Gbps but the transfer runs at 50 Mbps" is usually not a network problem at all.

Same tiny window, four parallel streams

client:~$ iperf3 -c 10.0.20.10 -w 64K -P 4
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  7.00 MBytes  5.87 Mbits/sec    0            sender
[  7]   0.00-10.00  sec  4.50 MBytes  3.77 Mbits/sec    4            sender
[  9]   0.00-10.00  sec  6.88 MBytes  5.77 Mbits/sec    1            sender
[ 11]   0.00-10.00  sec  6.88 MBytes  5.77 Mbits/sec    1            sender
[SUM]   0.00-10.00  sec  25.2 MBytes  21.2 Mbits/sec    6             sender
[SUM]   0.00-10.11  sec  25.2 MBytes  21.0 Mbits/sec                  receiver

Each stream is still window-starved at roughly 5 Mbit/sec, but four of them together deliver 21.2 Mbit/sec. Parallel streams multiply the effective in-flight data - four windows instead of one. This is exactly why browsers open multiple connections and why backup tools have a "streams" setting.

What the Comparison Tells You

Default window

26.3 Mbit/sec. Modern autotuning handles moderate BDPs on its own. If your OS is current and buffers are not capped, you rarely need -w.

-w 64K

5.77 Mbit/sec. A 78% collapse from a setting, not a fault. Window / RTT is a hard ceiling no amount of bandwidth fixes.

-w 64K -P 4

21.2 Mbit/sec. Parallelism buys back what small windows lose. If -P helps a lot, suspect per-flow limits: windows, per-flow policers, or single-flow load-balancing hashes.

How to Use -P and -w Diagnostically

Run a single stream, then -P 4, and compare:

  • Single stream is slow, parallel sum is much higher: a per-flow limit. Check RTT and window sizes (BDP math above), per-flow QoS policers, or an ECMP/port-channel hash pinning one flow to one member link.
  • Single and parallel both hit the same ceiling: a shared limit - the link itself, a shaper on the path, or CPU on either endpoint. Confirm the interface rate on the router while the test runs (show interfaces and watch the output rate counters climb).
  • Parallel is worse than single: usually endpoint CPU. iPerf3 runs all streams in one thread until recent versions, so a saturated core caps the sum. Check with top during the test; iPerf2 multithreads if you need to rule this out (see iPerf2 vs iPerf3).

Two cautions with -w. First, the OS may silently cap what you request (check the "socket buffer size" line iPerf3 prints). Second, what you set with -w is a buffer size request on both ends; setting it lower than autotune would reach makes things worse, so use it to reproduce problems, not as a routine "optimization."

Key Takeaways

A single TCP flow can never exceed window divided by RTT, so know your path's BDP before judging a test. Modern autotuning usually gets close to the ceiling; small fixed windows crater throughput in exact proportion to the math, and parallel streams recover it by flying multiple windows at once. Use -P as a diagnostic fork in the road: it separates per-flow limits from shared limits in under a minute. When a path still disappoints after this analysis, packet loss is the usual suspect - pick up the trail in troubleshooting slow throughput with iPerf3, or go back to the iPerf complete guide for the full command reference.

Written by
More from Ping Labz
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Ping Labz.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.