4.5.10 · D2Software Engineering

Visual walkthrough — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

2,137 words10 min readBack to topic

This is a companion to the parent topic and leans on Amdahl's Law at the finish.


Step 1 — What is a "job" and what is "time"?

WHAT. A pipeline stage is made of small tasks. We call each task a job. Think of a job as a single chore: "run the unit tests for folder A". In our pictures each job is one box.

WHY start here. Every symbol we use later counts boxes or measures how long a box takes. If we don't nail down "box = job" and "how long one box takes", nothing after it means anything.

PICTURE. Below, one job is drawn as a rectangle. Its width is its running time — we give this width the name (read "tee"), measured in minutes. Here minutes: the box is 3 units wide.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 2 — Many jobs, and the meaning of

WHAT. A real test stage has many jobs — say we split our tests into 8 pieces (called "shards"). We name the count of jobs with the letter . Here .

WHY this symbol. We need one short name for "how many boxes there are", because the answer to "how long does the stage take?" depends entirely on this count and on how many we can run at once.

PICTURE. Eight boxes, each of width . Notice they are not yet placed in time — we've only counted them. The count is what captures.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 3 — The slowest possible plan: one at a time (serial)

WHAT. Suppose we own exactly one runner — one worker machine. It can hold only one box at a time, so it runs job 1, then job 2, then job 3… laying the boxes end to end along the time axis.

WHY show the worst case first. It's the easiest to reason about and gives us a ceiling to beat. When boxes sit end to end, total time is just the sum of the widths.

PICTURE. Eight boxes in a single row along "time →". The total length is the sum of all widths — that's the wall-clock time.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 4 — Adding runners: the meaning of and the "waves"

WHAT. Now buy more workers. The number of runners — how many boxes can run at the same moment — gets the name . With runners, four boxes run side by side. When those four finish, the next four start. Each simultaneous group is a wave.

WHY this picture. Independent jobs (Step 1) have no reason to wait for each other — the only thing stopping all 8 from running at once is that we only have machines. So the machines, not the work, set the pace. Stacking boxes into columns of height makes this visible.

PICTURE. Two columns ("waves") of 4 boxes each. Height of a column = jobs running together. The stage ends when the last wave ends, so total time = (number of waves) × .

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 5 — Counting the waves: where comes from

WHAT. How many waves do we need? Divide the boxes into groups of . With jobs and per wave, that's waves — clean. But what if it doesn't divide evenly?

WHY the ceiling. If and , then . You cannot run "a quarter of a wave" — a leftover job still needs a whole wave to itself. So we always round up to the next whole number. That round-up operation has a symbol: , the ceiling (imagine the number bumping its head on a ceiling and stopping at the next whole floor above).

PICTURE. Left: → 2 full waves. Right: → a lonely 9th box forces a third wave that is mostly empty. The empty slots are wasted runner-time, but the wave still costs .

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 6 — Assembling the parallel-time formula

WHAT. Total time = (how many waves) × (cost of one wave). Cost of one wave is (Step 1). Number of waves is (Step 5). Multiply them.

WHY this is the whole answer. Because waves happen one after another (each waits for the previous group of machines to free up), their times add; and every wave has the same length , so adding them is just multiplying.

PICTURE. The finished timeline for : two stacked columns, total width min. The dashed line marks .

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 7 — Edge case: more runners than jobs ()

WHAT. What if we buy 12 runners but only have 8 jobs? Then all 8 fit in one wave and the 4 extra machines sit idle.

WHY it matters (the cap). . One wave, cost . Buying runner number 9, 10, 11, 12 changed nothing — the timeline was already as short as one job. This is the visual root of the parent note's warning "more runners is not always faster", and it is exactly Amdahl's Law: you cannot go faster than your longest single unfinished piece of work.

PICTURE. One wave of 8 filled boxes plus 4 greyed-out idle runners. The timeline is stuck at width no matter how many idle machines you add.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

Step 8 — Degenerate case: dependent jobs break the picture

WHAT. All the above assumed jobs are independent (Step 1). Suppose instead job B needs job A's output (in GitLab this is needs:, a DAG edge). Then A and B cannot share a wave — B must wait for A even if 100 runners are free.

WHY it breaks the formula. Our multiplication assumed the only limit was runner count. A dependency adds a second limit: an ordering. A chain of dependent jobs takes at least no matter what is — this chain is the "serial fraction" Amdahl's Law charges you for.

PICTURE. Two rows: top = 4 independent jobs finishing in one wave; bottom = 4 jobs in a dependency chain A→B→C→D, forced into 4 sequential slots. Same number of jobs, four times the time.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts

The one-picture summary

WHAT. Everything at once: the same 8 jobs shown three ways — serial (1 runner, 24 min), parallel (4 runners, 6 min), and over-provisioned (12 runners, still 6 min) — with a dependency chain shown as the immovable floor.

Figure — CI - CD — pipeline stages, GitHub Actions - GitLab CI concepts
Recall Feynman: tell it to a 12-year-old

You have 8 identical chores, each takes 3 minutes. If one friend does them all, that's the long line: 8 chores × 3 = 24 minutes. If four friends help, they do 4 chores at once (one "wave"), then 4 more — two waves, 3 minutes each = 6 minutes. To count waves you split the chores into groups of "how many friends", and if a leftover chore is stranded, it still needs its own whole wave — so you always round the wave count up. Adding a fifth, sixth… twelfth friend when you only have 8 chores does nothing: with everyone busy in one wave you're already at 3 minutes and can't go lower. And if chore B can't start until chore A is done — a chain — then friends don't help at all along that chain; those chores must wait in line no matter how many hands you have. That single unavoidable line is why speedup has a ceiling.

Recall The whole derivation in one breath

One job takes ::: yes — its width in the picture. jobs run serially in ::: (boxes end to end). With runners the count of waves is ::: (round up, leftover needs a full wave). So the parallel time is ::: . Speedup ::: , capped at when . A chain of dependent jobs costs at least ::: , independent of (Amdahl's floor).


Connections

  • Parent topic (Hinglish) — the formula this page derives.
  • Amdahl's Law — the serial-fraction ceiling made visual in Steps 7–8.
  • Automated Testing — Unit vs Integration vs E2E — test shards are the classic independent jobs.
  • DevOps Principles & Shift-Left — why we bother shrinking wall-clock time at all.