Multi-Stage Build Size Reduction
Problem Statement
A multi-stage build compiles wheels, CUDA extensions and datasets in a fat builder stage, then copies only the finished artefacts into a slim runtime stage. Everything else in the builder is discarded — it never reaches the registry. Compute how much that actually saves.
Background
The shipped image is the runtime stage: its base image, its own layers, plus whatever COPY --from=builder pulled across. The builder's compilers, caches and intermediate object files are left behind.
The single-stage baseline used here is the honest comparison: you would have done everything in one image on top of the builder's base, so you pay for every builder layer plus the runtime stage's non-base layers.
multi_stage_mb = sum(runtime_layers) + copied_mb
single_stage_mb = sum(builder_layers) + sum(runtime_layers[1:])
saved_mb = single_stage_mb - multi_stage_mb
reduction_pct = 100 * saved_mb / single_stage_mb
Note runtime_layers[1:] — the single-stage build does not carry a second base image.
Your Task
Implement:
def multi_stage_report(builder_layers, runtime_layers, copied_mb):
Return a dict with keys "multi_stage_mb", "single_stage_mb", "saved_mb" and "reduction_pct", in that order, each rounded to 2 decimal places.
Input Format
- builder_layers: list of numbers, MB added by each builder-stage layer (index 0 is the builder base image).
- runtime_layers: list of numbers, MB added by each runtime-stage layer (index 0 is the runtime base image).
- copied_mb: number, total MB copied from the builder into the runtime stage.
Output Format
- A dict with the four keys above, values rounded to 2 decimals.
Sample
print(multi_stage_report([900.0, 15.0, 640.0], [110.0, 4.0], 52.0))
Output:
{'multi_stage_mb': 166.0, 'single_stage_mb': 1559.0, 'saved_mb': 1393.0, 'reduction_pct': 89.35}
The runtime stage is 114 MB plus a 52 MB virtualenv copied from the builder, so 166 MB ships. The one-stage equivalent drags the 900 MB toolchain base and the 640 MB build cache along: 1559 MB.
Example
print(multi_stage_report([900.0, 15.0, 640.0], [110.0, 4.0], 52.0))
{'multi_stage_mb': 166.0, 'single_stage_mb': 1559.0, 'saved_mb': 1393.0, 'reduction_pct': 89.35}- Inputs:
builder_layers=[900.0, 15.0, 640.0]are the builder stage's layer sizes in MB (a 900 MB toolchain base, a 15 MB layer, a 640 MB build cache);runtime_layers=[110.0, 4.0]are the runtime stage's (a 110 MB slim base plus 4 MB);copied_mb= 52 MB of finished artefacts carried across. - What ships: only the runtime stage plus the copy: MB.
- One-stage baseline: every builder layer, plus the runtime stage's layers except its base image, since a single image has only one base: MB. The 110 MB runtime base is not counted here.
- Savings: MB, and , which rounds to 89.35 to 2 decimal places.
- Notice the saving is driven by what stays behind (the 900 MB base and 640 MB cache). If the copied artefacts were bigger than everything left behind,
saved_mbandreduction_pctwould come out negative.
Constraints
- 1 <= len(builder_layers) <= 50
- 1 <= len(runtime_layers) <= 50
- All sizes are non-negative numbers in MB
reduction_pctmay be negative when the copied artefacts are larger than what the builder stage saved- Round every returned value to 2 decimal places