v9.1.1
Menu

Multi-Stage Build Size Reduction

easyFREEContainer Images & BuildsSystems & InfrastructureML Systems & Infrastructure 1

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

Input
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}
Reasoning
  • 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: 110+4+52=166110 + 4 + 52 = 166 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: 900+15+640+4=1559900 + 15 + 640 + 4 = 1559 MB. The 110 MB runtime base is not counted here.
  • Savings: 1559−166=13931559 - 166 = 1393 MB, and 13931559×100≈89.352%\frac{1393}{1559} \times 100 \approx 89.352\%, 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_mb and reduction_pct would come out negative.

Constraints

  • 1 <= len(builder_layers) <= 50
  • 1 <= len(runtime_layers) <= 50
  • All sizes are non-negative numbers in MB
  • reduction_pct may be negative when the copied artefacts are larger than what the builder stage saved
  • Round every returned value to 2 decimal places

Learn this in

More from ML Systems & Infrastructure 1

solution.py

Test results

Sign in to run your code against the test cases.