Skip to content
About
Main content

Checkpoint interval optimum

Simulate a modelNeeds Python

Problem

A long job so that a failure loses only the work since the last checkpoint. Each checkpoint costs C; between checkpoints the expected loss on failure is half the interval. The wasted fraction is therefore about C/I + I/(2·), which is minimal at I* = √(2·C·MTBF). The two terms trade off smoothly, so the curve is flat near its minimum: a moderately wrong interval costs little.

Find the minimum of C/I + I/(2·MTBF) and test the "flat near the minimum" claim. Simulate a job that runs for 30 days of simulated time. Failures arrive as a Poisson process with MTBF = 1 day. A checkpoint costs C = 30 s. Sweep I from 2 minutes to 6 hours and measure the fraction of time that is not useful work. Then repeat with MTBF = 4 days while keeping the interval tuned for 1 day.

The question. Where is the minimum waste, how close does the simulation come to the formula, and how much does a 4× wrong MTBF cost?


Predict

The interval was tuned for a one-day MTBF, but the real MTBF is four days. How much does that cost?

Run it

  1. 1Install uv once. It fetches Python and the lab's packages for you.

    Terminal
    curl -LsSf https://astral.sh/uv/install.sh | sh
  2. 2Get the script. It is the whole lab: read it, then download it.

    checkpoint-interval-optimum.py62 linesDownload
    View the code
    checkpoint-interval-optimum.py
    # /// script
    # requires-python = ">=3.10"
    # dependencies = ["numpy"]
    # ///
    # Copyright (c) 2026 Aayush Sharma · SPDX-License-Identifier: MIT
    # https://thedataengineering.com/lab-code/LICENSE.txt
    """The checkpoint interval optimum.
    
    A 30-day job with Poisson failures (MTBF 1 day) and a 30 s checkpoint; on a
    failure it loses the work since the last checkpoint. Wasted time across
    intervals from 2 minutes to 6 hours, against C/I + I/(2 MTBF) and its minimum
    I* = sqrt(2 C MTBF). Then the same intervals when the MTBF is really 4 days.
    """
    import argparse, json, math
    import numpy as np
    
    p = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    p.add_argument("--days", type=float, default=30, help="Simulated days of useful work.")
    p.add_argument("--mtbf-h", type=float, default=24, help="Mean time between failures, hours.")
    p.add_argument("--cost-s", type=float, default=30, help="Seconds per checkpoint.")
    p.add_argument("--trials", type=int, default=20, help="Simulated jobs per interval.")
    p.add_argument("--seed", type=int, default=0, help="Random seed.")
    p.add_argument("--json", help="Also write the results to this JSON file.")
    args = p.parse_args()
    rng = np.random.default_rng(args.seed)
    C = args.cost_s; work = args.days * 86400
    intervals = np.unique(np.geomspace(120, 6 * 3600, 18).astype(int))
    
    def overhead(I, mtbf):
        total = 0.0
        for _ in range(args.trials):
            done, clock = 0.0, 0.0
            next_fail = rng.exponential(mtbf)
            while done < work:
                seg = min(I, work - done)
                if clock + seg + C <= next_fail:
                    clock += seg + C; done += seg
                else:
                    clock = next_fail; next_fail = clock + rng.exponential(mtbf)       # the segment is lost
            total += clock
        return (total / args.trials - work) / (total / args.trials)
    
    rows = []
    for real in (args.mtbf_h, args.mtbf_h * 4):
        for I in intervals:
            rows.append({"mtbf_h": real, "interval_s": int(I), "waste_pct": overhead(I, real * 3600) * 100,
                         "formula_pct": (C / I + I / (2 * real * 3600)) * 100})
    best = math.sqrt(2 * C * args.mtbf_h * 3600)
    at_best = min((r for r in rows if r["mtbf_h"] == args.mtbf_h), key=lambda r: abs(r["interval_s"] - best))
    same_I_4x = min((r for r in rows if r["mtbf_h"] == args.mtbf_h * 4), key=lambda r: abs(r["interval_s"] - best))
    best4 = math.sqrt(2 * C * args.mtbf_h * 4 * 3600)
    opt_4x = min((r for r in rows if r["mtbf_h"] == args.mtbf_h * 4), key=lambda r: r["waste_pct"])
    print(f"I* = sqrt(2 C MTBF) = {best:.0f} s ({best / 60:.0f} min); simulated waste near it {at_best['waste_pct']:.2f}% "
          f"(formula {at_best['formula_pct']:.2f}%)")
    print(f"if the MTBF is really 4x longer: waste at the same interval {same_I_4x['waste_pct']:.2f}%, best possible "
          f"{opt_4x['waste_pct']:.2f}% at {opt_4x['interval_s']:.0f} s (I* would be {best4:.0f} s)")
    
    if args.json:
        with open(args.json, "w") as f:
            json.dump({"tables": {"intervals": rows, "summary": [{"best_s": best, "waste_at_best": at_best["waste_pct"], "formula_at_best": at_best["formula_pct"],
                       "waste_wrong_mtbf": same_I_4x["waste_pct"], "waste_opt_4x": opt_4x["waste_pct"], "best4_s": best4}]}}, f)
    
  3. 3Run it in the folder you saved it to, with the defaults first. Then change a knob from the table below and run it again.

    Terminal
    uv run checkpoint-interval-optimum.py
    uv run checkpoint-interval-optimum.py --help     # every knob
Knobs
Knob · defaultWhat it changes
--days30 Simulated days of useful work.
--mtbf-h24 Mean time between failures, hours.
--cost-s30 Seconds per checkpoint.
--trials20 Simulated jobs per interval.
--seed0 Random seed.

Our run

Wasted time against checkpoint intervalApple M2 · 8 cores · 8 GB
2496
Data table
Wasted time against checkpoint interval
Checkpoint interval (s)seriesWaste (%)
1202420.1
1622415.7
2212412.1
300249.26
407247.1
552245.49
750244.28
1,020243.46
1,380242.95
1,880242.66
2,550242.7
3,460242.93
4,690243.35
6,370244.29
8,640245.19
11.7K247.18
15.9K249.23
21.6K2411.9
1209620
1629615.6
2219612
300969.13
407966.92
552965.25
750963.95
1,020963
1,380962.3
1,880961.83
2,550961.53
3,460961.31
4,690961.33
6,370961.4
8,640961.6
11.7K962.19
15.9K962.64
21.6K963.37
macOS 26.6.2 · Python 3.13.3 · numpy 2.5.4 · run 2026-10-20
Output · uv run checkpoint-interval-optimum.py
I* = sqrt(2 C MTBF) = 2277 s (38 min); simulated waste near it 2.70% (formula 2.65%)
if the MTBF is really 4x longer: waste at the same interval 1.53%, best possible 1.31% at 3455 s (I* would be 4554 s)

What we found

The optimum sat at 2,280 s, as the formula says, with 2.7% of time wasted in the simulation against 2.65% from the formula. If the MTBF is really four days, keeping that interval wasted 1.53%, against the best possible 1.31%: a small loss for a 4× error, because the curve is flat near its minimum. In this simulation the best interval for the longer MTBF was shorter than the formula's 4,550 s, a sign of how flat the curve is there.


Read it

Getting the checkpoint interval exactly right does not matter much; getting it in the right order of magnitude does. Far to the left of the optimum the checkpoint cost dominates (the curve rises as 1/I), far to the right the lost work does. The square-root rule also says how the optimum moves: four times the MTBF only doubles the interval.