TCP Acks
Delays in acks would reduce throughput if the round-trip delay is longer than the TCP window size. Modern TCP stacks tend to use a large window size; you can see with wireshark/tcpdump what window size has been negotiated (including the window scaling factor).
For example, on a test from macOS to TBB speedtest:
| Text |
1
2 | 08:35:01.591036 IP 10.12.255.240.64115 > 80.249.106.133.443: Flags [S], seq 3179489571, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1257357607 ecr 0,sackOK,eol], length 0
08:35:01.602209 IP 80.249.106.133.443 > 10.12.255.240.64115: Flags [S.], seq 863049753, ack 3179489572, win 14480, options [mss 1460,sackOK,TS val 3404316022 ecr 1257357607,nop,wscale 7], length 0 |
Window size in the return direction is 14480 * 2^7 = 1853440 bytes; that translates into about 50ms at 300Mbps. Packet loss can also reduce throughput, because dropped packets reduce the separate congestion window.
If there are multiple TCP streams running concurrently, then each one has its own window. Speedtest.net offers me a larger window (28960 * 2^7); and it also runs six TCP streams concurrently as opposed to TBB's one, to reduce the visible affects of packet loss. In other words, it's tuned to make your ISP look good!
It's also possible that the home router is the bottleneck, as it's doing all that forwarding and NAT.