---
title: 'Delay and Throughput'
source: 'https://academia.sh/en/courses/network-models/delay-and-throughput'
course: 'Network Models and Protocols'
language: en
updated: '2026-08-17T18:07:12+00:00'
license: 'CC BY-SA 4.0'
---

# Delay and Throughput

The four components of delay, the bandwidth-delay product, window sizing, and breaking down a transfer's duration into its components.

The previous two lessons showed how transport protocols limit throughput: window, loss
rate, congestion behavior. Beneath these limits lies a more fundamental layer — putting a
bit on the wire takes time, and the signal travels at a finite speed.

This lesson's question is what the sentence "my connection is 100 Mb/s" says, and does not
say, about a transfer's duration. The answer, in most cases, differs from what is
expected: what determines the duration is most often not bandwidth.

## The Four Components of Delay

A packet crossing a link consists of four components.

**Transmission delay** is the time it takes to put all of a packet's bits on the wire. It
is the ratio of packet size to link rate:

$$
d_{\text{transmission}} = \frac{L}{R}
$$

```python
for rate in (10e6, 100e6, 1e9, 10e9):
    print(f"{rate/1e6:8.0f} Mb/s -> {1500*8/rate*1e6:8.2f} us")
```

```
      10 Mb/s ->  1200.00 us
     100 Mb/s ->   120.00 us
    1000 Mb/s ->    12.00 us
   10000 Mb/s ->     1.20 us
```

**Propagation delay** is the time it takes for the signal to cross the distance. It is the
ratio of distance to the medium's propagation speed, and it is **independent** of packet
size. Inside fiber, the speed is approximately $2 \times 10^8$ m/s.

```python
for km in (1, 100, 1000, 10000):
    print(f"{km:6d} km -> {km*1000/2e8*1000:8.3f} ms")
```

```
     1 km ->    0.005 ms
   100 km ->    0.500 ms
  1000 km ->    5.000 ms
 10000 km ->   50.000 ms
```

**Queuing delay** is the packet waiting its turn at the router. It is the only variable
component: it grows as load increases and rises sharply as capacity is approached. The
effect of bufferbloat on delay shows up in this component.

**Processing delay** is the time it takes to read the header and make the routing
decision; it stays small next to the others.

The scale difference between two components is decisive. On a 1 Gb/s link, transmitting a
1500-byte packet takes 12 microseconds, while the same packet traveling a thousand
kilometers takes 5 milliseconds — four hundred times as long. **Over long distances, what
determines the duration is not bandwidth but the speed of light.** Increasing bandwidth
shortens transmission delay; it cannot touch propagation delay.

## Round-Trip Time

**Round-trip time (RTT)** is the total time it takes for a packet to reach its destination
and for the response to return. It is the sum of all components in both directions.

The measured value cannot fall below the geographic distance between the two ends. A
thousand-kilometer path requires at least 10 ms of propagation delay round trip;
intermediate routers and queues add to that. A measured value falling below this lower
bound shows that the destination is not where it is assumed to be.

RTT is the unit of measure for every mechanism in the transport layer: the handshake takes
one RTT, a window update takes one RTT, and every increase of the congestion window takes
one RTT.

## Bandwidth-Delay Product

The **bandwidth-delay product (BDP)** is the amount of data that can be "in flight" on the
path at the same time:

$$
\text{BDP} = R \times \text{RTT}
$$

The measure comes from thinking of the path as a pipe: bandwidth is the pipe's
cross-section, round-trip time is its length; the product is the pipe's volume.

```python
for mbps, rtt in ((100, 0.040), (100, 0.100), (1000, 0.040), (1000, 0.100)):
    bdp = mbps*1e6*rtt/8
    print(f"{mbps:5d} Mb/s x {rtt*1000:5.0f} ms = {bdp:12.0f} bytes = "
          f"{bdp/1024:9.2f} KiB = {bdp/1460:8.1f} MSS")
```

```
  100 Mb/s x    40 ms =       500000 bytes =    488.28 KiB =    342.5 MSS
  100 Mb/s x   100 ms =      1250000 bytes =   1220.70 KiB =    856.2 MSS
 1000 Mb/s x    40 ms =      5000000 bytes =   4882.81 KiB =   3424.7 MSS
 1000 Mb/s x   100 ms =     12500000 bytes =  12207.03 KiB =   8561.6 MSS
```

BDP has a direct consequence: **if the window is smaller than the BDP, the connection sits
idle.** The sender fills the window, waits for acknowledgement, and sends nothing during
that time. Throughput is limited by the relationship established in the TCP lesson.

The required window size and window scale follow directly:

| Target throughput | RTT | Required window | Required scale |
|---|---|---|---|
| 100 Mb/s | 40 ms | 488.3 KiB | 3 |
| 500 Mb/s | 100 ms | 6103.5 KiB | 7 |

The largest window without scaling is 65,535 bytes; both rows exceed it. On high-capacity
paths, the window scale option is not an optimization — it is a necessity.

## Components of a Transfer

Suppose the client on the example network fetches a 2 MiB resource from `198.51.100.20`.
The external link is 100 Mb/s, the round-trip time to the server is 40 ms, MSS is 1460
bytes, and the initial congestion window is 10 MSS.

```python
MSS = 1460
SIZE = 2 * 1024 * 1024
RATE = 100e6
RTT = 0.040
bdp_mss = RATE * RTT / 8 / MSS

cwnd = 10
sent = 0
round_ = 0
while sent < SIZE and cwnd < bdp_mss:
    round_ += 1
    this_round = cwnd * MSS
    sent += this_round
    print(f"round {round_}: cwnd={cwnd:4d} MSS, {this_round:7d} bytes this round, "
          f"total {sent:8d} bytes")
    cwnd *= 2

remaining = SIZE - sent
total = RTT + round_ * RTT + remaining * 8 / RATE
print(f"handshake {RTT*1000:.0f} ms + slow start {round_*RTT*1000:.0f} ms + "
      f"remaining {remaining*8/RATE*1000:.1f} ms = {total*1000:.0f} ms")
print(f"pure transmission time would be: {SIZE*8/RATE*1000:.0f} ms")
print(f"achieved average throughput: {SIZE*8/total/1e6:.1f} Mb/s")
```

```
round 1: cwnd=  10 MSS,   14600 bytes this round, total    14600 bytes
round 2: cwnd=  20 MSS,   29200 bytes this round, total    43800 bytes
round 3: cwnd=  40 MSS,   58400 bytes this round, total   102200 bytes
round 4: cwnd=  80 MSS,  116800 bytes this round, total   219000 bytes
round 5: cwnd= 160 MSS,  233600 bytes this round, total   452600 bytes
round 6: cwnd= 320 MSS,  467200 bytes this round, total   919800 bytes
handshake 40 ms + slow start 240 ms + remaining 94.2 ms = 374 ms
pure transmission time would be: 168 ms
achieved average throughput: 44.8 Mb/s
```

The result is worth reading closely. Pure transmission would take 168 ms; the actual
duration is 374 ms. The entire difference comes from delay: one round for the handshake,
six rounds of window growth. Average throughput ends up below half the connection's
capacity.

This is a model calculation; loss, name resolution, and the secure transport handshake are
not accounted for. Each of them adds at least one more round. What the model shows is not
the absolute duration but **the proportion between the components**.

## What Determines Small Transfers

As a transfer gets smaller, delay's share grows.

```python
RATE = 100e6            # same connection as the previous example
RTT = 0.040

small = 20 * 1024
print(f"pure transmission: {small*8/RATE*1000:.2f} ms; "
      f"handshake+first response: {2*RTT*1000:.0f} ms")
print(f"delay's share: {2*RTT/(2*RTT + small*8/RATE)*100:.1f} %")
```

```
pure transmission: 1.64 ms; handshake+first response: 80 ms
delay's share: 98.0 %
```

For a 20 KiB resource, 98% of the duration passes in waiting. Doubling bandwidth brings
1.64 ms down to 0.82 ms and makes no noticeable difference to the total; halving
round-trip time, on the other hand, cuts the total duration almost in half.

This asymmetry is the rationale behind many design decisions: keeping content
geographically close to the user, reducing the number of rounds, reusing connections. All
of them target delay, not bandwidth.

## Throughput and Bandwidth Are Not the Same Thing

Three terms need to be kept separate.

| Term | Definition | Measured? |
|---|---|---|
| Bandwidth | The connection's theoretical upper bound | Usually stated |
| Throughput | The rate actually achieved on a given flow | Measured |
| Goodput | The rate of useful data reaching the application | Header overhead and retransmission subtracted |

The difference among the three draws on every mechanism built throughout this course:
header overhead, retransmission, window limits, congestion behavior, fragmentation.

When a transfer is said to be slow, the questions to ask, in order, are these. Is the
bottleneck the receive window or the congestion window? What is the loss rate? Is the
round-trip time above what is expected? Is path MTU discovery working? The answer to every
question was established in one of this course's lessons.

## Summary

- Delay consists of four components: transmission, propagation, queuing, and processing.
  Only transmission delay depends on bandwidth.
- Over long distances, propagation determines the duration: at 1 Gb/s, transmitting a
  1500-byte packet takes 12 µs, while its propagation over a thousand kilometers takes
  5 ms.
- The bandwidth-delay product is the amount of data that can be in flight on the path at
  the same time; if the window is smaller than this, the connection sits idle.
- For 100 Mb/s and 40 ms, the BDP is 488 KiB; since the largest window without scaling is
  64 KiB, the window scale option is mandatory.
- For a 2 MiB transfer, pure transmission takes 168 ms; with the handshake and slow start
  included, it takes 374 ms; average throughput ends up below half of capacity.
- In small transfers, almost the entire duration is waiting; increasing bandwidth makes no
  difference, shortening round-trip time does.

## Course Wrap-Up

This course ran on a single example: an organization's network holding the
`192.168.10.0/24` block, and a packet sent to the outside world by the client at
`192.168.10.196` on that network.

Layered Models defined which problems the packet solves, and in what order, and gave a way
to place a fault at the correct layer. Encapsulation showed the layer-by-layer wrapping of
data and the cost of that wrapping.

The Link and Network Layer topic built the address plan. Where equal-size subnetting
required 640 addresses, variable-length subnetting did the same job with 244; the plan
turned into leasing pools and a translation table for external egress. When the same
network was readdressed with IPv6, address counting was not done at all — the
disappearance of scarcity had changed the planning work itself.

The Transport Layer topic showed that this packet is part of a flow. The four-tuple named
the flow; TCP kept its reliability promise with sequence numbers, retransmission, and
windows; congestion control estimated an invisible capacity through measurement and
adaptation; UDP showed in which cases these promises are unnecessary. The final lesson
separated out the physical limits underlying all of these mechanisms.

The course's outcomes converge: placing a problem at the correct layer, designing and
testing an address plan, and choosing a transport protocol based on an application's
requirements. All three rest on the same habit — tracing a behavior back to the mechanism
that produces it.

The next course, Application Layer Protocols, covers the protocols that run on top of the
transport abstraction built here: the design differences among HTTP versions and their
relationship to head-of-line blocking, the extra rounds of the secure transport handshake
and the verification of the certificate chain, and protocol selection for real-time
communication. The delay budget computed in this course will be the yardstick for every
design decision made there.
