From 7c148a1346081c7f12fbb551b999987f14bef5ae Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 05:13:30 +0800 Subject: [PATCH 1/7] bench(baremetal): Sandstorm against other sandboxes on one KVM machine compare.py measures start to first answer and memory per instance kept running, for the same two programs, on: a plain process, bubblewrap, Docker (runc), Podman, Docker + gVisor, Kata 4.2, microsandbox 0.7.8, CubeSandbox 0.7.3, and Sandstorm on gVisor and on Firecracker, cold and from a warm template. The runtimes from bench/fleet/baselines.py are reused as they are. fork.py, fork_msb.py and fork_cube.py measure snapshotting a running sandbox and cloning it, each the way its own API does it. setup.sh brings up the two Sandstorm nodes, with their own port ranges, and microsandbox's images. Results on 2x Xeon E5-2637 v2 in results/2026-10-30, with the raw rows. Co-Authored-By: Claude Opus 5.5 --- bench/baremetal/compare.py | 295 ++++++++++++ bench/baremetal/fork.py | 114 +++++ bench/baremetal/fork_cube.py | 62 +++ bench/baremetal/fork_msb.py | 83 ++++ bench/baremetal/results/2026-10-30/README.md | 73 +++ bench/baremetal/results/2026-10-30/fork.jsonl | 3 + bench/baremetal/results/2026-10-30/run1.jsonl | 421 ++++++++++++++++++ bench/baremetal/results/2026-10-30/run2.jsonl | 188 ++++++++ bench/baremetal/results/2026-10-30/run3.jsonl | 69 +++ bench/baremetal/results/2026-10-30/run4.jsonl | 42 ++ bench/baremetal/setup.sh | 126 ++++++ 11 files changed, 1476 insertions(+) create mode 100644 bench/baremetal/compare.py create mode 100644 bench/baremetal/fork.py create mode 100644 bench/baremetal/fork_cube.py create mode 100644 bench/baremetal/fork_msb.py create mode 100644 bench/baremetal/results/2026-10-30/README.md create mode 100644 bench/baremetal/results/2026-10-30/fork.jsonl create mode 100644 bench/baremetal/results/2026-10-30/run1.jsonl create mode 100644 bench/baremetal/results/2026-10-30/run2.jsonl create mode 100644 bench/baremetal/results/2026-10-30/run3.jsonl create mode 100644 bench/baremetal/results/2026-10-30/run4.jsonl create mode 100644 bench/baremetal/setup.sh diff --git a/bench/baremetal/compare.py b/bench/baremetal/compare.py new file mode 100644 index 00000000..dfc9cce9 --- /dev/null +++ b/bench/baremetal/compare.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +"""Sandstorm against other open-source sandboxes, on one machine with KVM. + + sudo python3 compare.py --runtimes process,runc,sandstorm-fc-warm --apps web,app64 --out out.jsonl + +Every runtime runs the same two programs from bench/fleet/apps: `web`, a +Python HTTP server, and `app64`, one holding a 64 MiB numpy heap that every +request reads. For each runtime and program: + + start one instance at a time, 20 of them after one to warm up: from the + call that starts it to its first 200, polled every 5 ms + memory 100 kept running, each answering before the next starts; then + 30 s to settle, MemAvailable against before, and 20 of them + called at random to check they all still answer + +`memory` is per instance on top of whatever the runtime holds resident with +nothing running (its daemons), which is not counted: MemAvailable is read with the runtime already up. 100 +rather than until the machine is full: Docker's bridge holds 1023 ports, and +a 31 GiB machine would take thousands of the lighter ones. + +The runtimes from bench/fleet/baselines.py (process, bwrap, runc, runsc, +podman) run the program from the host's /usr; Kata does too, as a Docker +runtime. Sandstorm runs it the way a template does, and microsandbox from an +image of the same rootfs (see setup.sh). +""" + +import argparse +import json +import os +import random +import ssl +import statistics +import subprocess +import sys +import time +import urllib.request +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "fleet")) +import baselines as B # noqa: E402 + +POLL = 0.005 + + +def poll(url, headers, deadline): + """Seconds until url answers 200, or None. Polled every 5 ms.""" + req = urllib.request.Request(url, headers=headers or {}) + t0 = time.perf_counter() + while time.time() < deadline: + try: + with urllib.request.urlopen(req, timeout=2) as r: + r.read() + if r.status == 200: + return time.perf_counter() - t0 + except Exception: + time.sleep(POLL) + return None + + +# --- runtimes ------------------------------------------------------------------ +# +# start(app, i) -> (handle, url, headers); stop(handle); stop_all(). `idle` is +# brought up before and down after each runtime, so one's daemons are never +# counted against another. + + +class Baseline: + """A runtime from baselines.py, which has no per-instance stop.""" + + def __init__(self, cls, a): + self.name, self.rt = cls.name, cls(a) + + def start(self, app, i): + h, url = self.rt.start(app, i) + return h, url, None + + def stop(self, h): + pass + + def stop_all(self): + self.rt.stop_all() + + +class Kata(B.Container): + name, runtime = "kata", "io.containerd.kata.v2" + + +class Sandstorm: + """A local master and node; templates registered by setup.sh.""" + + def __init__(self, name, master, pki, warm): + self.name, self.master, self.warm = name, master, warm + self.token = (Path(pki) / "api-token").read_text().strip() + self.ctx = ssl.create_default_context(cafile=str(Path(pki) / "ca.pem")) + self.ctx.check_hostname = False + self.ids = [] + + def call(self, method, path, body=None): + req = urllib.request.Request( + self.master + path, + data=json.dumps(body).encode() if body is not None else None, + method=method, + headers={"authorization": f"Bearer {self.token}", "content-type": "application/json"}, + ) + with urllib.request.urlopen(req, context=self.ctx, timeout=120) as r: + raw = r.read() + return json.loads(raw) if raw else None + + def start(self, app, i): + sb = self.call("POST", "/v1/sandboxes", {"template": app + ("-warm" if self.warm else ""), "port": 8000}) + self.ids.append(sb["id"]) + return sb["id"], f"http://127.0.0.1:{sb['gateway_port']}/", {"x-sandstorm-sandbox-token": sb["token"]} + + def stop(self, h): + self.call("DELETE", f"/v1/sandboxes/{h}") + self.ids.remove(h) + + def stop_all(self): + for h in list(self.ids): + self.stop(h) + + +class Microsandbox: + """`msb run -d` from images setup.sh loaded, the port forwarded to the host. + (`msb create` boots the VM without running the image's command.)""" + + name = "microsandbox" + + def __init__(self, a): + self.names = [] + + def start(self, app, i): + name, port = f"cmp-{app}-{i}-{random.randrange(1 << 30)}", 31000 + i + subprocess.run(["msb", "run", "-d", "-q", "-n", name, "-m", "512", "-p", f"{port}:8000", f"sst-{app}:latest"], + check=True, capture_output=True) + self.names.append(name) + return name, f"http://127.0.0.1:{port}/", None + + def stop(self, h): + subprocess.run(["msb", "rm", "-f", h], capture_output=True) + self.names.remove(h) + + def stop_all(self): + if self.names: + subprocess.run(["msb", "rm", "-f"] + self.names, capture_output=True) + self.names = [] + + +class CubeSandbox: + """CubeSandbox through its E2B-compatible API, reached through cube-proxy. + + Templates are made by setup-cube.sh from the same rootfs, as an image.""" + + name = "cubesandbox" + + def __init__(self, a): + self.templates = {"web": a.cube_web, "app64": a.cube_app64} + self.ids = [] + + def call(self, method, path, body=None): + req = urllib.request.Request( + "http://127.0.0.1:3000" + path, + data=json.dumps(body).encode() if body is not None else None, + method=method, + headers={"X-API-Key": "e2b_000000", "Content-Type": "application/json"}, + ) + with urllib.request.urlopen(req, timeout=120) as r: + raw = r.read() + return json.loads(raw) if raw else None + + def start(self, app, i): + sb = self.call("POST", "/sandboxes", {"templateID": self.templates[app], "timeout": 3600}) + self.ids.append(sb["sandboxID"]) + return sb["sandboxID"], "http://127.0.0.1/", {"Host": f"8000-{sb['sandboxID']}.cube.app"} + + def stop(self, h): + try: + self.call("DELETE", f"/sandboxes/{h}") + except Exception: + pass + self.ids.remove(h) + + def stop_all(self): + for h in list(self.ids): + self.stop(h) + + +def make(name, a): + if name in B.RUNTIMES: + return Baseline(B.RUNTIMES[name], a) + if name == "kata": + return Baseline(Kata, a) + if name == "microsandbox": + return Microsandbox(a) + if name == "cubesandbox": + return CubeSandbox(a) + if name.startswith("sandstorm-"): + backend = "fc" if "-fc" in name else "gvisor" + return Sandstorm(name, a.fc_master if backend == "fc" else a.gvisor_master, + a.fc_pki if backend == "fc" else a.gvisor_pki, name.endswith("-warm")) + raise SystemExit(f"unknown runtime {name}") + + +# --- the measurements ------------------------------------------------------------- + + +def stop_all(rt, out): + """Clean up, without losing the measurement if cleanup fails: Kata left a + container `docker rm` could not kill, its process a zombie.""" + try: + rt.stop_all() + except Exception as e: + out.write(json.dumps({"runtime": rt.name, "kind": "cleanup_failed", "error": str(e)[-400:]}) + "\n") + + +def start_times(rt, app, n, out): + took = [] + for i in range(n + 1): + t0 = time.perf_counter() + h, url, hdr = rt.start(app, i) + s = poll(url, hdr, time.time() + 120) + total = time.perf_counter() - t0 if s is not None else None + rt.stop(h) + if i: # the first warms caches and templates up + took.append(total) + out.write(json.dumps({"runtime": rt.name, "app": app, "kind": "start", "n": i, + "start_to_answer_s": total and round(total, 4)}) + "\n") + stop_all(rt, out) + ok = sorted(t * 1000 for t in took if t is not None) + return {"p50_ms": round(statistics.median(ok), 1), "min_ms": round(ok[0], 1), + "p90_ms": round(ok[int(0.9 * len(ok))], 1), "failed": len(took) - len(ok)} if ok else {"failed": len(took)} + + +def memory(rt, app, n, out): + base = B.avail_mib() + up = [] + failed = None + for i in range(n): + try: + h, url, hdr = rt.start(app, 1000 + i) + except Exception as e: # a runtime that runs out of something says so here + failed = str(e)[-400:] + out.write(json.dumps({"runtime": rt.name, "app": app, "kind": "start_failed", "n": i, "error": failed}) + "\n") + break + if poll(url, hdr, time.time() + 120) is None: + out.write(json.dumps({"runtime": rt.name, "app": app, "kind": "never_answered", "n": i}) + "\n") + up.append((h, url, hdr)) + if B.avail_mib() < B.FLOOR_MIB: + break + time.sleep(30) + after = B.avail_mib() + sample = random.sample(up, min(20, len(up))) + answered = sum(poll(u, hd, time.time() + 30) is not None for _, u, hd in sample) + stop_all(rt, out) + return {"kept": len(up), "per_instance_mib": round((base - after) / len(up), 1), + "sampled": len(sample), "answered": answered, **({"stopped_by": failed} if failed else {})} + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--runtimes", required=True) + ap.add_argument("--apps", default="web,app64", dest="programs") + ap.add_argument("--start-count", type=int, default=20) + ap.add_argument("--keep", type=int, default=100) + ap.add_argument("--skip", default="", help="start or memory") + ap.add_argument("--app-dir", default="/root/rootfs/app") + ap.add_argument("--gvisor-master", default="https://127.0.0.1:18080") + ap.add_argument("--gvisor-pki", default="/var/lib/sst-gvisor/pki") + ap.add_argument("--fc-master", default="https://127.0.0.1:18081") + ap.add_argument("--fc-pki", default="/var/lib/sst-fc/pki") + ap.add_argument("--cube-web", default="") + ap.add_argument("--cube-app64", default="") + ap.add_argument("--out", required=True) + a = ap.parse_args() + a.apps = a.app_dir # the directory baselines.py's runtimes bind in + out = open(a.out, "a", buffering=1) + for name in a.runtimes.split(","): + docker = name in ("runc", "runsc", "kata") + if docker: + B.docker(True) + rt = make(name, a) + for app in a.programs.split(","): + row = {"runtime": name, "app": app, "kind": "summary", "avail_mib_before": B.avail_mib()} + if "start" not in a.skip: + row["start"] = start_times(rt, app, a.start_count, out) + if "memory" not in a.skip: + row["memory"] = memory(rt, app, a.keep, out) + out.write(json.dumps(row) + "\n") + print(json.dumps(row), flush=True) + if docker: + B.docker(False) + + +if __name__ == "__main__": + main() diff --git a/bench/baremetal/fork.py b/bench/baremetal/fork.py new file mode 100644 index 00000000..2ccbcb98 --- /dev/null +++ b/bench/baremetal/fork.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +"""Snapshot a running sandbox and fork it, against a Sandstorm node. + + sudo python3 fork.py --name sandstorm-fc --master https://127.0.0.1:18081 \ + --pki /var/lib/sst-fc/pki --out fork.jsonl + +The source is app64-warm on port 8000, answering. Then: + + snapshot `branch` it 6 times; the first is dropped + fork 1 a child from the last tag, to its first 200, 10 times after one + fork n n children in one call, until every one has answered, 3 rounds + +Everything polled every 5 ms, as compare.py does. The same steps, the same +way, as CubeSandbox's snapshot and SDK clone were measured on bm +(bench/fleet/results/2026-10-29-cubesandbox). +""" + +import argparse +import concurrent.futures as cf +import json +import ssl +import statistics +import time +import urllib.request +from pathlib import Path + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--name", required=True) + ap.add_argument("--master", required=True) + ap.add_argument("--pki", required=True) + ap.add_argument("--template", default="app64-warm") + ap.add_argument("--out", required=True) + a = ap.parse_args() + tok = (Path(a.pki) / "api-token").read_text().strip() + ctx = ssl.create_default_context(cafile=str(Path(a.pki) / "ca.pem")) + ctx.check_hostname = False + + def call(method, path, body=None): + req = urllib.request.Request( + a.master + path, + data=json.dumps(body).encode() if body is not None else None, + method=method, + headers={"authorization": f"Bearer {tok}", "content-type": "application/json"}, + ) + with urllib.request.urlopen(req, context=ctx, timeout=180) as r: + raw = r.read() + return json.loads(raw) if raw else None + + def answered(sb, secs=120): + req = urllib.request.Request(f"http://127.0.0.1:{sb['gateway_port']}/", + headers={"x-sandstorm-sandbox-token": sb["token"]}) + end = time.time() + secs + while time.time() < end: + try: + with urllib.request.urlopen(req, timeout=2) as r: + if r.status == 200: + return time.time() + except Exception: + time.sleep(0.005) + return None + + def p50(v): + return round(statistics.median(v), 1) + + parent = call("POST", "/v1/sandboxes", {"template": a.template, "port": 8000}) + assert answered(parent), "the source never answered" + stamp = int(time.time()) + + snap = [] + for i in range(6): + t = time.time() + call("POST", f"/v1/sandboxes/{parent['id']}/branch", {"tag": f"cmp-{stamp}-{i}"}) + snap.append((time.time() - t) * 1000) + answered(parent, 30) + tag = f"cmp-{stamp}-5" + + one = [] + for i in range(11): + t = time.time() + kid = call("POST", "/v1/sandboxes", {"snapshot_tag": tag, "n": 1})[0] + done = answered(kid) + one.append((done - t) * 1000) + call("DELETE", f"/v1/sandboxes/{kid['id']}") + time.sleep(0.5) + + batches = {} + for n in (10, 20): + walls = [] + for _ in range(3): + t = time.time() + kids = call("POST", "/v1/sandboxes", {"snapshot_tag": tag, "n": n}) + with cf.ThreadPoolExecutor(n) as ex: + ends = list(ex.map(answered, kids)) + ok = [e for e in ends if e] + walls.append((max(ok) - t) * 1000 if len(ok) == n else float("nan")) + for k in kids: + call("DELETE", f"/v1/sandboxes/{k['id']}") + time.sleep(3) + batches[n] = walls + call("DELETE", f"/v1/sandboxes/{parent['id']}") + + row = {"runtime": a.name, "kind": "fork", "template": a.template, + "snapshot_ms": p50(snap[1:]), "snapshot_all_ms": [round(x) for x in snap], + "fork1_ms": p50(one[1:]), + **{f"fork{n}_wall_ms": p50(w) for n, w in batches.items()}, + **{f"fork{n}_rounds_ms": [round(x) for x in w] for n, w in batches.items()}} + open(a.out, "a").write(json.dumps(row) + "\n") + print(json.dumps(row), flush=True) + + +if __name__ == "__main__": + main() diff --git a/bench/baremetal/fork_cube.py b/bench/baremetal/fork_cube.py new file mode 100644 index 00000000..039aa824 --- /dev/null +++ b/bench/baremetal/fork_cube.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""CubeSandbox's snapshot and clone, measured as fork.py measures Sandstorm's. + + python3 fork_cube.py + +The source is an app64 started from its template. Then: snapshot it +(`POST /sandboxes/{id}/snapshots`) 6 times, the first dropped; start one +from the snapshot to its first answer, 10 times after one; and clone n the +way its SDK's `Sandbox.clone(n, concurrency=n)` does -- one snapshot, then n +creates at once -- until every child answers, 3 rounds. v0.7.3 has no +`/fork` endpoint. Polled every 5 ms through cube-proxy. +""" + +import json, statistics, sys, time, urllib.request, urllib.error, concurrent.futures as cf +API = "http://127.0.0.1:3000"; TPL = sys.argv[1] +H = {"X-API-Key": "e2b_000000", "Content-Type": "application/json"} +def call(m, path, body=None, timeout=180): + r = urllib.request.Request(API + path, data=json.dumps(body).encode() if body is not None else None, method=m, headers=H) + try: + with urllib.request.urlopen(r, timeout=timeout) as f: return f.status, json.loads(f.read() or b"null") + except urllib.error.HTTPError as e: return e.code, e.read().decode()[:300] +def answer(sid, deadline): + req = urllib.request.Request("http://127.0.0.1/", headers={"Host": f"8000-{sid}.cube.app"}) + while time.time() < deadline: + try: + with urllib.request.urlopen(req, timeout=2) as r: + if r.status == 200: return time.time() + except Exception: time.sleep(0.005) + return None +def q(v): v = sorted(v); return f"p50 {statistics.median(v):.0f} ms min {v[0]:.0f} max {v[-1]:.0f} n={len(v)}" +st, parent = call("POST", "/sandboxes", {"templateID": TPL, "timeout": 3600}); assert st == 201, (st, parent) +pid = parent["sandboxID"]; assert answer(pid, time.time() + 60), "parent never answered"; print("parent up", pid) +snap, snaps = [], [] +for i in range(6): + t = time.time(); st, info = call("POST", f"/sandboxes/{pid}/snapshots", {}); assert st in (200, 201), (st, info) + snap.append((time.time() - t) * 1000); snaps.append(info["snapshotID"]) + assert answer(pid, time.time() + 30) +print("snapshot ms", [round(x) for x in snap]); print("snapshot (a running app64):", q(snap[1:])) +one = [] +for i in range(11): + t = time.time(); st, sb = call("POST", "/sandboxes", {"templateID": snaps[-1], "timeout": 3600}); assert st == 201, (st, sb) + done = answer(sb["sandboxID"], time.time() + 60); assert done, "child never answered"; one.append((done - t) * 1000) + call("DELETE", f"/sandboxes/{sb['sandboxID']}"); time.sleep(0.5) +print("start 1 from the snapshot, to first answer:", q(one[1:])) +def create(snap): + st, sb = call("POST", "/sandboxes", {"templateID": snap, "timeout": 3600}) + return sb["sandboxID"] if st == 201 else None +for n in (1, 10, 20): + walls = [] + for r in range(3): + t = time.time(); st, info = call("POST", f"/sandboxes/{pid}/snapshots", {}); assert st in (200, 201), (st, info) + snaps.append(info["snapshotID"]) + with cf.ThreadPoolExecutor(n) as ex: + ids = [i for i in ex.map(lambda _: create(info["snapshotID"]), range(n)) if i] + ends = list(ex.map(lambda s: answer(s, time.time() + 120), ids)) + ok = [e for e in ends if e]; walls.append((max(ok) - t) * 1000 if ok else float("nan")) + if len(ok) < n: print(f" n={n}: only {len(ok)} answered") + for s_ in ids: call("DELETE", f"/sandboxes/{s_}") + time.sleep(3) + print(f"clone {n} (snapshot + {n} creates at once), until all answer: wall p50 {statistics.median(walls):.0f} ms, per child {statistics.median(walls)/n:.1f} ms (rounds {[round(w) for w in walls]})") +call("DELETE", f"/sandboxes/{pid}") +for sid in snaps: call("DELETE", f"/snapshots/{sid}") diff --git a/bench/baremetal/fork_msb.py b/bench/baremetal/fork_msb.py new file mode 100644 index 00000000..4a59d5c5 --- /dev/null +++ b/bench/baremetal/fork_msb.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""microsandbox's fork, measured as fork.py measures Sandstorm's. + + sudo python3 fork_msb.py --out fork.jsonl + +`msb fork` copies a running sandbox; there is no separate snapshot step. A +child gets no port forward (`msb fork` takes none and `msb modify` cannot add +one), so it cannot be called from the host the way fork.py calls Sandstorm's +children through their gateways. The time here is therefore until `msb fork` +returns with the children running -- more lenient than fork.py, which waits +for each child's first answer. Each child is then checked from inside, with +`msb exec`, outside the timing. +""" + +import argparse +import json +import statistics +import subprocess +import time +import urllib.request + +SRC = "fk-src" + + +def msb(*args, check=True): + return subprocess.run(["msb", *args], capture_output=True, text=True, check=check) + + +def answers(name): + r = msb("exec", name, "--", "python3", "-c", + "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8000/', timeout=10).read().decode())", + check=False) + return r.returncode == 0 and r.stdout.strip() != "" + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--out", required=True) + a = ap.parse_args() + msb("rm", "-f", SRC, check=False) + msb("run", "-d", "-q", "-n", SRC, "-m", "512", "-p", "32600:8000", "sst-app64:latest") + end = time.time() + 60 + while time.time() < end: + try: + urllib.request.urlopen("http://127.0.0.1:32600/", timeout=1).read() + break + except Exception: + time.sleep(0.05) + + one, checked = [], 0 + for i in range(11): + t = time.time() + msb("fork", SRC, "-n", f"fk1-{i}") + one.append((time.time() - t) * 1000) + checked += answers(f"fk1-{i}") + msb("rm", "-f", f"fk1-{i}", check=False) + time.sleep(0.5) + + batches, failed = {}, 0 + for n in (10, 20): + walls = [] + for r in range(3): + names = [f"fk{n}-{r}-{i}" for i in range(n)] + t = time.time() + msb("fork", SRC, "--names", *names) + walls.append((time.time() - t) * 1000) + failed += sum(not answers(x) for x in names[:3]) + msb("rm", "-f", *names, check=False) + time.sleep(3) + batches[n] = walls + msb("rm", "-f", SRC, check=False) + + row = {"runtime": "microsandbox", "kind": "fork", "template": "app64", "measured_to": "msb fork returns", + "fork1_ms": round(statistics.median(one[1:]), 1), "fork1_children_answering": f"{checked}/11", + **{f"fork{n}_wall_ms": round(statistics.median(w), 1) for n, w in batches.items()}, + **{f"fork{n}_rounds_ms": [round(x) for x in w] for n, w in batches.items()}, + "batch_children_checked_failed": failed} + open(a.out, "a").write(json.dumps(row) + "\n") + print(json.dumps(row), flush=True) + + +if __name__ == "__main__": + main() diff --git a/bench/baremetal/results/2026-10-30/README.md b/bench/baremetal/results/2026-10-30/README.md new file mode 100644 index 00000000..e099b241 --- /dev/null +++ b/bench/baremetal/results/2026-10-30/README.md @@ -0,0 +1,73 @@ +# Sandstorm against other open-source sandboxes, on bare metal — 2026-10-30 + +One machine, every runtime on it in turn, the same two programs, the same harness. + +- **Machine:** 2 × Intel Xeon E5-2637 v2 (Ivy Bridge, 2013; 8 cores, 16 threads), 31 GB, a SATA SSD, Ubuntu 24.04, kernel 6.8, native KVM. +- **Programs:** `web`, a Python HTTP server, and `app64`, which holds a 64 MiB numpy heap and reads all of it on every request (`bench/fleet/apps`). +- **Start:** one instance at a time, from the call that starts it to its first 200, polled every 5 ms; 20 after one warm-up; p50. +- **Memory:** 100 instances kept running, each answering before the next starts; 30 s to settle; MemAvailable before and after, divided by the count; then 20 of them called at random. Nothing is tiered or paused in this table: Sandstorm ran with `--idle-frozen-secs 86400 --reclaim-hot off --reclaim-frozen off`, so its sandboxes stayed hot like everyone else's. +- **Harness:** [`compare.py`](../../compare.py), [`setup.sh`](../../setup.sh), [`fork.py`](../../fork.py), [`fork_msb.py`](../../fork_msb.py), [`fork_cube.py`](../../fork_cube.py). Raw rows: `run1.jsonl` (the runtimes that are not Sandstorm, plus microsandbox), `run2.jsonl` (Sandstorm), `run3.jsonl` (Kata), `run4.jsonl` (CubeSandbox), `fork.jsonl`. + +## Start and memory + +| | isolation | start, web / app64 | memory per instance, web / app64 | +|---|---|---:|---:| +| plain process | none | 67 / 200 ms | 7.8 / 79.7 MiB | +| bubblewrap | namespaces, host network | 74 / 195 ms | 8.3 / 66.9 MiB | +| Docker (runc) | namespaces | 256 / 414 ms | 15.2 / 88.5 MiB | +| Podman (crun) | namespaces | 296 / 429 ms | 10.8 / 84.0 MiB | +| Docker + gVisor | gVisor | 327 / 660 ms | 30.8 / 106.8 MiB | +| **Sandstorm, gVisor** | gVisor | **308 / 624 ms** | **24.0 / 97.2 MiB** | +| **Sandstorm, gVisor, warm template** | gVisor | **168 / 186 ms** | 24.3 / 97.8 MiB | +| Kata 4.2 (runtime-rs, QEMU) | VM | 3,005 / 3,397 ms | 223 / 311 MiB¹ | +| microsandbox 0.7.8 (libkrun) | VM | 1,117 / 1,119 ms | 80.2 / 166.2 MiB | +| CubeSandbox 0.7.3 | VM | **72 / 78 ms** | **8.9 / 12.2 MiB** | +| **Sandstorm, Firecracker** | VM | 636 / 964 ms² | 80.0 / 166.1 MiB | +| **Sandstorm, Firecracker, warm template** | VM | 129 / 199 ms | 10.8 / 11.9 MiB | + +Every runtime answered 20 of 20 when sampled. + +¹ Kata keeps every guest's memory in shared memory for virtio-fs, so `/dev/shm` (16 GB here) is its ceiling: 81 `web` guests, 57 `app64`. Past it a new guest fails to start, and at 57 `app64` none of the 20 sampled answered; its figure is from 40. +² After the fixes in deeplethe/sandstorm#380, each measured on its own: 1,953 / 2,120 ms before them. `run2.jsonl` has 868 / 1,174 ms, measured before the last two (`quiet`, the agent starting the program first). + +Every CubeSandbox and warm Sandstorm sandbox starts from a snapshot of the program already running, and maps that memory privately, so a page only costs a sandbox once it writes it. `app64` only reads its heap after starting, which is why it costs those two barely more than `web`; a program that rewrote its heap would cost more. + +## Snapshot and fork + +The source is a running `app64` started from a template; polled every 5 ms. + +| p50 | Sandstorm, Firecracker | Sandstorm, gVisor | CubeSandbox | microsandbox³ | +|---|---:|---:|---:|---:| +| snapshot a running sandbox | **52 ms** | 368 ms | 252 ms | — | +| start 1 from the snapshot, to its first answer | 135 ms | 138 ms | 133 ms | — | +| clone 1: snapshot, then start | **~187 ms** | ~506 ms | 542 ms | 658 ms | +| clone 10, until all answer | ~883 ms | ~1,530 ms | 973 ms | 835 ms | +| clone 20, until all answer | ~1,562 ms | ~2,760 ms | **1,046 ms** | 1,152 ms | + +Sandstorm's clone is `branch` then one fork call with `n`, so the sum is approximate. CubeSandbox's is its SDK's `clone(n, concurrency=n)`: a snapshot, then n creates at once (0.7.3 has no `/fork`). +³ `msb fork` copies a running sandbox in one step. Its children get no port forward and cannot be called from the host, so its time is until `msb fork` returns with them running, not until they answer; each was checked from inside afterwards. + +## What it says + +- **Against the other VM runtimes,** a warm Sandstorm Firecracker sandbox starts 8× faster than microsandbox and 23× faster than Kata, in a seventh to a twentieth of the memory. Cold, it is still faster than both. +- **Against Docker with gVisor,** the same isolation, Sandstorm on gVisor starts a little faster cold, twice as fast warm, and holds 10-20% less per instance. +- **Against CubeSandbox,** Sandstorm snapshots a running sandbox 5× faster and clones one 3× faster. Starting one from a snapshot is level, and so is memory. CubeSandbox starts a sandbox from its template faster (72 against 129 ms for `web`, 78 against 199 for `app64`) and clones 20 faster (1,046 against ~1,562 ms). +- On the 2025 EPYC in the earlier bm run, Sandstorm's warm `web` start was 52 ms against CubeSandbox's 55. On this 2013 Xeon it is 129 against 72: something on Sandstorm's warm path is far more sensitive to an old CPU than CubeSandbox's, not yet found. +- A fork of n children is created one after another on the node, about 65 ms each; CubeSandbox and microsandbox create them in parallel. + +## Found and fixed on the way + +All in deeplethe/sandstorm#380: + +- The gateway retried a sandbox that had not started listening yet with a backoff up to 500 ms, holding a first answer 300-370 ms past the program listening. Sandstorm gVisor cold `app64`: 941 → 616 ms. +- Firecracker cold start: i8042 probing, the agent importing numpy before starting the program, a SYN resent only after 1 s, and above all ARP for a guest still booting asked again only after 1 s; then `quiet` and the program started first. `web` 1,953 → 636 ms. +- A fixed tap MAC, without which pinning the guest's neighbour entry made every warm start 43 s. +- A guest hostname that resolves without DNS, which cost 20 s per Firecracker sandbox on bm. +- Two master-and-node processes on one machine sharing gateway ports: the second now refuses to start. + +## Not covered + +- E2B self-hosted (Nomad and Consul) was not set up. +- No load: idle sandboxes that each answered single requests. +- One machine, one run of each; the p90s are in the raw rows. +- bubblewrap shares the host's network here, so it did the least work of all. diff --git a/bench/baremetal/results/2026-10-30/fork.jsonl b/bench/baremetal/results/2026-10-30/fork.jsonl new file mode 100644 index 00000000..2b4b615d --- /dev/null +++ b/bench/baremetal/results/2026-10-30/fork.jsonl @@ -0,0 +1,3 @@ +{"runtime": "sandstorm-fc", "kind": "fork", "template": "app64-warm", "snapshot_ms": 52.5, "snapshot_all_ms": [71, 65, 53, 37, 46, 76], "fork1_ms": 135.1, "fork10_wall_ms": 830.7, "fork20_wall_ms": 1510.3, "fork10_rounds_ms": [831, 859, 805], "fork20_rounds_ms": [1527, 1504, 1510]} +{"runtime": "sandstorm-gvisor", "kind": "fork", "template": "app64-warm", "snapshot_ms": 368.3, "snapshot_all_ms": [398, 487, 339, 363, 376, 368], "fork1_ms": 137.6, "fork10_wall_ms": 1161.4, "fork20_wall_ms": 2391.2, "fork10_rounds_ms": [1161, 1187, 1147], "fork20_rounds_ms": [2511, 2376, 2391]} +{"runtime": "microsandbox", "kind": "fork", "template": "app64", "measured_to": "msb fork returns", "fork1_ms": 658.2, "fork1_children_answering": "11/11", "fork10_wall_ms": 834.9, "fork20_wall_ms": 1151.5, "fork10_rounds_ms": [800, 835, 930], "fork20_rounds_ms": [1066, 1152, 1259], "batch_children_checked_failed": 0} diff --git a/bench/baremetal/results/2026-10-30/run1.jsonl b/bench/baremetal/results/2026-10-30/run1.jsonl new file mode 100644 index 00000000..5f467848 --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run1.jsonl @@ -0,0 +1,421 @@ +{"runtime": "process", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.0667} +{"runtime": "process", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.0608} +{"runtime": "process", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.0638} +{"runtime": "process", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1309} +{"runtime": "process", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.0639} +{"runtime": "process", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.1412} +{"runtime": "process", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.0575} +{"runtime": "process", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.0692} +{"runtime": "process", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.0638} +{"runtime": "process", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1398} +{"runtime": "process", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.0636} +{"runtime": "process", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1581} +{"runtime": "process", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.0698} +{"runtime": "process", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.0581} +{"runtime": "process", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.0729} +{"runtime": "process", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.0685} +{"runtime": "process", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.0669} +{"runtime": "process", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.061} +{"runtime": "process", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.0634} +{"runtime": "process", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1137} +{"runtime": "process", "app": "web", "kind": "summary", "avail_mib_before": 30867, "start": {"p50_ms": 66.8, "min_ms": 57.5, "p90_ms": 141.2, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 7.8, "sampled": 20, "answered": 20}} +{"runtime": "process", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.2307} +{"runtime": "process", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.2974} +{"runtime": "process", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.1647} +{"runtime": "process", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.192} +{"runtime": "process", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.158} +{"runtime": "process", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.259} +{"runtime": "process", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.1583} +{"runtime": "process", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.313} +{"runtime": "process", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1811} +{"runtime": "process", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.181} +{"runtime": "process", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.3529} +{"runtime": "process", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.2188} +{"runtime": "process", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.3151} +{"runtime": "process", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1637} +{"runtime": "process", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1803} +{"runtime": "process", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.2194} +{"runtime": "process", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.2141} +{"runtime": "process", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.158} +{"runtime": "process", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.2089} +{"runtime": "process", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.1637} +{"runtime": "process", "app": "app64", "kind": "summary", "avail_mib_before": 30908, "start": {"p50_ms": 200.4, "min_ms": 158.0, "p90_ms": 315.1, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 79.7, "sampled": 20, "answered": 20}} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.08} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.146} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.0739} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1265} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.0745} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.0732} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.0684} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.0715} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.0708} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.0739} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.074} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.0804} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.0685} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.0738} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.0805} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.0735} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.1459} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.0739} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.0806} +{"runtime": "bwrap", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.0747} +{"runtime": "bwrap", "app": "web", "kind": "summary", "avail_mib_before": 30957, "start": {"p50_ms": 74.0, "min_ms": 68.4, "p90_ms": 145.9, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 8.3, "sampled": 20, "answered": 20}} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.1807} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.1819} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.2682} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.1917} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.2359} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.221} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.1902} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.1867} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.3298} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.1977} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.1971} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.1742} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.2357} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1938} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1849} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.2412} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.1967} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.2737} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1869} +{"runtime": "bwrap", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.189} +{"runtime": "bwrap", "app": "app64", "kind": "summary", "avail_mib_before": 30121, "start": {"p50_ms": 195.3, "min_ms": 174.2, "p90_ms": 273.7, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 66.9, "sampled": 20, "answered": 20}} +{"runtime": "runc", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.2973} +{"runtime": "runc", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.2803} +{"runtime": "runc", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.2712} +{"runtime": "runc", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.2416} +{"runtime": "runc", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.316} +{"runtime": "runc", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.2806} +{"runtime": "runc", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.2385} +{"runtime": "runc", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.2779} +{"runtime": "runc", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.2966} +{"runtime": "runc", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.2439} +{"runtime": "runc", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.2463} +{"runtime": "runc", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.2591} +{"runtime": "runc", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.2493} +{"runtime": "runc", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.2514} +{"runtime": "runc", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.2414} +{"runtime": "runc", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.246} +{"runtime": "runc", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.2512} +{"runtime": "runc", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.2535} +{"runtime": "runc", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.2617} +{"runtime": "runc", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.2712} +{"runtime": "runc", "app": "web", "kind": "summary", "avail_mib_before": 30806, "start": {"p50_ms": 256.3, "min_ms": 238.5, "p90_ms": 297.3, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 15.2, "sampled": 20, "answered": 20}} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.4234} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.364} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.3593} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.3664} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.5393} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.3645} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.3647} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.3508} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.3614} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.4607} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.4205} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.4899} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.4645} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.5335} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.4377} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.3999} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.4109} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.4165} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.3522} +{"runtime": "runc", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.4506} +{"runtime": "runc", "app": "app64", "kind": "summary", "avail_mib_before": 30775, "start": {"p50_ms": 413.7, "min_ms": 350.8, "p90_ms": 533.5, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 88.5, "sampled": 20, "answered": 20}} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.3839} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.3069} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.3485} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.3186} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.3348} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.2954} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.3177} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.306} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.3146} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.3153} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.3498} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.3353} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.3381} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.3172} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.3418} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.3395} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.3025} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.3174} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.3439} +{"runtime": "runsc", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.3363} +{"runtime": "runsc", "app": "web", "kind": "summary", "avail_mib_before": 30826, "start": {"p50_ms": 326.7, "min_ms": 295.4, "p90_ms": 349.8, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 30.8, "sampled": 20, "answered": 20}} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.7624} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.6709} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.575} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.63} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.7321} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.6677} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.6211} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.6196} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.7667} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.655} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.7343} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.6764} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.7444} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.6448} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.6714} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.6077} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.6652} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.6439} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.6542} +{"runtime": "runsc", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.5706} +{"runtime": "runsc", "app": "app64", "kind": "summary", "avail_mib_before": 30746, "start": {"p50_ms": 660.1, "min_ms": 570.6, "p90_ms": 762.4, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 106.8, "sampled": 20, "answered": 20}} +{"runtime": "podman", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.295} +{"runtime": "podman", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.3761} +{"runtime": "podman", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.2932} +{"runtime": "podman", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.3056} +{"runtime": "podman", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.2609} +{"runtime": "podman", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.2964} +{"runtime": "podman", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.2643} +{"runtime": "podman", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.3559} +{"runtime": "podman", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.3397} +{"runtime": "podman", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.3599} +{"runtime": "podman", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.2524} +{"runtime": "podman", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.2644} +{"runtime": "podman", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.3127} +{"runtime": "podman", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.2907} +{"runtime": "podman", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.3152} +{"runtime": "podman", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.3075} +{"runtime": "podman", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.2886} +{"runtime": "podman", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.3286} +{"runtime": "podman", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.2469} +{"runtime": "podman", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.2572} +{"runtime": "podman", "app": "web", "kind": "summary", "avail_mib_before": 30804, "start": {"p50_ms": 295.7, "min_ms": 246.9, "p90_ms": 359.9, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 10.8, "sampled": 20, "answered": 20}} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.377} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.3934} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.457} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.431} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.3898} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.3768} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.4364} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.4628} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.4394} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.482} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.4078} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.394} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.4378} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.4098} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.4265} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.5313} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.4329} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.4374} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.4222} +{"runtime": "podman", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.3715} +{"runtime": "podman", "app": "app64", "kind": "summary", "avail_mib_before": 30831, "start": {"p50_ms": 428.7, "min_ms": 371.5, "p90_ms": 482.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 84.0, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.3102} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.2991} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.314} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.3216} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.5338} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.3084} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.3122} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.3093} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.3168} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.3028} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.3078} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.3001} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.3028} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.3131} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.505} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.3086} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.32} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.3112} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.3163} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.3096} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "summary", "avail_mib_before": 30825, "start": {"p50_ms": 310.7, "min_ms": 299.1, "p90_ms": 505.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 17.6, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.942} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.951} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.9407} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.9379} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.9433} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.9413} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.9341} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.9569} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.9449} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.9332} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.9217} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.9343} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.9336} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.931} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.9479} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.9633} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.9738} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.9491} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.9376} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.9398} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "summary", "avail_mib_before": 29000, "start": {"p50_ms": 941.0, "min_ms": 921.7, "p90_ms": 963.3, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 35.6, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.1716} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.1559} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.19} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1468} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.1549} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.171} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.1547} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.157} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.1609} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1582} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.146} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1646} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.1822} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.1486} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.1659} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.1709} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.1547} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.206} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.1748} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1544} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "summary", "avail_mib_before": 26100, "start": {"p50_ms": 159.5, "min_ms": 146.0, "p90_ms": 190.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 21.0, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.2099} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.1939} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.1977} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.2263} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.1978} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.1869} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.1968} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.1839} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1886} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.1848} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.2031} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.1923} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.1989} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1881} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1856} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.1994} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.1947} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.2211} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1813} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.1853} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "summary", "avail_mib_before": 28638, "start": {"p50_ms": 194.3, "min_ms": 181.3, "p90_ms": 221.1, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 50.8, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 1.5961} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 1.5299} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 2.2037} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 1.565} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 1.5973} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 1.9386} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 1.9774} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 1.976} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 1.976} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 1.2173} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 1.9673} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 1.9103} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 1.9812} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 1.9733} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 1.5069} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 1.933} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 1.9764} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 1.9758} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 1.9121} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 1.9772} +{"runtime": "sandstorm-fc", "app": "web", "kind": "summary", "avail_mib_before": 25410, "start": {"p50_ms": 1953.0, "min_ms": 1217.3, "p90_ms": 1981.2, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 58.2, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 2.2262} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 1.9601} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 1.9551} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 2.0135} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 1.9454} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 1.9901} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 2.174} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 2.16} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 2.1947} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 2.0} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 2.2023} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 2.0795} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 2.1611} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 2.0182} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 2.0316} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 2.2259} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 2.1968} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 2.0046} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 2.1935} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 2.1717} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "never_answered", "n": 67} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "summary", "avail_mib_before": 24709, "start": {"p50_ms": 2119.7, "min_ms": 1945.4, "p90_ms": 2225.9, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 19.4, "sampled": 20, "answered": 2}} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.1658} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.1445} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.1912} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1989} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.1607} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.1621} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.1422} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.1375} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.1398} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1527} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.1637} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1505} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.1332} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.1403} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.1353} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.1374} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.1371} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.1408} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.1342} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1342} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "summary", "avail_mib_before": 30428, "start": {"p50_ms": 141.5, "min_ms": 133.2, "p90_ms": 191.2, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 9.6, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 1.9899} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.4692} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.1819} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.2074} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.1834} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.2182} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.223} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.1814} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.159} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.1679} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.1875} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.1845} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.198} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1692} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1851} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.1818} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.1613} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.1885} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1759} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.2034} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "summary", "avail_mib_before": 29630, "start": {"p50_ms": 184.8, "min_ms": 159.0, "p90_ms": 469.2, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 10.4, "sampled": 20, "answered": 20}} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 1.1118} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 1.115} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 1.1607} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 1.1095} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 1.1245} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 1.1134} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 1.1207} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 1.1109} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 1.1388} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 1.1144} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 1.1169} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 1.1092} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 1.2017} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 1.1081} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 1.126} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 1.1183} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 1.1131} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 1.117} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 1.1805} +{"runtime": "microsandbox", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 1.1908} +{"runtime": "microsandbox", "app": "web", "kind": "summary", "avail_mib_before": 29576, "start": {"p50_ms": 1116.9, "min_ms": 1108.1, "p90_ms": 1190.8, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 80.2, "sampled": 20, "answered": 20}} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 1.1615} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 1.1447} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 1.1169} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 1.2037} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 1.1129} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 1.1476} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 1.1243} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 1.116} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 1.134} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 1.1128} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 1.1843} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 1.1621} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 1.1113} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 1.1183} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 1.1194} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 1.1102} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 1.1195} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 1.1132} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 1.1134} +{"runtime": "microsandbox", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 1.1132} +{"runtime": "microsandbox", "app": "app64", "kind": "summary", "avail_mib_before": 30575, "start": {"p50_ms": 1118.8, "min_ms": 1110.2, "p90_ms": 1184.3, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 166.2, "sampled": 20, "answered": 20}} diff --git a/bench/baremetal/results/2026-10-30/run2.jsonl b/bench/baremetal/results/2026-10-30/run2.jsonl new file mode 100644 index 00000000..89170071 --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run2.jsonl @@ -0,0 +1,188 @@ +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.2937} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.3239} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.2799} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.2818} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.3421} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.2791} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.3103} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.3521} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.2837} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.2953} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.2963} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.3428} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.3266} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.3581} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.3366} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.275} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.3058} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.3475} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.3389} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.2949} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "summary", "avail_mib_before": 30619, "start": {"p50_ms": 308.1, "min_ms": 275.0, "p90_ms": 352.1, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 24.0, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.7038} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.7853} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.6793} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.7284} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.6687} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.6198} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.6131} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.6847} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.6871} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.5673} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.6658} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.6315} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.6103} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.6126} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.6248} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.6122} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.6215} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.5775} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.6063} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.6228} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "summary", "avail_mib_before": 28311, "start": {"p50_ms": 623.8, "min_ms": 567.3, "p90_ms": 728.4, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 97.2, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.1987} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.1701} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.1789} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1716} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.1688} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.1415} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.1832} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.1739} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.1649} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1838} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.1641} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1658} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.1663} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.1607} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.1614} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.1685} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.1665} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.1574} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.1708} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1653} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "summary", "avail_mib_before": 20933, "start": {"p50_ms": 167.5, "min_ms": 141.5, "p90_ms": 183.8, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 24.3, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.1971} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.2088} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.1939} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.1846} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.1957} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.1732} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.2094} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.1851} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1843} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.181} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.192} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.187} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.1952} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1858} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1818} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.1884} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.1798} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.1841} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1828} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.1921} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "summary", "avail_mib_before": 28231, "start": {"p50_ms": 186.4, "min_ms": 173.2, "p90_ms": 208.8, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 97.8, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.8775} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.9291} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.976} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.8385} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.8044} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.8183} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.9935} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.9229} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.8912} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.8929} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.8445} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.7826} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.8967} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.8519} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.7856} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.84} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.8576} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.9571} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.96} +{"runtime": "sandstorm-fc", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.7895} +{"runtime": "sandstorm-fc", "app": "web", "kind": "summary", "avail_mib_before": 20943, "start": {"p50_ms": 867.5, "min_ms": 782.6, "p90_ms": 976.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 80.0, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 1.1254} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 1.1395} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 1.179} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 1.2199} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 1.1204} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 1.446} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 1.1657} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 1.1763} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 1.1636} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 1.3083} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 1.1852} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 1.0736} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 1.2209} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 1.3312} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 1.0599} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 1.3167} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 1.1253} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 1.1706} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 1.1707} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 1.2914} +{"runtime": "sandstorm-fc", "app": "app64", "kind": "summary", "avail_mib_before": 22942, "start": {"p50_ms": 1173.5, "min_ms": 1059.9, "p90_ms": 1331.2, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 166.1, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 43.3257} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 43.5796} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 43.572} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 43.6184} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 43.5698} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 43.5794} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 43.5647} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 43.5608} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 43.5807} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 43.5819} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 43.5746} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 43.5846} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 43.5599} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 43.5979} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 43.5842} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 43.3334} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 43.3242} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 43.333} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 43.5673} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 43.5802} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.1309} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.1342} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.1184} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1186} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.1228} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.1225} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.1258} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.1377} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.1364} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1198} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.1235} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1279} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.1318} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.1149} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.1404} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.1274} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.1364} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.1443} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.1335} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1332} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "summary", "avail_mib_before": 30418, "start": {"p50_ms": 129.4, "min_ms": 114.9, "p90_ms": 140.4, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 10.8, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.2325} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.24} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.2293} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.1679} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.1887} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.1841} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.1822} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.2226} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1986} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.2063} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.2669} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.184} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.1989} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.183} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1786} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.195} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.2071} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.2101} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1722} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.2036} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "summary", "avail_mib_before": 29506, "start": {"p50_ms": 198.8, "min_ms": 167.9, "p90_ms": 240.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 11.9, "sampled": 20, "answered": 20}} diff --git a/bench/baremetal/results/2026-10-30/run3.jsonl b/bench/baremetal/results/2026-10-30/run3.jsonl new file mode 100644 index 00000000..b958ef4b --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run3.jsonl @@ -0,0 +1,69 @@ +{"runtime": "kata", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 3.0435} +{"runtime": "kata", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 3.0027} +{"runtime": "kata", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 3.02} +{"runtime": "kata", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 3.0682} +{"runtime": "kata", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 3.0914} +{"runtime": "kata", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 2.9526} +{"runtime": "kata", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 2.9404} +{"runtime": "kata", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 3.0066} +{"runtime": "kata", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 2.9467} +{"runtime": "kata", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 2.9201} +{"runtime": "kata", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 2.9961} +{"runtime": "kata", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 2.9455} +{"runtime": "kata", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 3.0552} +{"runtime": "kata", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 2.9429} +{"runtime": "kata", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 2.9662} +{"runtime": "kata", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 3.0086} +{"runtime": "kata", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 2.9447} +{"runtime": "kata", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 3.123} +{"runtime": "kata", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 3.085} +{"runtime": "kata", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 3.0589} +{"runtime": "kata", "app": "web", "kind": "start_failed", "n": 81, "error": "Command '('docker', 'run', '-d', '--network', 'bridge', '--runtime', 'io.containerd.kata.v2', '-v', '/usr:/usr:ro', '-v', '/usr/lib:/lib:ro', '-v', '/usr/lib64:/lib64:ro', '-v', '/usr/bin:/bin:ro', '-v', '/usr/sbin:/sbin:ro', '-v', '/etc/alternatives:/etc/alternatives:ro', '-v', '/root/rootfs/app:/app:ro', 'bench-base:latest', '/usr/bin/python3', '/app/web.py')' returned non-zero exit status 125."} +{"runtime": "kata", "app": "web", "kind": "summary", "avail_mib_before": 30521, "memory": {"kept": 81, "per_instance_mib": 223.3, "sampled": 20, "answered": 20, "stopped_by": "Command '('docker', 'run', '-d', '--network', 'bridge', '--runtime', 'io.containerd.kata.v2', '-v', '/usr:/usr:ro', '-v', '/usr/lib:/lib:ro', '-v', '/usr/lib64:/lib64:ro', '-v', '/usr/bin:/bin:ro', '-v', '/usr/sbin:/sbin:ro', '-v', '/etc/alternatives:/etc/alternatives:ro', '-v', '/root/rootfs/app:/app:ro', 'bench-base:latest', '/usr/bin/python3', '/app/web.py')' returned non-zero exit status 125."}} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 3.5192} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 3.3104} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 3.2913} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 3.2948} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 3.203} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 3.403} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 3.2599} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 3.2076} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 3.3729} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 3.2483} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 3.2315} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 3.2621} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 3.4261} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 3.2825} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 3.2576} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 3.6681} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 3.6009} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 3.2487} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 3.5189} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 3.4131} +{"runtime": "kata", "app": "app64", "kind": "never_answered", "n": 56} +{"runtime": "kata", "app": "app64", "kind": "start_failed", "n": 57, "error": "nd '('docker', 'run', '-d', '--network', 'bridge', '--runtime', 'io.containerd.kata.v2', '-v', '/usr:/usr:ro', '-v', '/usr/lib:/lib:ro', '-v', '/usr/lib64:/lib64:ro', '-v', '/usr/bin:/bin:ro', '-v', '/usr/sbin:/sbin:ro', '-v', '/etc/alternatives:/etc/alternatives:ro', '-v', '/root/rootfs/app:/app:ro', 'bench-base:latest', '/usr/bin/python3', '/app/srv.py', '64')' returned non-zero exit status 125."} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 3.2193} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 3.192} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 3.6016} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 3.3477} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 3.49} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 3.5579} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 3.4207} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 3.3316} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 3.3116} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 3.5168} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 3.3561} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 3.3822} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 3.1646} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 3.3041} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 3.4798} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 3.4923} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 3.5618} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 3.3362} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 3.4121} +{"runtime": "kata", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 3.4984} +{"runtime": "kata", "app": "app64", "kind": "never_answered", "n": 56} +{"runtime": "kata", "app": "app64", "kind": "start_failed", "n": 57, "error": "nd '('docker', 'run', '-d', '--network', 'bridge', '--runtime', 'io.containerd.kata.v2', '-v', '/usr:/usr:ro', '-v', '/usr/lib:/lib:ro', '-v', '/usr/lib64:/lib64:ro', '-v', '/usr/bin:/bin:ro', '-v', '/usr/sbin:/sbin:ro', '-v', '/etc/alternatives:/etc/alternatives:ro', '-v', '/root/rootfs/app:/app:ro', 'bench-base:latest', '/usr/bin/python3', '/app/srv.py', '64')' returned non-zero exit status 125."} +{"runtime": "kata", "kind": "cleanup_failed", "error": "docker rm failed: 6ac878f2\": could not kill container: tried to kill container, but did not receive an exit event\nError response from daemon: cannot remove container \"0e174e68507450b6d5b6930e1c678a5a77716f479ec6b7b8ca6c1337e3721be1\": could not kill container: tried to kill container, but did not receive an exit event"} +{"runtime": "kata", "app": "app64", "kind": "summary", "avail_mib_before": 30530, "start": {"p50_ms": 3397.1, "min_ms": 3164.6, "p90_ms": 3561.8, "failed": 0}, "memory": {"kept": 57, "per_instance_mib": 307.8, "sampled": 20, "answered": 0, "stopped_by": "nd '('docker', 'run', '-d', '--network', 'bridge', '--runtime', 'io.containerd.kata.v2', '-v', '/usr:/usr:ro', '-v', '/usr/lib:/lib:ro', '-v', '/usr/lib64:/lib64:ro', '-v', '/usr/bin:/bin:ro', '-v', '/usr/sbin:/sbin:ro', '-v', '/etc/alternatives:/etc/alternatives:ro', '-v', '/root/rootfs/app:/app:ro', 'bench-base:latest', '/usr/bin/python3', '/app/srv.py', '64')' returned non-zero exit status 125."}} +{"runtime": "kata", "app": "app64", "kind": "summary", "avail_mib_before": 30365, "memory": {"kept": 40, "per_instance_mib": 310.5, "sampled": 20, "answered": 20}} diff --git a/bench/baremetal/results/2026-10-30/run4.jsonl b/bench/baremetal/results/2026-10-30/run4.jsonl new file mode 100644 index 00000000..30d5658e --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run4.jsonl @@ -0,0 +1,42 @@ +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.0756} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.0748} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.0701} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.0734} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.0748} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.0671} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.0639} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.0958} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.0678} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.0651} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.0668} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.069} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.0737} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.0859} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.0705} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.0815} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.0841} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.0849} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.0681} +{"runtime": "cubesandbox", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.0673} +{"runtime": "cubesandbox", "app": "web", "kind": "summary", "avail_mib_before": 24790, "start": {"p50_ms": 72.0, "min_ms": 63.9, "p90_ms": 85.9, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 8.9, "sampled": 20, "answered": 20}} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.0791} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.0698} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.0787} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.0799} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.0856} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.0991} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.0699} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.0773} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.0797} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.078} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.0763} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.0797} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.0792} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.0913} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.0736} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.0683} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.07} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.0736} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.0679} +{"runtime": "cubesandbox", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.0934} +{"runtime": "cubesandbox", "app": "app64", "kind": "summary", "avail_mib_before": 24973, "start": {"p50_ms": 78.3, "min_ms": 67.9, "p90_ms": 93.4, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 12.2, "sampled": 20, "answered": 20}} diff --git a/bench/baremetal/setup.sh b/bench/baremetal/setup.sh new file mode 100644 index 00000000..83ba85b2 --- /dev/null +++ b/bench/baremetal/setup.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# Puts what compare.py measures on one machine with KVM (Ubuntu 24.04). Run as +# root from a checkout, after: +# - apt: python3-numpy docker.io bubblewrap podman xfsprogs debootstrap +# - runsc, firecracker and a Firecracker guest vmlinux on the PATH and at +# /var/lib/sandstorm/vmlinux; msb and libkrunfw for microsandbox +# - `cargo build --release -p sandstorm-core` +# - /root/rootfs: `debootstrap --variant=minbase +# --include=python3,python3-numpy,ca-certificates,iproute2,procps noble` +# with bench/fleet/apps copied to /root/rootfs/app +# +# Two Sandstorm nodes, one per backend, each a master and node in one +# process: runsc on 127.0.0.1:18080 in /var/lib/sst-gvisor, Firecracker on +# :18081 in /var/lib/sst-fc (XFS, which it requires). Both with templates +# web and app64, plain and warm, at the memory limits the fleet runs used. +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +REPO="$(cd "$HERE/../.." && pwd)" +BIN="$REPO/target/release/sandstormd" +ROOTFS=/root/rootfs +APPS="web:128 app64:224" +# Extra flags for both nodes. To keep every sandbox hot, as the other runtimes +# keep their instances, for a memory comparison: +# SANDSTORM_FLAGS="--idle-frozen-secs 86400 --idle-snapshot-secs 86400 +# --idle-detached-secs 86400 --reclaim-hot off --reclaim-frozen off" +SANDSTORM_FLAGS=${SANDSTORM_FLAGS:-} + +# The guest's hostname has to resolve without DNS: Python's HTTPServer looks +# it up before it listens, and no sandbox here reaches a resolver, so it +# waited out the timeout -- 20 s per sandbox on bm. runsc writes /etc/hosts +# itself; a VM's init has to. +HOSTS_FIX='echo sandbox > /proc/sys/kernel/hostname +printf "127.0.0.1 localhost\n127.0.1.1 sandbox\n" > /etc/hosts' + +serve() { # name port workdir extra-args... + local name=$1 port=$2 dir=$3; shift 3 + systemctl stop "$name" 2>/dev/null || true + systemd-run --unit "$name" --collect -p KillMode=process "$BIN" serve --master --node \ + --bind "127.0.0.1:$port" --state-db "$dir/state.db" --pki-dir "$dir/pki" --work-dir "$dir" \ + --node-id "$name" "$@" >/dev/null + for _ in $(seq 1 60); do [ -s "$dir/pki/api-token" ] && curl -s -o /dev/null --cacert "$dir/pki/ca.pem" "https://127.0.0.1:$port/" && break; sleep 1; done +} + +register() { # port dir name args mem warm + local body="{\"name\":\"$3\",\"rootfs\":\"rootfs\",\"spec\":{\"args\":$4,\"memory_max_mib\":$5$6}}" + curl -s -o /dev/null -w "$3 %{http_code}\n" --cacert "$2/pki/ca.pem" \ + -H "authorization: Bearer $(cat "$2/pki/api-token")" -H 'content-type: application/json' \ + -X POST --data-raw "$body" "https://127.0.0.1:$1/v1/templates" +} + +args_of() { + case $1 in + web) echo '["/usr/bin/python3","/app/web.py"]' ;; + app*) echo "[\"/usr/bin/python3\",\"/app/srv.py\",\"${1#app}\"]" ;; + esac +} + +# --- Sandstorm on runsc: the fleet's templates, the host's /usr bound in ------- +G=/var/lib/sst-gvisor +mkdir -p "$G" +for app in $APPS; do + name=${app%%:*} + for t in "$name" "$name-warm"; do + r=$G/templates/$t/rootfs + mkdir -p $r/proc $r/dev $r/sys $r/tmp $r/etc/alternatives $r/var $r/root $r/app $r/usr $r/lib $r/lib64 $r/bin $r/sbin + printf 'root:x:0:0:root:/root:/bin/sh\n' > $r/etc/passwd + cp "$ROOTFS"/app/*.py $r/app/ + cp -a /etc/alternatives/lib*.so* $r/etc/alternatives/ 2>/dev/null || true + done +done +# Two nodes on one machine allocate gateway ports from the same default range, +# so each gets its own: on the same port the second one's sandbox never binds. +serve sst-gvisor 18080 "$G" --port-min 21000 --port-max 25999 $SANDSTORM_FLAGS +for app in $APPS; do + name=${app%%:*} mem=${app##*:} + register 18080 "$G" "$name" "$(args_of "$name")" "$mem" "" + register 18080 "$G" "$name-warm" "$(args_of "$name")" "$mem" ',"warm":{}' +done + +# --- Sandstorm on Firecracker: the same rootfs as an ext4 image ------------------ +F=/var/lib/sst-fc +if ! mountpoint -q "$F"; then + mkdir -p "$F" + [ -f /var/lib/sst-fc.xfs ] || { fallocate -l 80G /var/lib/sst-fc.xfs; mkfs.xfs -q -m reflink=1 /var/lib/sst-fc.xfs; } + mount -o loop /var/lib/sst-fc.xfs "$F" +fi +img=$(mktemp -d) +cp -a "$ROOTFS"/. "$img"/ +install -m755 "$REPO/rootfs-init/sandstorm-init.sh" "$img/sandstorm-init.sh" +install -m644 "$REPO/rootfs-init/sandstorm-agent.py" "$img/sandstorm-agent.py" +python3 - "$img/sandstorm-init.sh" "$HOSTS_FIX" <<'PY' +import sys +p, fix = sys.argv[1], sys.argv[2] +s = open(p).read() +if "/etc/hosts" not in s: + s = s.replace('echo "sandstorm-init: launching agent..."', fix + '\necho "sandstorm-init: launching agent..."') +open(p, "w").write(s) +PY +rm -f /root/tpl.ext4; truncate -s 2G /root/tpl.ext4; mkfs.ext4 -q -d "$img" /root/tpl.ext4; rm -rf "$img" +for app in $APPS; do + name=${app%%:*} + for t in "$name" "$name-warm"; do mkdir -p "$F/templates/$t"; cp --sparse=always /root/tpl.ext4 "$F/templates/$t/rootfs.ext4"; done +done +# Warm images hold the init they booted with; a new one means new images. +rm -rf "$F/warm" "$G/warm" +serve sst-fc 18081 "$F" --backend firecracker --fc-kernel /var/lib/sandstorm/vmlinux --port-min 26000 --port-max 31999 $SANDSTORM_FLAGS +for app in $APPS; do + name=${app%%:*} mem=${app##*:} + register 18081 "$F" "$name" "$(args_of "$name")" "$mem" "" + register 18081 "$F" "$name-warm" "$(args_of "$name")" "$mem" ',"warm":{}' +done + +# --- microsandbox: an image per program from the same rootfs --------------------- +if command -v msb >/dev/null; then + systemctl start docker + for app in $APPS; do + name=${app%%:*} + cmd=$(args_of "$name" | python3 -c 'import json,sys; print(" ".join(json.load(sys.stdin)))') + tar -C "$ROOTFS" -c . | docker import \ + --change "CMD [\"/bin/sh\",\"-c\",\"echo 127.0.1.1 \$(hostname) >> /etc/hosts; exec $cmd\"]" - "sst-$name:latest" >/dev/null + docker save "sst-$name:latest" -o "/root/sst-$name.tar" + msb load -i "/root/sst-$name.tar" >/dev/null 2>&1 || msb load "/root/sst-$name.tar" + done + systemctl stop docker.socket docker.service containerd.service +fi +echo setup done From 16de51981a54427ccd2dd93472f4589fa81820fd Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 12:50:06 +0800 Subject: [PATCH 2/7] bench(baremetal): Sandstorm Firecracker after soft-dirty snapshots and the pool fix Warm start 129/199 -> 62/74 ms (web/app64), ahead of CubeSandbox's 72/78; snapshot 52 -> 27 ms; clone 20 ~1,562 -> ~980 ms. Co-Authored-By: Claude Opus 5.5 --- bench/baremetal/results/2026-10-30/README.md | 28 +++++++------ bench/baremetal/results/2026-10-30/fork.jsonl | 1 + bench/baremetal/results/2026-10-30/run5.jsonl | 42 +++++++++++++++++++ 3 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 bench/baremetal/results/2026-10-30/run5.jsonl diff --git a/bench/baremetal/results/2026-10-30/README.md b/bench/baremetal/results/2026-10-30/README.md index e099b241..9ea5343e 100644 --- a/bench/baremetal/results/2026-10-30/README.md +++ b/bench/baremetal/results/2026-10-30/README.md @@ -6,7 +6,7 @@ One machine, every runtime on it in turn, the same two programs, the same harnes - **Programs:** `web`, a Python HTTP server, and `app64`, which holds a 64 MiB numpy heap and reads all of it on every request (`bench/fleet/apps`). - **Start:** one instance at a time, from the call that starts it to its first 200, polled every 5 ms; 20 after one warm-up; p50. - **Memory:** 100 instances kept running, each answering before the next starts; 30 s to settle; MemAvailable before and after, divided by the count; then 20 of them called at random. Nothing is tiered or paused in this table: Sandstorm ran with `--idle-frozen-secs 86400 --reclaim-hot off --reclaim-frozen off`, so its sandboxes stayed hot like everyone else's. -- **Harness:** [`compare.py`](../../compare.py), [`setup.sh`](../../setup.sh), [`fork.py`](../../fork.py), [`fork_msb.py`](../../fork_msb.py), [`fork_cube.py`](../../fork_cube.py). Raw rows: `run1.jsonl` (the runtimes that are not Sandstorm, plus microsandbox), `run2.jsonl` (Sandstorm), `run3.jsonl` (Kata), `run4.jsonl` (CubeSandbox), `fork.jsonl`. +- **Harness:** [`compare.py`](../../compare.py), [`setup.sh`](../../setup.sh), [`fork.py`](../../fork.py), [`fork_msb.py`](../../fork_msb.py), [`fork_cube.py`](../../fork_cube.py). Raw rows: `run1.jsonl` (the runtimes that are not Sandstorm, plus microsandbox), `run2.jsonl` (Sandstorm), `run3.jsonl` (Kata), `run4.jsonl` (CubeSandbox), `run5.jsonl` (Sandstorm Firecracker, warm, after deeplethe/sandstorm#380), `fork.jsonl` (the last `sandstorm-fc` row is the one below). ## Start and memory @@ -21,14 +21,15 @@ One machine, every runtime on it in turn, the same two programs, the same harnes | **Sandstorm, gVisor, warm template** | gVisor | **168 / 186 ms** | 24.3 / 97.8 MiB | | Kata 4.2 (runtime-rs, QEMU) | VM | 3,005 / 3,397 ms | 223 / 311 MiB¹ | | microsandbox 0.7.8 (libkrun) | VM | 1,117 / 1,119 ms | 80.2 / 166.2 MiB | -| CubeSandbox 0.7.3 | VM | **72 / 78 ms** | **8.9 / 12.2 MiB** | +| CubeSandbox 0.7.3 | VM | 72 / 78 ms | **8.9** / 12.2 MiB | | **Sandstorm, Firecracker** | VM | 636 / 964 ms² | 80.0 / 166.1 MiB | -| **Sandstorm, Firecracker, warm template** | VM | 129 / 199 ms | 10.8 / 11.9 MiB | +| **Sandstorm, Firecracker, warm template** | VM | **62 / 74 ms**³ | 9.9 / **10.5 MiB**³ | Every runtime answered 20 of 20 when sampled. ¹ Kata keeps every guest's memory in shared memory for virtio-fs, so `/dev/shm` (16 GB here) is its ceiling: 81 `web` guests, 57 `app64`. Past it a new guest fails to start, and at 57 `app64` none of the 20 sampled answered; its figure is from 40. ² After the fixes in deeplethe/sandstorm#380, each measured on its own: 1,953 / 2,120 ms before them. `run2.jsonl` has 868 / 1,174 ms, measured before the last two (`quiet`, the agent starting the program first). +³ `run5.jsonl`, with all of deeplethe/sandstorm#380. `run2.jsonl` has 129 / 199 ms and 10.8 / 11.9 MiB from before it. Every CubeSandbox and warm Sandstorm sandbox starts from a snapshot of the program already running, and maps that memory privately, so a page only costs a sandbox once it writes it. `app64` only reads its heap after starting, which is why it costs those two barely more than `web`; a program that rewrote its heap would cost more. @@ -38,22 +39,21 @@ The source is a running `app64` started from a template; polled every 5 ms. | p50 | Sandstorm, Firecracker | Sandstorm, gVisor | CubeSandbox | microsandbox³ | |---|---:|---:|---:|---:| -| snapshot a running sandbox | **52 ms** | 368 ms | 252 ms | — | -| start 1 from the snapshot, to its first answer | 135 ms | 138 ms | 133 ms | — | -| clone 1: snapshot, then start | **~187 ms** | ~506 ms | 542 ms | 658 ms | -| clone 10, until all answer | ~883 ms | ~1,530 ms | 973 ms | 835 ms | -| clone 20, until all answer | ~1,562 ms | ~2,760 ms | **1,046 ms** | 1,152 ms | +| snapshot a running sandbox | **27 ms** | 368 ms | 252 ms | — | +| start 1 from the snapshot, to its first answer | **110 ms** | 138 ms | 133 ms | — | +| clone 1: snapshot, then start | **~137 ms** | ~506 ms | 542 ms | 658 ms | +| clone 10, until all answer | **~528 ms** | ~1,530 ms | 973 ms | 835 ms | +| clone 20, until all answer | **~980 ms** | ~2,760 ms | 1,046 ms | 1,152 ms | -Sandstorm's clone is `branch` then one fork call with `n`, so the sum is approximate. CubeSandbox's is its SDK's `clone(n, concurrency=n)`: a snapshot, then n creates at once (0.7.3 has no `/fork`). +Sandstorm's clone is `branch` then one fork call with `n`, so the sum is approximate. Its snapshot was 14-34 ms over six; one run straight after the 100-instance memory run, with the host still writing back, had 41-52. CubeSandbox's is its SDK's `clone(n, concurrency=n)`: a snapshot, then n creates at once (0.7.3 has no `/fork`). ³ `msb fork` copies a running sandbox in one step. Its children get no port forward and cannot be called from the host, so its time is until `msb fork` returns with them running, not until they answer; each was checked from inside afterwards. ## What it says -- **Against the other VM runtimes,** a warm Sandstorm Firecracker sandbox starts 8× faster than microsandbox and 23× faster than Kata, in a seventh to a twentieth of the memory. Cold, it is still faster than both. +- **Against CubeSandbox,** the fastest of the rest: a warm Sandstorm Firecracker sandbox starts faster (62 against 72 ms for `web`, 74 against 78 for `app64`) in about the same memory (9.9 / 10.5 against 8.9 / 12.2 MiB). It snapshots a running sandbox 9× faster, clones one 4× faster, and clones 10 and 20 faster too. +- **Against the other VM runtimes,** it starts 15-18× faster than microsandbox and 46-48× faster than Kata, in an eighth to a thirtieth of the memory. Cold, it is still faster than both. - **Against Docker with gVisor,** the same isolation, Sandstorm on gVisor starts a little faster cold, twice as fast warm, and holds 10-20% less per instance. -- **Against CubeSandbox,** Sandstorm snapshots a running sandbox 5× faster and clones one 3× faster. Starting one from a snapshot is level, and so is memory. CubeSandbox starts a sandbox from its template faster (72 against 129 ms for `web`, 78 against 199 for `app64`) and clones 20 faster (1,046 against ~1,562 ms). -- On the 2025 EPYC in the earlier bm run, Sandstorm's warm `web` start was 52 ms against CubeSandbox's 55. On this 2013 Xeon it is 129 against 72: something on Sandstorm's warm path is far more sensitive to an old CPU than CubeSandbox's, not yet found. -- A fork of n children is created one after another on the node, about 65 ms each; CubeSandbox and microsandbox create them in parallel. +- A fork of n children is created one after another on the node, about 50 ms each; CubeSandbox and microsandbox create them in parallel, which is where they would gain on a larger n. ## Found and fixed on the way @@ -64,6 +64,8 @@ All in deeplethe/sandstorm#380: - A fixed tap MAC, without which pinning the guest's neighbour entry made every warm start 43 s. - A guest hostname that resolves without DNS, which cost 20 s per Firecracker sandbox on bm. - Two master-and-node processes on one machine sharing gateway ports: the second now refuses to start. +- KVM dirty logging on every restored VM, kept so its next snapshot could be a diff, which made each page the guest touched first fault in on its own: warm `app64` 103 → 67 ms. Writes are now tracked with the kernel's soft-dirty bits, as CubeSandbox does, and a snapshot copies just those pages: 52 → 27 ms. +- The netns pool's refill waited for a quiet spell that back-to-back starts never leave, until the pool was empty: from the 33rd start on, 185-236 ms. It now refills in time, and reuses a destroyed sandbox's namespace (its conntrack table flushed) rather than building one under load. ## Not covered diff --git a/bench/baremetal/results/2026-10-30/fork.jsonl b/bench/baremetal/results/2026-10-30/fork.jsonl index 2b4b615d..c3e351a4 100644 --- a/bench/baremetal/results/2026-10-30/fork.jsonl +++ b/bench/baremetal/results/2026-10-30/fork.jsonl @@ -1,3 +1,4 @@ {"runtime": "sandstorm-fc", "kind": "fork", "template": "app64-warm", "snapshot_ms": 52.5, "snapshot_all_ms": [71, 65, 53, 37, 46, 76], "fork1_ms": 135.1, "fork10_wall_ms": 830.7, "fork20_wall_ms": 1510.3, "fork10_rounds_ms": [831, 859, 805], "fork20_rounds_ms": [1527, 1504, 1510]} {"runtime": "sandstorm-gvisor", "kind": "fork", "template": "app64-warm", "snapshot_ms": 368.3, "snapshot_all_ms": [398, 487, 339, 363, 376, 368], "fork1_ms": 137.6, "fork10_wall_ms": 1161.4, "fork20_wall_ms": 2391.2, "fork10_rounds_ms": [1161, 1187, 1147], "fork20_rounds_ms": [2511, 2376, 2391]} {"runtime": "microsandbox", "kind": "fork", "template": "app64", "measured_to": "msb fork returns", "fork1_ms": 658.2, "fork1_children_answering": "11/11", "fork10_wall_ms": 834.9, "fork20_wall_ms": 1151.5, "fork10_rounds_ms": [800, 835, 930], "fork20_rounds_ms": [1066, 1152, 1259], "batch_children_checked_failed": 0} +{"runtime": "sandstorm-fc", "kind": "fork", "template": "app64-warm", "snapshot_ms": 27.3, "snapshot_all_ms": [32, 27, 34, 28, 20, 14], "fork1_ms": 109.6, "fork10_wall_ms": 501.0, "fork20_wall_ms": 952.9, "fork10_rounds_ms": [501, 511, 494], "fork20_rounds_ms": [953, 952, 976]} diff --git a/bench/baremetal/results/2026-10-30/run5.jsonl b/bench/baremetal/results/2026-10-30/run5.jsonl new file mode 100644 index 00000000..ac82fe1a --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run5.jsonl @@ -0,0 +1,42 @@ +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.0652} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.0609} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.0563} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.0794} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.0698} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.0734} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.0763} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.0626} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.0744} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.063} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.0527} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.0542} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.0606} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.0587} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.0564} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.0644} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.063} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.0589} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.059} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.06} +{"runtime": "sandstorm-fc-warm", "app": "web", "kind": "summary", "avail_mib_before": 26678, "start": {"p50_ms": 61.7, "min_ms": 52.7, "p90_ms": 76.3, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 9.9, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.0843} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.08} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.0734} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.0715} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.0742} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.0831} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.0683} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.0687} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1081} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.0708} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.0663} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.0697} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.0821} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.0676} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.0753} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.0763} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.0955} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.0828} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.0677} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.0638} +{"runtime": "sandstorm-fc-warm", "app": "app64", "kind": "summary", "avail_mib_before": 26668, "start": {"p50_ms": 73.8, "min_ms": 63.8, "p90_ms": 95.5, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 10.5, "sampled": 20, "answered": 20}} From 09295ca8ae7947a4512e7326424a35799fe0d1c8 Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 12:57:49 +0800 Subject: [PATCH 3/7] bench(baremetal): Sandstorm gVisor re-measured with #380 Cold 308/624 -> 234/545 ms, warm 168/186 -> 107/123 ms (web/app64); clone 20 ~2,760 -> ~2,280 ms. Co-Authored-By: Claude Opus 5.5 --- bench/baremetal/results/2026-10-30/README.md | 19 +++-- bench/baremetal/results/2026-10-30/fork.jsonl | 1 + bench/baremetal/results/2026-10-30/run6.jsonl | 84 +++++++++++++++++++ 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 bench/baremetal/results/2026-10-30/run6.jsonl diff --git a/bench/baremetal/results/2026-10-30/README.md b/bench/baremetal/results/2026-10-30/README.md index 9ea5343e..a114206d 100644 --- a/bench/baremetal/results/2026-10-30/README.md +++ b/bench/baremetal/results/2026-10-30/README.md @@ -6,7 +6,7 @@ One machine, every runtime on it in turn, the same two programs, the same harnes - **Programs:** `web`, a Python HTTP server, and `app64`, which holds a 64 MiB numpy heap and reads all of it on every request (`bench/fleet/apps`). - **Start:** one instance at a time, from the call that starts it to its first 200, polled every 5 ms; 20 after one warm-up; p50. - **Memory:** 100 instances kept running, each answering before the next starts; 30 s to settle; MemAvailable before and after, divided by the count; then 20 of them called at random. Nothing is tiered or paused in this table: Sandstorm ran with `--idle-frozen-secs 86400 --reclaim-hot off --reclaim-frozen off`, so its sandboxes stayed hot like everyone else's. -- **Harness:** [`compare.py`](../../compare.py), [`setup.sh`](../../setup.sh), [`fork.py`](../../fork.py), [`fork_msb.py`](../../fork_msb.py), [`fork_cube.py`](../../fork_cube.py). Raw rows: `run1.jsonl` (the runtimes that are not Sandstorm, plus microsandbox), `run2.jsonl` (Sandstorm), `run3.jsonl` (Kata), `run4.jsonl` (CubeSandbox), `run5.jsonl` (Sandstorm Firecracker, warm, after deeplethe/sandstorm#380), `fork.jsonl` (the last `sandstorm-fc` row is the one below). +- **Harness:** [`compare.py`](../../compare.py), [`setup.sh`](../../setup.sh), [`fork.py`](../../fork.py), [`fork_msb.py`](../../fork_msb.py), [`fork_cube.py`](../../fork_cube.py). Raw rows: `run1.jsonl` (the runtimes that are not Sandstorm, plus microsandbox), `run2.jsonl` (Sandstorm), `run3.jsonl` (Kata), `run4.jsonl` (CubeSandbox), `run5.jsonl` (Sandstorm Firecracker, warm) and `run6.jsonl` (Sandstorm gVisor), both with all of deeplethe/sandstorm#380, `fork.jsonl` (the last row of each Sandstorm backend is the one below). ## Start and memory @@ -17,8 +17,8 @@ One machine, every runtime on it in turn, the same two programs, the same harnes | Docker (runc) | namespaces | 256 / 414 ms | 15.2 / 88.5 MiB | | Podman (crun) | namespaces | 296 / 429 ms | 10.8 / 84.0 MiB | | Docker + gVisor | gVisor | 327 / 660 ms | 30.8 / 106.8 MiB | -| **Sandstorm, gVisor** | gVisor | **308 / 624 ms** | **24.0 / 97.2 MiB** | -| **Sandstorm, gVisor, warm template** | gVisor | **168 / 186 ms** | 24.3 / 97.8 MiB | +| **Sandstorm, gVisor** | gVisor | **234 / 545 ms**⁴ | **24.1 / 97.9 MiB** | +| **Sandstorm, gVisor, warm template** | gVisor | **107 / 123 ms**⁴ | 23.3 / 97.3 MiB | | Kata 4.2 (runtime-rs, QEMU) | VM | 3,005 / 3,397 ms | 223 / 311 MiB¹ | | microsandbox 0.7.8 (libkrun) | VM | 1,117 / 1,119 ms | 80.2 / 166.2 MiB | | CubeSandbox 0.7.3 | VM | 72 / 78 ms | **8.9** / 12.2 MiB | @@ -30,6 +30,7 @@ Every runtime answered 20 of 20 when sampled. ¹ Kata keeps every guest's memory in shared memory for virtio-fs, so `/dev/shm` (16 GB here) is its ceiling: 81 `web` guests, 57 `app64`. Past it a new guest fails to start, and at 57 `app64` none of the 20 sampled answered; its figure is from 40. ² After the fixes in deeplethe/sandstorm#380, each measured on its own: 1,953 / 2,120 ms before them. `run2.jsonl` has 868 / 1,174 ms, measured before the last two (`quiet`, the agent starting the program first). ³ `run5.jsonl`, with all of deeplethe/sandstorm#380. `run2.jsonl` has 129 / 199 ms and 10.8 / 11.9 MiB from before it. +⁴ `run6.jsonl`, with all of deeplethe/sandstorm#380. `run2.jsonl` has 308 / 624 ms cold and 168 / 186 ms warm from before it. Every CubeSandbox and warm Sandstorm sandbox starts from a snapshot of the program already running, and maps that memory privately, so a page only costs a sandbox once it writes it. `app64` only reads its heap after starting, which is why it costs those two barely more than `web`; a program that rewrote its heap would cost more. @@ -39,11 +40,11 @@ The source is a running `app64` started from a template; polled every 5 ms. | p50 | Sandstorm, Firecracker | Sandstorm, gVisor | CubeSandbox | microsandbox³ | |---|---:|---:|---:|---:| -| snapshot a running sandbox | **27 ms** | 368 ms | 252 ms | — | -| start 1 from the snapshot, to its first answer | **110 ms** | 138 ms | 133 ms | — | -| clone 1: snapshot, then start | **~137 ms** | ~506 ms | 542 ms | 658 ms | -| clone 10, until all answer | **~528 ms** | ~1,530 ms | 973 ms | 835 ms | -| clone 20, until all answer | **~980 ms** | ~2,760 ms | 1,046 ms | 1,152 ms | +| snapshot a running sandbox | **27 ms** | 342 ms | 252 ms | — | +| start 1 from the snapshot, to its first answer | **110 ms** | 117 ms | 133 ms | — | +| clone 1: snapshot, then start | **~137 ms** | ~459 ms | 542 ms | 658 ms | +| clone 10, until all answer | **~528 ms** | ~1,340 ms | 973 ms | 835 ms | +| clone 20, until all answer | **~980 ms** | ~2,280 ms | 1,046 ms | 1,152 ms | Sandstorm's clone is `branch` then one fork call with `n`, so the sum is approximate. Its snapshot was 14-34 ms over six; one run straight after the 100-instance memory run, with the host still writing back, had 41-52. CubeSandbox's is its SDK's `clone(n, concurrency=n)`: a snapshot, then n creates at once (0.7.3 has no `/fork`). ³ `msb fork` copies a running sandbox in one step. Its children get no port forward and cannot be called from the host, so its time is until `msb fork` returns with them running, not until they answer; each was checked from inside afterwards. @@ -52,7 +53,7 @@ Sandstorm's clone is `branch` then one fork call with `n`, so the sum is approxi - **Against CubeSandbox,** the fastest of the rest: a warm Sandstorm Firecracker sandbox starts faster (62 against 72 ms for `web`, 74 against 78 for `app64`) in about the same memory (9.9 / 10.5 against 8.9 / 12.2 MiB). It snapshots a running sandbox 9× faster, clones one 4× faster, and clones 10 and 20 faster too. - **Against the other VM runtimes,** it starts 15-18× faster than microsandbox and 46-48× faster than Kata, in an eighth to a thirtieth of the memory. Cold, it is still faster than both. -- **Against Docker with gVisor,** the same isolation, Sandstorm on gVisor starts a little faster cold, twice as fast warm, and holds 10-20% less per instance. +- **Against Docker with gVisor,** the same isolation, Sandstorm on gVisor starts 1.2-1.4× faster cold (234 / 545 against 327 / 660 ms), 3-5× faster from a warm template (107 / 123 ms), and holds 8-24% less per instance. - A fork of n children is created one after another on the node, about 50 ms each; CubeSandbox and microsandbox create them in parallel, which is where they would gain on a larger n. ## Found and fixed on the way diff --git a/bench/baremetal/results/2026-10-30/fork.jsonl b/bench/baremetal/results/2026-10-30/fork.jsonl index c3e351a4..0b8249ec 100644 --- a/bench/baremetal/results/2026-10-30/fork.jsonl +++ b/bench/baremetal/results/2026-10-30/fork.jsonl @@ -2,3 +2,4 @@ {"runtime": "sandstorm-gvisor", "kind": "fork", "template": "app64-warm", "snapshot_ms": 368.3, "snapshot_all_ms": [398, 487, 339, 363, 376, 368], "fork1_ms": 137.6, "fork10_wall_ms": 1161.4, "fork20_wall_ms": 2391.2, "fork10_rounds_ms": [1161, 1187, 1147], "fork20_rounds_ms": [2511, 2376, 2391]} {"runtime": "microsandbox", "kind": "fork", "template": "app64", "measured_to": "msb fork returns", "fork1_ms": 658.2, "fork1_children_answering": "11/11", "fork10_wall_ms": 834.9, "fork20_wall_ms": 1151.5, "fork10_rounds_ms": [800, 835, 930], "fork20_rounds_ms": [1066, 1152, 1259], "batch_children_checked_failed": 0} {"runtime": "sandstorm-fc", "kind": "fork", "template": "app64-warm", "snapshot_ms": 27.3, "snapshot_all_ms": [32, 27, 34, 28, 20, 14], "fork1_ms": 109.6, "fork10_wall_ms": 501.0, "fork20_wall_ms": 952.9, "fork10_rounds_ms": [501, 511, 494], "fork20_rounds_ms": [953, 952, 976]} +{"runtime": "sandstorm-gvisor", "kind": "fork", "template": "app64-warm", "snapshot_ms": 341.5, "snapshot_all_ms": [385, 372, 349, 342, 329, 337], "fork1_ms": 116.5, "fork10_wall_ms": 998.6, "fork20_wall_ms": 1938.4, "fork10_rounds_ms": [971, 999, 1007], "fork20_rounds_ms": [2064, 1938, 1937]} diff --git a/bench/baremetal/results/2026-10-30/run6.jsonl b/bench/baremetal/results/2026-10-30/run6.jsonl new file mode 100644 index 00000000..5efbe541 --- /dev/null +++ b/bench/baremetal/results/2026-10-30/run6.jsonl @@ -0,0 +1,84 @@ +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.2396} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.2178} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.2693} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.2234} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.3191} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.2117} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.2433} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.245} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.2328} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.2256} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.2196} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.2182} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.264} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.316} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.2335} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.2351} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.2207} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.2202} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.318} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.2722} +{"runtime": "sandstorm-gvisor", "app": "web", "kind": "summary", "avail_mib_before": 26782, "start": {"p50_ms": 234.3, "min_ms": 211.7, "p90_ms": 318.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 24.1, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.539} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.494} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.5392} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.5355} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.4844} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.6341} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.5773} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.4742} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.5902} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.5823} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.6352} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.5259} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.5027} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.59} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.5398} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.5886} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.5493} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.5888} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.4813} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.5943} +{"runtime": "sandstorm-gvisor", "app": "app64", "kind": "summary", "avail_mib_before": 26502, "start": {"p50_ms": 544.6, "min_ms": 474.2, "p90_ms": 634.1, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 97.9, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 1, "start_to_answer_s": 0.0981} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 2, "start_to_answer_s": 0.1137} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 3, "start_to_answer_s": 0.1119} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 4, "start_to_answer_s": 0.1138} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 5, "start_to_answer_s": 0.1087} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 6, "start_to_answer_s": 0.0964} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 7, "start_to_answer_s": 0.0937} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 8, "start_to_answer_s": 0.0995} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 9, "start_to_answer_s": 0.1149} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 10, "start_to_answer_s": 0.1013} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 11, "start_to_answer_s": 0.1145} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 12, "start_to_answer_s": 0.1061} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 13, "start_to_answer_s": 0.0984} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 14, "start_to_answer_s": 0.1019} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 15, "start_to_answer_s": 0.0948} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 16, "start_to_answer_s": 0.1105} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 17, "start_to_answer_s": 0.106} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 18, "start_to_answer_s": 0.124} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 19, "start_to_answer_s": 0.1219} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "start", "n": 20, "start_to_answer_s": 0.1256} +{"runtime": "sandstorm-gvisor-warm", "app": "web", "kind": "summary", "avail_mib_before": 20203, "start": {"p50_ms": 107.4, "min_ms": 93.7, "p90_ms": 124.0, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 23.3, "sampled": 20, "answered": 20}} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 1, "start_to_answer_s": 0.1431} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 2, "start_to_answer_s": 0.1307} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 3, "start_to_answer_s": 0.1152} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 4, "start_to_answer_s": 0.1196} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 5, "start_to_answer_s": 0.1257} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 6, "start_to_answer_s": 0.107} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 7, "start_to_answer_s": 0.1216} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 8, "start_to_answer_s": 0.1269} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 9, "start_to_answer_s": 0.1346} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 10, "start_to_answer_s": 0.1201} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 11, "start_to_answer_s": 0.1096} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 12, "start_to_answer_s": 0.125} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 13, "start_to_answer_s": 0.1199} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 14, "start_to_answer_s": 0.1343} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 15, "start_to_answer_s": 0.1093} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 16, "start_to_answer_s": 0.132} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 17, "start_to_answer_s": 0.1417} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 18, "start_to_answer_s": 0.1077} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 19, "start_to_answer_s": 0.1118} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "start", "n": 20, "start_to_answer_s": 0.1329} +{"runtime": "sandstorm-gvisor-warm", "app": "app64", "kind": "summary", "avail_mib_before": 26594, "start": {"p50_ms": 123.3, "min_ms": 107.0, "p90_ms": 141.7, "failed": 0}, "memory": {"kept": 100, "per_instance_mib": 97.3, "sampled": 20, "answered": 20}} From bcef712b399cbc7d6711cbca398110fabcf3bc7b Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:01:57 +0800 Subject: [PATCH 4/7] docs(readme): bare-metal comparison against CubeSandbox, microsandbox, Kata and Docker, with two charts bench/baremetal/charts.py draws start-and-memory and clone charts from the results directory with the fleet charts' palette and primitives. CubeSandbox's clone row is added to fork.jsonl as fork_cube.py printed it. Co-Authored-By: Claude Opus 5.5 --- README-zh.md | 32 +++- README.md | 32 +++- bench/baremetal/charts.py | 172 ++++++++++++++++++ bench/baremetal/results/2026-10-30/fork.jsonl | 1 + docs/assets/charts/baremetal-clone-dark.svg | 52 ++++++ docs/assets/charts/baremetal-clone-light.svg | 52 ++++++ docs/assets/charts/baremetal-start-dark.svg | 63 +++++++ docs/assets/charts/baremetal-start-light.svg | 63 +++++++ 8 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 bench/baremetal/charts.py create mode 100644 docs/assets/charts/baremetal-clone-dark.svg create mode 100644 docs/assets/charts/baremetal-clone-light.svg create mode 100644 docs/assets/charts/baremetal-start-dark.svg create mode 100644 docs/assets/charts/baremetal-start-light.svg diff --git a/README-zh.md b/README-zh.md index 512a9c7b..f617400a 100644 --- a/README-zh.md +++ b/README-zh.md @@ -104,7 +104,37 @@ master 在 `/` 提供控制台:每个沙箱在哪一档、在各档之间流 Sandstorm 启动 64 MiB 应用的 289 ms 里,master 和建网络 37 ms,准备 bundle 5 ms,runsc 55 ms,剩下 189 ms 是 Python 导入 numpy、填充堆。预热模板直接恢复一个已经启动好的应用镜像,省掉了最后这段;它需要手动开启,因为每个沙箱都从同一份内存开始,模板要说明怎么重新播种随机数。50 ms 的轮询间隔是下限。 -Podman 下的 CRIU checkpoint/restore 是标准工具里最接近落盘档位的做法:64 MiB 应用落盘 0.3 s,恢复到首次响应 0.24 s;Sandstorm 恢复同一个应用要 0.2 s。E2B、CubeSandbox、microsandbox 都基于 Firecracker,需要 KVM,这几台云主机没有,所以没法在这里跑;同类项目的对比见 [docs/COMPARISON.md](docs/COMPARISON.md)。 +Podman 下的 CRIU checkpoint/restore 是标准工具里最接近落盘档位的做法:64 MiB 应用落盘 0.3 s,恢复到首次响应 0.24 s;Sandstorm 恢复同一个应用要 0.2 s。E2B、CubeSandbox、microsandbox 都基于 Firecracker,需要 KVM,这几台云主机没有;它们在下面一台有 KVM 的机器上测了,同类项目的对比见 [docs/COMPARISON.md](docs/COMPARISON.md)。 + +## 在有 KVM 的机器上,对比其他沙箱 + +
+ + + + 同一台 KVM 机器上 64 MiB 应用的启动到首次响应时间和单实例内存:Sandstorm Firecracker 预热模板 74 ms、10 MiB,CubeSandbox 78 ms、12 MiB,Sandstorm gVisor 预热模板 123 ms、97 MiB,Sandstorm gVisor 545 ms、98 MiB,Docker 414 ms、88 MiB,Docker + gVisor 660 ms、107 MiB,microsandbox 1.1 s、166 MiB,Kata 3.4 s、310 MiB + + + + + 把运行中的 64 MiB 应用克隆成 1、10、20 份并全部响应:Sandstorm Firecracker 137、528、980 ms;CubeSandbox 542、973、1,046 ms;microsandbox 658、835、1,152 ms(到运行);Sandstorm gVisor 458、1,340、2,280 ms + + +
+ +需要 KVM 的运行时,放在一台有 KVM 的机器上测:2 × Xeon E5-2637 v2、31 GB、Ubuntu 24.04。各运行时轮流跑,同样两个程序、同一个测试脚本([`compare.py`](bench/baremetal/compare.py))。在这里 Sandstorm 也可以把每个沙箱跑成 [Firecracker](https://firecracker-microvm.github.io) 微虚拟机(`--backend firecracker`);用预热模板时,它是所有被测项目里启动最快的,内存和 CubeSandbox 相当。 + +| p50 | web | 64 MiB 应用 | 内存,web / 64 MiB 应用 | +|---|---:|---:|---:| +| **Sandstorm,Firecracker,预热模板** | **62 ms** | **74 ms** | 9.9 / **10.5 MiB** | +| CubeSandbox 0.7.3 | 72 ms | 78 ms | **8.9** / 12.2 MiB | +| **Sandstorm,gVisor,预热模板** | 107 ms | 123 ms | 23.3 / 97.3 MiB | +| **Sandstorm,gVisor** | 234 ms | 545 ms | 24.1 / 97.9 MiB | +| Docker + gVisor | 327 ms | 660 ms | 30.8 / 106.8 MiB | +| microsandbox 0.7.8 | 1,117 ms | 1,119 ms | 80.2 / 166.2 MiB | +| Kata 4.2(QEMU) | 3,005 ms | 3,397 ms | 223 / 311 MiB | + +Sandstorm 在 Firecracker 上给运行中的沙箱打快照要 27 ms,CubeSandbox 要 252 ms;克隆 n 份就是这一次快照加一次 fork 调用。子沙箱在节点上逐个创建,每个约 50 ms,而 CubeSandbox 和 microsandbox 是同时创建,所以 n 更大时差距会缩小。E2B 自托管没有搭。方法、原始数据和测试中发现的问题见 [bench/baremetal/results/2026-10-30](bench/baremetal/results/2026-10-30/README.md)。 ## 实测数据 diff --git a/README.md b/README.md index b8907c9f..7d0151f0 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,37 @@ Starting, timed on one machine (bm: AMD EPYC 9K65, 2 vCPU, 3.6 GB; dev at 872682 Of Sandstorm's 289 ms for the 64 MiB app, 37 ms is the master and the network, 5 ms the bundle, 55 ms runsc and 189 ms Python importing numpy and filling its heap. A warm template restores an image of the app already started, so it skips that last part; it is opt-in, because every sandbox starts from the same memory and the template has to say how to reseed. The 50 ms poll is the floor. -Checkpoint and restore with CRIU under Podman, the nearest standard counterpart to the snapshot tier, takes 0.3 s to checkpoint a 64 MiB app and 0.24 s from restore to first answer; Sandstorm restores the same app in 0.2 s. E2B, CubeSandbox and microsandbox are built on Firecracker and need KVM, which these VMs do not have, so they could not be run here; [docs/COMPARISON.md](docs/COMPARISON.md) covers the field. +Checkpoint and restore with CRIU under Podman, the nearest standard counterpart to the snapshot tier, takes 0.3 s to checkpoint a 64 MiB app and 0.24 s from restore to first answer; Sandstorm restores the same app in 0.2 s. E2B, CubeSandbox and microsandbox are built on Firecracker and need KVM, which these VMs do not have; they are measured on a machine that has it below, and [docs/COMPARISON.md](docs/COMPARISON.md) covers the field. + +## On a KVM machine, against the other sandboxes + +
+ + + + The 64 MiB app on one KVM machine, start to first answer and memory per instance: Sandstorm on Firecracker from a warm template 74 ms and 10 MiB, CubeSandbox 78 ms and 12 MiB, Sandstorm on gVisor from a warm template 123 ms and 97 MiB, Sandstorm on gVisor 545 ms and 98 MiB, Docker 414 ms and 88 MiB, Docker with gVisor 660 ms and 107 MiB, microsandbox 1.1 s and 166 MiB, Kata 3.4 s and 310 MiB + + + + + Cloning a running 64 MiB app into 1, 10 and 20 copies that answer: Sandstorm on Firecracker 137, 528 and 980 ms; CubeSandbox 542, 973 and 1,046 ms; microsandbox 658, 835 and 1,152 ms to running; Sandstorm on gVisor 458, 1,340 and 2,280 ms + + +
+ +The runtimes that need KVM, run on one machine that has it: 2 × Xeon E5-2637 v2, 31 GB, Ubuntu 24.04. Every runtime in turn, the same two programs and the same harness ([`compare.py`](bench/baremetal/compare.py)). There Sandstorm can also run each sandbox as a [Firecracker](https://firecracker-microvm.github.io) microVM (`--backend firecracker`), and from a warm template that is the fastest start measured, in about CubeSandbox's memory. + +| p50 | web | 64 MiB app | memory, web / 64 MiB app | +|---|---:|---:|---:| +| **Sandstorm, Firecracker, warm template** | **62 ms** | **74 ms** | 9.9 / **10.5 MiB** | +| CubeSandbox 0.7.3 | 72 ms | 78 ms | **8.9** / 12.2 MiB | +| **Sandstorm, gVisor, warm template** | 107 ms | 123 ms | 23.3 / 97.3 MiB | +| **Sandstorm, gVisor** | 234 ms | 545 ms | 24.1 / 97.9 MiB | +| Docker + gVisor | 327 ms | 660 ms | 30.8 / 106.8 MiB | +| microsandbox 0.7.8 | 1,117 ms | 1,119 ms | 80.2 / 166.2 MiB | +| Kata 4.2 (QEMU) | 3,005 ms | 3,397 ms | 223 / 311 MiB | + +Sandstorm on Firecracker snapshots a running sandbox in 27 ms, against CubeSandbox's 252, and a clone of one into n is that snapshot and one fork call. Its children are created one after another on the node, about 50 ms each, where CubeSandbox and microsandbox create theirs at once, so a larger n would close the gap. E2B self-hosted was not set up. Method, raw rows and what the runs turned up: [bench/baremetal/results/2026-10-30](bench/baremetal/results/2026-10-30/README.md). ## Numbers diff --git a/bench/baremetal/charts.py b/bench/baremetal/charts.py new file mode 100644 index 00000000..9d3ac428 --- /dev/null +++ b/bench/baremetal/charts.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +"""Draw the bare-metal comparison charts from a results directory. + + python3 bench/baremetal/charts.py bench/baremetal/results/2026-10-30 docs/assets/charts + +The same drawing code and palette as bench/fleet/charts.py, and the same +rule: every chart in `-light.svg` and `-dark.svg`, and a chart whose data +is missing is skipped, not faked. Each runtime's figure is its last row in +the directory, so a re-run supersedes the one before it. +""" + +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "fleet")) +from charts import THEMES, W, Chart # noqa: E402 + +# Shown in this order, top to bottom; Sandstorm's rows in bold. +STARTS = [ + ("sandstorm-fc-warm", "Sandstorm, Firecracker, warm", True), + ("cubesandbox", "CubeSandbox", False), + ("sandstorm-gvisor-warm", "Sandstorm, gVisor, warm", True), + ("sandstorm-gvisor", "Sandstorm, gVisor", True), + ("runc", "Docker (runc)", False), + ("runsc", "Docker + gVisor", False), + ("microsandbox", "microsandbox", False), + ("kata", "Kata (QEMU)", False), +] +CLONES = [ + ("sandstorm-fc", "Sandstorm, Firecracker"), + ("cubesandbox", "CubeSandbox"), + ("microsandbox", "microsandbox"), + ("sandstorm-gvisor", "Sandstorm, gVisor"), +] + + +def rows(src): + for f in sorted(src.glob("*.jsonl")): + for line in open(f): + if line.strip(): + yield json.loads(line) + + +def summaries(src): + """runtime -> app -> (start p50 ms, MiB per instance), last row wins.""" + out = {} + for r in rows(src): + if r.get("kind") != "summary": + continue + start = (r.get("start") or {}).get("p50_ms") + mem = (r.get("memory") or {}).get("per_instance_mib") + prev = out.setdefault(r["runtime"], {}).get(r["app"], (None, None)) + out[r["runtime"]][r["app"]] = (start or prev[0], mem or prev[1]) + return out + + +def clones(src): + """runtime -> [clone 1, 10, 20] in ms, until every child answers. For + Sandstorm a branch then one fork call, so the snapshot plus the fork.""" + out = {} + for r in rows(src): + if r.get("kind") != "fork": + continue + if "clone1_ms" in r: + out[r["runtime"]] = [r["clone1_ms"], r["clone10_wall_ms"], r["clone20_wall_ms"]] + else: + s = r.get("snapshot_ms", 0) + out[r["runtime"]] = [s + r["fork1_ms"], s + r["fork10_wall_ms"], s + r["fork20_wall_ms"]] + return out + + +def hbars(c, x0, x1, y0, items, lo, hi, fmt, ticks): + """Log-scale horizontal bars between x0 and x1, one per row.""" + import math + t = c.t + a, b = math.log10(lo), math.log10(hi) + sx = lambda v: x0 + (x1 - x0) * (math.log10(max(v, lo)) - a) / (b - a) + yb = y0 + 34 * len(items) + for v in ticks: + X = sx(v) + c.out.append(f'') + c.text(X, yb + 18, fmt(v), anchor="middle") + for i, (v, colour) in enumerate(items): + if v is None: + continue + y = y0 + 8 + i * 34 + w = sx(v) - x0 + c.out.append(f'') + c.text(sx(v) + 6, y + 16, fmt(v), colour=t["ink"], weight=600) + + +def start(src, theme): + """Start to first answer and memory per instance for app64, side by + side, one row per runtime. Two plots, not two axes on one: they are + different measures.""" + s = summaries(src) + shown = [(k, label, ours) for k, label, ours in STARTS if "app64" in s.get(k, {})] + if len(shown) < 2: + return None + t = THEMES[theme] + colour = lambda k, ours: t["series"][0] if k == "sandstorm-fc-warm" else t["series"][2] if ours else t["series"][1] if k == "cubesandbox" else t["muted"] + h = 112 + 34 * len(shown) + 40 + c = Chart(theme, "The 64 MiB app on one KVM machine", + "2 × Xeon E5-2637 v2, 31 GB. Start: p50 of 20, one at a time. Memory: 100 kept running. Log scales.", + h=h, left=24, right=24, title_left=24) + y0 = c.top + 16 + lx, gap = 236, 28 + mid = lx + (W - 24 - lx - gap) / 2 + c.text(lx, y0 - 6, "Start to first answer", colour=t["ink2"], weight=600) + c.text(mid + gap, y0 - 6, "Memory per instance", colour=t["ink2"], weight=600) + for i, (k, label, ours) in enumerate(shown): + c.text(lx - 12, y0 + 8 + i * 34 + 15, label, colour=t["ink"] if ours else t["ink2"], anchor="end", weight=600 if ours else 400) + ms = lambda v: f"{v / 1000:.1f} s" if v >= 1000 else f"{v:.0f} ms" + hbars(c, lx, mid - 40, y0 + 4, [(s[k]["app64"][0], colour(k, o)) for k, _, o in shown], + 30, 10000, ms, [30, 100, 1000, 10000]) + hbars(c, mid + gap, W - 24 - 72, y0 + 4, [(s[k]["app64"][1], colour(k, o)) for k, _, o in shown], + 5, 500, lambda v: f"{v:.0f}" + (" MiB" if v >= 300 else ""), [5, 10, 100, 500]) + return c.svg("Start time and memory per instance of a 64 MiB app, by runtime, on one KVM machine") + + +def clone(src, theme): + """Copying a running app64 into n that answer: grouped bars by n.""" + cl = clones(src) + shown = [(k, label) for k, label in CLONES if k in cl] + if len(shown) < 2: + return None + t = THEMES[theme] + colours = {"sandstorm-fc": t["series"][0], "cubesandbox": t["series"][1], + "sandstorm-gvisor": t["series"][2], "microsandbox": t["muted"]} + c = Chart(theme, "Cloning a running sandbox", + "Snapshot a running 64 MiB app, then start n copies; until all answer (microsandbox: until running).", + h=360, left=56, right=24, title_left=24, + legend=[(colours[k], label, "dot") for k, label in shown]) + x0, y0, x1, y1 = c.plot + c.yscale(0, 2500) + c.ygrid([0, 500, 1000, 1500, 2000, 2500], lambda v: f"{v / 1000:g} s" if v else "0") + slot = (x1 - x0) / 3 + bw = min(26, slot / (len(shown) + 1.5)) + for i, n in enumerate((1, 10, 20)): + cx = x0 + slot * (i + 0.5) + for j, (k, _) in enumerate(shown): + v = cl[k][i] + bx = cx + (j - (len(shown) - 1) / 2) * (bw + 4) + yt = c.sy(v) + r = min(4, y1 - yt) + c.out.append(f'') + c.text(bx, yt - 6, f"{v:,.0f}", size=10, colour=t["ink"], anchor="middle", weight=600) + c.text(cx, y1 + 22, f"n = {n}", anchor="middle") + return c.svg("Time to clone a running sandbox into 1, 10 and 20 copies, by runtime") + + +CHARTS = {"start": start, "clone": clone} + + +def main(): + src, dst = Path(sys.argv[1]), Path(sys.argv[2]) + dst.mkdir(parents=True, exist_ok=True) + wrote = [] + for name, draw in CHARTS.items(): + for theme in THEMES: + svg = draw(src, theme) + if svg is None: + break + (dst / f"baremetal-{name}-{theme}.svg").write_text(svg) + else: + wrote.append(name) + print(f"wrote {', '.join(wrote) or 'nothing'} to {dst}") + + +if __name__ == "__main__": + main() diff --git a/bench/baremetal/results/2026-10-30/fork.jsonl b/bench/baremetal/results/2026-10-30/fork.jsonl index 0b8249ec..55e19f10 100644 --- a/bench/baremetal/results/2026-10-30/fork.jsonl +++ b/bench/baremetal/results/2026-10-30/fork.jsonl @@ -3,3 +3,4 @@ {"runtime": "microsandbox", "kind": "fork", "template": "app64", "measured_to": "msb fork returns", "fork1_ms": 658.2, "fork1_children_answering": "11/11", "fork10_wall_ms": 834.9, "fork20_wall_ms": 1151.5, "fork10_rounds_ms": [800, 835, 930], "fork20_rounds_ms": [1066, 1152, 1259], "batch_children_checked_failed": 0} {"runtime": "sandstorm-fc", "kind": "fork", "template": "app64-warm", "snapshot_ms": 27.3, "snapshot_all_ms": [32, 27, 34, 28, 20, 14], "fork1_ms": 109.6, "fork10_wall_ms": 501.0, "fork20_wall_ms": 952.9, "fork10_rounds_ms": [501, 511, 494], "fork20_rounds_ms": [953, 952, 976]} {"runtime": "sandstorm-gvisor", "kind": "fork", "template": "app64-warm", "snapshot_ms": 341.5, "snapshot_all_ms": [385, 372, 349, 342, 329, 337], "fork1_ms": 116.5, "fork10_wall_ms": 998.6, "fork20_wall_ms": 1938.4, "fork10_rounds_ms": [971, 999, 1007], "fork20_rounds_ms": [2064, 1938, 1937]} +{"runtime": "cubesandbox", "kind": "fork", "template": "app64", "source": "fork_cube.py, as it printed; clone_n is snapshot then n creates at once", "snapshot_ms": 252, "fork1_ms": 133, "clone1_ms": 542, "clone10_wall_ms": 973, "clone20_wall_ms": 1046} diff --git a/docs/assets/charts/baremetal-clone-dark.svg b/docs/assets/charts/baremetal-clone-dark.svg new file mode 100644 index 00000000..bf148d1b --- /dev/null +++ b/docs/assets/charts/baremetal-clone-dark.svg @@ -0,0 +1,52 @@ + + +Cloning a running sandbox +Snapshot a running 64 MiB app, then start n copies; until all answer (microsandbox: until running). + +Sandstorm, Firecracker + +CubeSandbox + +microsandbox + +Sandstorm, gVisor + +0 + +0.5 s + +1 s + +1.5 s + +2 s + +2.5 s + +137 + +542 + +658 + +458 +n = 1 + +528 + +973 + +835 + +1,340 +n = 10 + +980 + +1,046 + +1,152 + +2,280 +n = 20 + diff --git a/docs/assets/charts/baremetal-clone-light.svg b/docs/assets/charts/baremetal-clone-light.svg new file mode 100644 index 00000000..681008c3 --- /dev/null +++ b/docs/assets/charts/baremetal-clone-light.svg @@ -0,0 +1,52 @@ + + +Cloning a running sandbox +Snapshot a running 64 MiB app, then start n copies; until all answer (microsandbox: until running). + +Sandstorm, Firecracker + +CubeSandbox + +microsandbox + +Sandstorm, gVisor + +0 + +0.5 s + +1 s + +1.5 s + +2 s + +2.5 s + +137 + +542 + +658 + +458 +n = 1 + +528 + +973 + +835 + +1,340 +n = 10 + +980 + +1,046 + +1,152 + +2,280 +n = 20 + diff --git a/docs/assets/charts/baremetal-start-dark.svg b/docs/assets/charts/baremetal-start-dark.svg new file mode 100644 index 00000000..17da99b1 --- /dev/null +++ b/docs/assets/charts/baremetal-start-dark.svg @@ -0,0 +1,63 @@ + + +The 64 MiB app on one KVM machine +2 × Xeon E5-2637 v2, 31 GB. Start: p50 of 20, one at a time. Memory: 100 kept running. Log scales. +Start to first answer +Memory per instance +Sandstorm, Firecracker, warm +CubeSandbox +Sandstorm, gVisor, warm +Sandstorm, gVisor +Docker (runc) +Docker + gVisor +microsandbox +Kata (QEMU) + +30 ms + +100 ms + +1.0 s + +10.0 s + +74 ms + +78 ms + +123 ms + +545 ms + +414 ms + +660 ms + +1.1 s + +3.4 s + +5 + +10 + +100 + +500 MiB + +10 + +12 + +97 + +98 + +88 + +107 + +166 + +310 MiB + diff --git a/docs/assets/charts/baremetal-start-light.svg b/docs/assets/charts/baremetal-start-light.svg new file mode 100644 index 00000000..be9a8b2a --- /dev/null +++ b/docs/assets/charts/baremetal-start-light.svg @@ -0,0 +1,63 @@ + + +The 64 MiB app on one KVM machine +2 × Xeon E5-2637 v2, 31 GB. Start: p50 of 20, one at a time. Memory: 100 kept running. Log scales. +Start to first answer +Memory per instance +Sandstorm, Firecracker, warm +CubeSandbox +Sandstorm, gVisor, warm +Sandstorm, gVisor +Docker (runc) +Docker + gVisor +microsandbox +Kata (QEMU) + +30 ms + +100 ms + +1.0 s + +10.0 s + +74 ms + +78 ms + +123 ms + +545 ms + +414 ms + +660 ms + +1.1 s + +3.4 s + +5 + +10 + +100 + +500 MiB + +10 + +12 + +97 + +98 + +88 + +107 + +166 + +310 MiB + From 2e363191b5c0e67aef711e2e4374fc2a37234ff3 Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:26:52 +0800 Subject: [PATCH 5/7] docs(readme): Firecracker badge and backend in the intro; gVisor-only setup and fleet chart for the 2c2g comparison Co-Authored-By: Claude Opus 5.5 --- README-zh.md | 3 +- README.md | 3 +- bench/baremetal/charts.py | 71 ++++++++++++++++++++++++++++----- bench/baremetal/setup-gvisor.sh | 52 ++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 12 deletions(-) create mode 100755 bench/baremetal/setup-gvisor.sh diff --git a/README-zh.md b/README-zh.md index f617400a..740bb056 100644 --- a/README-zh.md +++ b/README-zh.md @@ -18,11 +18,12 @@ [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) [![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22)](https://firecracker-microvm.github.io) [![English](https://img.shields.io/badge/LANG-ENGLISH-2D333B?style=flat-square&labelColor=161B22)](README.md) -**一个有意超卖的沙箱集群。** agent 的沙箱大部分时间都闲着。Sandstorm 先把闲置的沙箱暂停,再把它 checkpoint 到磁盘;请求一到,马上恢复。所以一台机器能装下的沙箱,远多于它能同时跑着的数量。每个沙箱都是一个 [gVisor](https://gvisor.dev) 容器,有自己的网络命名空间。Sandstorm 跑在普通云主机上,不需要 KVM,也不需要嵌套虚拟化。 +**一个有意超卖的沙箱集群。** agent 的沙箱大部分时间都闲着。Sandstorm 先把闲置的沙箱暂停,再把它 checkpoint 到磁盘;请求一到,马上恢复。所以一台机器能装下的沙箱,远多于它能同时跑着的数量。每个沙箱都是一个 [gVisor](https://gvisor.dev) 容器,有自己的网络命名空间。Sandstorm 跑在普通云主机上,不需要 KVM,也不需要嵌套虚拟化。在有 KVM 的机器上,沙箱也可以是一个 [Firecracker](https://firecracker-microvm.github.io) 微虚拟机(`--backend firecracker`),启动比我们测过的其他所有沙箱都快([见下文](#在有-kvm-的机器上对比其他沙箱))。 六台 2 核 2 GB 的云主机,全部常驻只能放 **286** 个 Python HTTP 服务;用 Sandstorm 放了 **20,000** 个。之后随机抽 1,200 个去请求,1,198 个都正常响应。 diff --git a/README.md b/README.md index 7d0151f0..edfb7131 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,12 @@ [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) [![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22)](https://firecracker-microvm.github.io) [![中文](https://img.shields.io/badge/LANG-%E4%B8%AD%E6%96%87-DA3633?style=flat-square&labelColor=161B22)](README-zh.md) -**A sandbox fleet that is oversold on purpose.** Most agent sandboxes sit idle most of the time. Sandstorm pauses an idle sandbox, then checkpoints it to disk, and brings it back the moment a request reaches it. So a machine holds far more sandboxes than it could keep running. Every sandbox is a [gVisor](https://gvisor.dev) container with its own network namespace, and Sandstorm runs on ordinary cloud VMs: no KVM, no nested virtualisation. +**A sandbox fleet that is oversold on purpose.** Most agent sandboxes sit idle most of the time. Sandstorm pauses an idle sandbox, then checkpoints it to disk, and brings it back the moment a request reaches it. So a machine holds far more sandboxes than it could keep running. Every sandbox is a [gVisor](https://gvisor.dev) container with its own network namespace, and Sandstorm runs on ordinary cloud VMs: no KVM, no nested virtualisation. On a machine with KVM a sandbox can be a [Firecracker](https://firecracker-microvm.github.io) microVM instead (`--backend firecracker`), which started faster than every other sandbox we measured ([below](#on-a-kvm-machine-against-the-other-sandboxes)). On six cloud machines with 2 cores and 2 GB each, which hold **286** Python HTTP servers kept in memory, Sandstorm held **20,000** — and of 1,200 picked at random afterwards and called, 1,198 answered. diff --git a/bench/baremetal/charts.py b/bench/baremetal/charts.py index 9d3ac428..6409639e 100644 --- a/bench/baremetal/charts.py +++ b/bench/baremetal/charts.py @@ -27,6 +27,16 @@ ("microsandbox", "microsandbox", False), ("kata", "Kata (QEMU)", False), ] +# The fleet's 2-core, 2 GB nodes: no KVM, so gVisor and containers only. +FLEET_STARTS = [ + ("sandstorm-gvisor-warm", "Sandstorm, warm template", True), + ("sandstorm-gvisor", "Sandstorm", True), + ("process", "Plain process, no isolation", False), + ("bwrap", "bubblewrap", False), + ("podman", "Podman (crun)", False), + ("runc", "Docker (runc)", False), + ("runsc", "Docker + gVisor", False), +] CLONES = [ ("sandstorm-fc", "Sandstorm, Firecracker"), ("cubesandbox", "CubeSandbox"), @@ -55,6 +65,34 @@ def summaries(src): return out +def fleet_summaries(src): + """The same, the median across nodes: one file per node in `fleet/`.""" + per = {} + for f in sorted((src / "fleet").glob("*.jsonl")): + for rt, apps in summaries_of(f).items(): + for app, (st, mem) in apps.items(): + per.setdefault(rt, {}).setdefault(app, ([], [])) + if st: + per[rt][app][0].append(st) + if mem: + per[rt][app][1].append(mem) + med = lambda xs: sorted(xs)[len(xs) // 2] if len(xs) % 2 else sum(sorted(xs)[len(xs) // 2 - 1:len(xs) // 2 + 1]) / 2 if xs else None + return {rt: {app: (med(a), med(b)) for app, (a, b) in apps.items()} for rt, apps in per.items()}, \ + len(list((src / "fleet").glob("*.jsonl"))) + + +def summaries_of(f): + out = {} + for line in open(f): + if not line.strip(): + continue + r = json.loads(line) + if r.get("kind") == "summary": + out.setdefault(r["runtime"], {})[r["app"]] = ( + (r.get("start") or {}).get("p50_ms"), (r.get("memory") or {}).get("per_instance_mib")) + return out + + def clones(src): """runtime -> [clone 1, 10, 20] in ms, until every child answers. For Sandstorm a branch then one fork call, so the snapshot plus the fork.""" @@ -94,29 +132,42 @@ def start(src, theme): """Start to first answer and memory per instance for app64, side by side, one row per runtime. Two plots, not two axes on one: they are different measures.""" - s = summaries(src) - shown = [(k, label, ours) for k, label, ours in STARTS if "app64" in s.get(k, {})] + return start_chart(summaries(src), STARTS, theme, "The 64 MiB app on one KVM machine", + "2 × Xeon E5-2637 v2, 31 GB. Start: p50 of 20, one at a time. Memory: 100 kept running. Log scales.", + "Start time and memory per instance of a 64 MiB app, by runtime, on one KVM machine") + + +def fleet(src, theme): + """The same chart on the fleet's 2-core, 2 GB nodes, the median node.""" + s, nodes = fleet_summaries(src) + if not nodes: + return None + return start_chart(s, FLEET_STARTS, theme, "The 64 MiB app on 2-core, 2 GB cloud machines", + f"Median of {nodes} nodes, no KVM. Start: p50 of 20, one at a time. Memory: 8 kept running. Log scales.", + "Start time and memory per instance of a 64 MiB app, by runtime, on 2-core, 2 GB machines") + + +def start_chart(s, order, theme, title, subtitle, label): + shown = [(k, name, ours) for k, name, ours in order if "app64" in s.get(k, {})] if len(shown) < 2: return None t = THEMES[theme] colour = lambda k, ours: t["series"][0] if k == "sandstorm-fc-warm" else t["series"][2] if ours else t["series"][1] if k == "cubesandbox" else t["muted"] h = 112 + 34 * len(shown) + 40 - c = Chart(theme, "The 64 MiB app on one KVM machine", - "2 × Xeon E5-2637 v2, 31 GB. Start: p50 of 20, one at a time. Memory: 100 kept running. Log scales.", - h=h, left=24, right=24, title_left=24) + c = Chart(theme, title, subtitle, h=h, left=24, right=24, title_left=24) y0 = c.top + 16 lx, gap = 236, 28 mid = lx + (W - 24 - lx - gap) / 2 c.text(lx, y0 - 6, "Start to first answer", colour=t["ink2"], weight=600) c.text(mid + gap, y0 - 6, "Memory per instance", colour=t["ink2"], weight=600) - for i, (k, label, ours) in enumerate(shown): - c.text(lx - 12, y0 + 8 + i * 34 + 15, label, colour=t["ink"] if ours else t["ink2"], anchor="end", weight=600 if ours else 400) + for i, (k, name, ours) in enumerate(shown): + c.text(lx - 12, y0 + 8 + i * 34 + 15, name, colour=t["ink"] if ours else t["ink2"], anchor="end", weight=600 if ours else 400) ms = lambda v: f"{v / 1000:.1f} s" if v >= 1000 else f"{v:.0f} ms" hbars(c, lx, mid - 40, y0 + 4, [(s[k]["app64"][0], colour(k, o)) for k, _, o in shown], 30, 10000, ms, [30, 100, 1000, 10000]) hbars(c, mid + gap, W - 24 - 72, y0 + 4, [(s[k]["app64"][1], colour(k, o)) for k, _, o in shown], 5, 500, lambda v: f"{v:.0f}" + (" MiB" if v >= 300 else ""), [5, 10, 100, 500]) - return c.svg("Start time and memory per instance of a 64 MiB app, by runtime, on one KVM machine") + return c.svg(label) def clone(src, theme): @@ -150,7 +201,7 @@ def clone(src, theme): return c.svg("Time to clone a running sandbox into 1, 10 and 20 copies, by runtime") -CHARTS = {"start": start, "clone": clone} +CHARTS = {"baremetal-start": start, "baremetal-clone": clone, "fleet-start": fleet} def main(): @@ -162,7 +213,7 @@ def main(): svg = draw(src, theme) if svg is None: break - (dst / f"baremetal-{name}-{theme}.svg").write_text(svg) + (dst / f"{name}-{theme}.svg").write_text(svg) else: wrote.append(name) print(f"wrote {', '.join(wrote) or 'nothing'} to {dst}") diff --git a/bench/baremetal/setup-gvisor.sh b/bench/baremetal/setup-gvisor.sh new file mode 100755 index 00000000..48dfd133 --- /dev/null +++ b/bench/baremetal/setup-gvisor.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# The gVisor half of setup.sh, for a machine without KVM: the fleet's 2-core, +# 2 GB nodes. One master and node in one process on 127.0.0.1:18080 in +# /var/lib/sst-gvisor, with templates web and app64, plain and warm. Run as +# root from a checkout with runsc on the PATH and python3-numpy installed: +# +# BIN=/usr/local/bin/sandstormd-cmp bench/baremetal/setup-gvisor.sh +# +# then compare.py with --runtimes process,bwrap,runc,podman,runsc, +# sandstorm-gvisor,sandstorm-gvisor-warm. +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +REPO="$(cd "$HERE/../.." && pwd)" +BIN=${BIN:-$REPO/target/release/sandstormd} +APPS="web:128 app64:224" +# Every sandbox kept hot, as the other runtimes keep their instances. +SANDSTORM_FLAGS=${SANDSTORM_FLAGS:---idle-frozen-secs 86400 --reclaim-hot off --reclaim-frozen off} + +G=/var/lib/sst-gvisor +mkdir -p "$G" +for app in $APPS; do + name=${app%%:*} + for t in "$name" "$name-warm"; do + r=$G/templates/$t/rootfs + mkdir -p $r/proc $r/dev $r/sys $r/tmp $r/etc/alternatives $r/var $r/root $r/app $r/usr $r/lib $r/lib64 $r/bin $r/sbin + printf 'root:x:0:0:root:/root:/bin/sh\n' > $r/etc/passwd + cp "$REPO"/bench/fleet/apps/*.py $r/app/ + cp -a /etc/alternatives/lib*.so* $r/etc/alternatives/ 2>/dev/null || true + done +done +rm -rf "$G/warm" + +systemctl stop sst-gvisor 2>/dev/null || true +systemd-run --unit sst-gvisor --collect -p KillMode=process "$BIN" serve --master --node \ + --bind 127.0.0.1:18080 --state-db "$G/state.db" --pki-dir "$G/pki" --work-dir "$G" \ + --node-id sst-gvisor --port-min 21000 --port-max 25999 $SANDSTORM_FLAGS >/dev/null +for _ in $(seq 1 60); do [ -s "$G/pki/api-token" ] && curl -s -o /dev/null --cacert "$G/pki/ca.pem" https://127.0.0.1:18080/ && break; sleep 1; done + +for app in $APPS; do + name=${app%%:*} mem=${app##*:} + case $name in + web) args='["/usr/bin/python3","/app/web.py"]' ;; + app*) args="[\"/usr/bin/python3\",\"/app/srv.py\",\"${name#app}\"]" ;; + esac + for t in "$name" "$name-warm"; do + warm=; [ "$t" = "$name" ] || warm=',"warm":{}' + curl -s -o /dev/null -w "$t %{http_code}\n" --cacert "$G/pki/ca.pem" \ + -H "authorization: Bearer $(cat "$G/pki/api-token")" -H 'content-type: application/json' \ + -X POST --data-raw "{\"name\":\"$t\",\"rootfs\":\"rootfs\",\"spec\":{\"args\":$args,\"memory_max_mib\":$mem$warm}}" \ + https://127.0.0.1:18080/v1/templates + done +done From adba6b1833c96c61eeba1be2d8a14edabc2467cc Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:40:23 +0800 Subject: [PATCH 6/7] docs(readme): gVisor and Firecracker logos on their badges Co-Authored-By: Claude Opus 5.5 --- README-zh.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README-zh.md b/README-zh.md index 740bb056..d1e4bb9f 100644 --- a/README-zh.md +++ b/README-zh.md @@ -17,8 +17,8 @@ [![License](https://img.shields.io/badge/LICENSE-APACHE%202.0-3FB950?style=flat-square&labelColor=161B22)](LICENSE) [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) -[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22)](https://gvisor.dev) -[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22)](https://firecracker-microvm.github.io) +[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) [![English](https://img.shields.io/badge/LANG-ENGLISH-2D333B?style=flat-square&labelColor=161B22)](README.md) diff --git a/README.md b/README.md index edfb7131..6163b797 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ [![License](https://img.shields.io/badge/LICENSE-APACHE%202.0-3FB950?style=flat-square&labelColor=161B22)](LICENSE) [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) -[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22)](https://gvisor.dev) -[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22)](https://firecracker-microvm.github.io) +[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) [![中文](https://img.shields.io/badge/LANG-%E4%B8%AD%E6%96%87-DA3633?style=flat-square&labelColor=161B22)](README-zh.md) From d2ddcbfeb0886f07f4d5483883207cad4e9f712a Mon Sep 17 00:00:00 2001 From: WaylandYang <145302500+WaylandYang@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:41:31 +0800 Subject: [PATCH 7/7] docs(readme): gVisor and Firecracker badges without the ISOLATION label Co-Authored-By: Claude Opus 5.5 --- README-zh.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README-zh.md b/README-zh.md index d1e4bb9f..fc13752e 100644 --- a/README-zh.md +++ b/README-zh.md @@ -17,8 +17,8 @@ [![License](https://img.shields.io/badge/LICENSE-APACHE%202.0-3FB950?style=flat-square&labelColor=161B22)](LICENSE) [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) -[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) -[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) +[![gVisor](https://img.shields.io/badge/GVISOR-2D333B?style=flat-square&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/FIRECRACKER-2D333B?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) [![English](https://img.shields.io/badge/LANG-ENGLISH-2D333B?style=flat-square&labelColor=161B22)](README.md) diff --git a/README.md b/README.md index 6163b797..d8edd17c 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ [![License](https://img.shields.io/badge/LICENSE-APACHE%202.0-3FB950?style=flat-square&labelColor=161B22)](LICENSE) [![Rust](https://img.shields.io/badge/BUILT%20WITH-RUST-F74C00?style=flat-square&labelColor=161B22&logo=rust&logoColor=FFFFFF)](https://www.rust-lang.org) [![DeepLethe](https://img.shields.io/badge/BUILT%20BY-DEEPLETHE-F1F2F5?style=flat-square&labelColor=161B22)](https://deeplethe.com) -[![gVisor](https://img.shields.io/badge/ISOLATION-GVISOR-2D333B?style=flat-square&labelColor=161B22&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) -[![Firecracker](https://img.shields.io/badge/ISOLATION-FIRECRACKER-2D333B?style=flat-square&labelColor=161B22&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) +[![gVisor](https://img.shields.io/badge/GVISOR-2D333B?style=flat-square&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNzUuMzUiIGhlaWdodD0iMTkzLjIwIiB2aWV3Qm94PSIwIDAgMTc1LjM1IDE5My4yMCIgPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywtNjE0LjQ1LDYzOC45NikiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU0OC4yNCwzNjMuMjQpIj48cGF0aCBkPSJtIDAsMCBjIDE2LjY1LDIxLjEyIDIyLjY5LDQ0LjQzIDE4LjMyLDcwLjk5IDMuMDYsMCA1Ljc0LC0wLjAyIDguNDEsMC4wMCAyLjIyLDAuMDIgNC40NCwwLjEwIDYuNjYsMC4xNyA0Ljc5LDAuMTUgNC44MSwwLjE2IDUuODgsLTQuNTggMy4xNCwtMTQuMDUgMi4xOCwtMjguMDkgLTAuMTcsLTQyLjExIC0wLjI1LC0xLjQ5IC0wLjcsLTIuOTUgLTAuODYsLTQuNDUgQyAzNy4wNSw5LjA4IDMwLjA4LDMuNjQgMjAuMTYsMS4wOSAxMy43OCwtMC41NCA3LjMyLC0wLjgyIDAsMCIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz48L2c%2BPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTQ0LjY4LDM5Ni4xNykiPjxwYXRoIGQ9Ik0gMCwwIEMgMCwyLjU5IC0zLjQ1LDQuMzIgLTMuNDUsNC4zMiAtMC44Niw1LjE4IDAsOC42NCAwLDguNjQgMCw4LjY0IDAuODYsNS4xOCAzLjQ1LDQuMzIgMy40NSw0LjMyIDAsMi41OSAwLDAgbSAtMTcuMDksNi40NSBjIDAsNi43NCAtOC45OCwxMS4yMyAtOC45OCwxMS4yMyA2Ljc0LDIuMjQgOC45OCwxMS4yMyA4Ljk4LDExLjIzIDAsMCAyLjI0LC04Ljk5IDguOTksLTExLjIzIDAsMCAtOC45OSwtNC40OSAtOC45OSwtMTEuMjMiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ4NS4wOCw0MjkuNzkpIj48cGF0aCBkPSJtIDAsMCBjIDAsMCAtMi4yMSwzLjM1IC05LjczLDIuMDUgMCwwIDUuOTgsMjguNzMgMzYuMjksMzguODAgQyAyNi41Niw0MC44NiAtMi44MiwyNC4yNyAwLDAgTSAwLjU4LC0zMy4yMCAwLjU4LC0zMy4yMSBjIC0xLjI5LC0yLjAyIC0yLjgyLC0zLjU3IC00LjUzLC00LjYxIC0xLjUxLC0wLjkzIC0zLjE3LC0xLjQyIC00Ljc0LC0xLjQyIC0wLjUyLDAgLTEuMDQsMC4wNSAtMS41MywwLjE3IGwgLTIuMjAsMC41MCAyLjE4LDAuNjAgYyAxLjYzLDAuNDUgMy4wNiwxLjM0IDQuMjUsMi42NiAxLjAxLDEuMTAgMS44NSwyLjQ4IDIuNTcsNC4yMSAxLjE3LDIuODIgMS43OCw2LjE2IDEuODEsOS45MyAtMC4wNCwzLjcxIC0wLjY4LDcuMDUgLTEuODgsOS45MCAtMC43MCwxLjY1IC0xLjU4LDMuMDUgLTIuNjIsNC4xNiAtMS4yMiwxLjMxIC0yLjY3LDIuMTcgLTQuMjksMi41NyBsIC0yLjE4LDAuNTMgMi4xNywwLjU3IGMgMC40OCwwLjEyIDAuOTksMC4xOSAxLjUzLDAuMjAgaCAwLjAzIGwgMS42OCwtMC4xNSBjIDEuMDQsLTAuMjAgMi4xMCwtMC42MSAzLjA2LC0xLjE4IDEuNzUsLTEuMDMgMy4zMCwtMi41NiA0LjU5LC00LjU2IDIuMTUsLTMuMzcgMy4zMSwtNy41MyAzLjM1LC0xMi4wNCAtMC4wMiwtNC41NCAtMS4xNSwtOC43MSAtMy4yNywtMTIuMDYgbSAxMDEuOTQsNTEuMTcgYyAwLDAgLTAuMDcsMC4wNSAtMC4yMiwwLjEzIC0wLjU0LDAuMzIgLTEuMTEsMC42MCAtMS43MSwwLjgxIC0zLjA0LDEuMjQgLTkuODgsMy4xOCAtMjEuOTAsMi42MiAtMC4wMiwwIC0wLjA1LDAgLTAuMDgsLTAuMDAgQyA1Mi45MSwyMS4xMiAzMC4wMiwxMC45MiAzMC4wMiwxMC45MiBjIDAsMCAxLjQzLDEuNzYgMy40NSwzLjY5IDEwZS00LDAgMTBlLTQsMTBlLTQgMC4wMCwxMGUtNCAxLjA1LDAuOTcgMi4zNSwyLjA3IDMuOTEsMy4yMiAwLjA0LDAuMDMgMC4wOCwwLjA2IDAuMTIsMC4wOSA4LjcwLDYuMzggMjUuMzQsMTQuMTYgNTEuNjIsOS41NCAtMC45OCwxLjEyIC0yLjAwLDIuMTkgLTMuMDMsMy4yMSAtMS4xMSwwLjg4IC0yLjIzLDEuNjkgLTMuMzUsMi40NSAwLjAyLC0wLjAxIDAuMDMsLTAuMDIgMC4wNSwtMC4wMyAwLDAgLTE3LjAxLDE5LjQxIC00OC42OCwxNS44OSBDIDMwLjE5LDQ4LjYyIDI1Ljk4LDQ3Ljg2IDIxLjY2LDQ2LjU2IDIxLjY1LDQ2LjU2IDIxLjY0LDQ2LjU2IDIxLjY0LDQ2LjU2IEwgMjEuNjMsNDYuNTUgQyAxMS40OCw0My40OSAwLjY4LDM3LjM4IC04LjcxLDI1LjkxIC05LjI5LDI1LjE5IC05Ljg0LDI0LjQ3IC0xMC4zNywyMy43NyBjIC0wLjA2LC0wLjA5IC0wLjE0LC0wLjIwIC0wLjIyLC0wLjMwIC0xLjE4LC0xLjU4IC0yLjI3LC0zLjE0IC0zLjI3LC00LjY3IC0zLjI2LC01LjQyIC01LjYzLC0xMS42NiAtNi4zMSwtMTMuNTQgLTEwLjU4LC0zMi40MCAyLjU4LC01Ny41NSA1LjE0LC02MS45NiA4LjkzLC0xNS4xNSAyNC41NiwtMzIuMzUgNTAuNzcsLTM3LjMyIDAuMTksLTAuMDQgMC4zOCwtMC4xMCAwLjU4LC0wLjE0IDEuNzIsLTAuMzYgNC44NiwtMC45MiA4LjkwLC0xLjE5IDEuNTIsLTAuMDYgMy4wOCwtMC4wOSA0LjY5LC0wLjA2IDEuNTQsLTAuMDAgMi45OSwwLjAxIDQuMzMsMC4wNiAwLjM5LDAuMDIgMC43NCwwLjA0IDEuMDQsMC4wNCA1LjEwLDAuMjMgOC4yNywwLjc3IDguMjcsMC43NyAtMjYuNTQsMS4yOSAtMzkuODQsMTMuNDAgLTQ1LjY5LDIxLjE0IC0xLjMyLDEuNjQgLTIuNDYsMy40MiAtMy4zNyw1LjMxIC0wLjM2LDAuNzEgLTAuNTIsMS4xMSAtMC41MiwxLjExIDguNDUsLTcuMTggMjAuMjksLTEzLjM2IDIwLjI5LC0xMy4zNiAxMC42MSwtNC45OSAyMS43MywtNy40NSAzMy41MiwtNS44MyAwLDAgMjQuNjQsMi4yNiAzNC40NiwyNS4wOSAtMC40MiwwLjMyIC0wLjM2LDAuMjcgLTAuNzksMC42IC0wLjY1LC0wLjUyIC0xLjI5LC0xLjAyIC0xLjkyLC0xLjQ5IC0wLjk5LC0wLjY1IC0xLjk2LC0xLjM1IC0yLjkzLC0yLjA3IC01LjI2LC0zLjQ4IC05LjU2LC01LjEyIC0xMi4xMiwtNS44NyAtMTkuMzUsLTQuODggLTM3LjI3LC0xLjI1IC01Mi45MywxMi40NSAtNy4yNSw2LjM0IC0xMS43NSwxNC4zNSAtMTEuOTQsMjQuMjkgLTAuMTIsNi40NiAtMC4xOSwxMi45MyAtMC4xMywxOS40IDAuMDgsMTAuMTggNy4yNCwxNy45MiAxNy4zOSwxOS4yOCAyMC41NiwyLjc1IDQxLjIzLDMuNzEgNjEuOTQsNC4xOSAzLjE3LDAuMDcgNS45OCwwLjAzIDcuNDUsLTMuMzUgMC4wMiwtMC4wNSAwLjM2LDAuMDIgMC41NSwwLjAzIDEuNCw0LjQ2IC0wLjYxLDkuMjcgLTQuMjksMTEuNjIiIHN0eWxlPSJmaWxsOiNmZmZmZmYiIC8%2BPC9nPjwvZz48L3N2Zz4%3D)](https://gvisor.dev) +[![Firecracker](https://img.shields.io/badge/FIRECRACKER-2D333B?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM%2FrhtAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAApjS%2BXAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAWRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD53d3cuaW5rc2NhcGUub3JnPC94bXA6Q3JlYXRvclRvb2w%2BCiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY%2BCjwveDp4bXBtZXRhPgqyyWIhAAAJG0lEQVRYCaVYW2xcRxn%2B51x2z6693thu7boOCbawGzXFEShSUB%2Bg8MBFFaCqD3koRcADQqoUVIwQD5TygATiASHEQwVIXIqEqj6AUKWipmpIiQopIcJq08Yxie3Yydo4sXe9tnf37LnwfWOPvZvsrtfOL83OnjMz%2F3zn%2B29zjpJ7kHPnzmX6%2BvoeVkod8jyvP5FIHLJt%2B%2BOpVOo0rucsy5qG%2BrcxXtjvNs5%2BF8ZxbOfz%2BT%2Bur68%2FHgSBAJAAoACUpNPpE9QbhqHMzMy%2BirmfB8hwP3tZ%2B1nENQD3dGdn5%2BPZbFbAmgCobGxsSLValVKphPGCXJuZFdtxPjc5NfXl%2Fe6j9rNwcXGR5ryQTCYPkiUKwUVRpJmsVHzJr65KHIu4js37845tHR8eHl7c6377YhDmeg5%2BdpCmNQKzCgBLsbgmK4VNl1N4%2FAAPAPMf9P3q983cvfR7ZnBhYeEEgJzFJkn6GxsFoLWZl1fyorbu6YGtMduyKlEYfGJ0dPS8ud9OvycGGRhoP4LPJdHX6fd9X9bW1kRJ%2FX1O4lz4YjKM5MdnzpzZU2DuCWAulzsJ9j5ZLpfrwDEwKpWKjloy2Qgkxz0v%2BdjAwMGTdYt3uWgb4NTUVBec%2FXkGQq0QHH2RPZnaBMgZdzPJtbHEz1NXrY5W%2F9sGiKj9KgJjlECMEBgbgbGHn2mfpF%2Bqu%2FFJFXPS6dQI4uZrRsdufVsA%2BcQAcYp%2BRjAUpheTYthr9ixbrCgUK46QG6Ea%2FZ1CkEB%2Fql0W2wIIRp5CqhgmSxSCMUB5TVZpWkl60nX2ZTnw2u9EeWmxcK92HudSBywxBHN%2Fide7ya4AJyYmOqDkmwac9jGC2RLtVwBsUo539T%2BSfufvYsHbWGGAUGKFbdi2hLrgracmFhaou6XsrGoyDeXsJNh7iCwRhN60Zi43M6BVGIiT%2F584t26IXVoTy3XFrZYk%2B9afxb19U2K4AIVmps5ksbhrRLcEOD097cFEz9LHCMzFhkZoOt6PsKlKJHVytisbYhdvi%2BWjLxWR%2B1xxwLZdWhVVXsfSHeZDZoMwfpZ7GJ2N%2BpYAYb4n8aSPEAxPKkZ4TdNGMFsSJk29e05UMi1ufhEAlxEDCBIAog%2Bqrm4pfOopKfcfFhXtlEZaJJnyHqkEwZNGb6O%2BKcBLly4lAORbNKsBtw2M%2BUz7lpKuV16Q7hd%2FoDf3Jv8lCiaF12kTC9hl6rHxcAoWQKmrw6B1RPE496obqLloChCR9gUcAD5KJZRacJo93LervtgbebHBXPdvvycdb%2FxBYi%2BlK4mzuqRBWY4j3npevJUFBgYyz07qYdpCZfoI3OeLNZjq%2FjYEiBzFg8C4A%2BV3AjPXynbEXl%2FRPhcnU5I%2B%2F4rYhSWcr5IC2sTJXUNQIS9iXtebL8mBf%2FxJvOUbcLu7M7hS1jj3rEO2ddEQIPzuY2ysnwYQn5z%2Fw61Ka7sJcRdnRCFaET0Sp9ICXxDB%2BU84lpvSMxnZ3pW3xS3eksy1i2KFVQTXjqnJou26J8JQPdo2QDjwAlrJgDMmjWBS792z4lbWRRHE9feQYsAImN5uYCxGwuaYm7sqCfT20nVxV26KC3dI3Z6XCEuMqZmikA3CyI4bvrc0ZHBoaGgKoN5haiG4TeYsbPhfSV05L6mlGUQoCLt6ET80KQCaRrAAr4KyZH%2F9bcm8%2BJzA1uIWkB%2FLawA4Bw9QqCibNZ1BCLw3rDCcaptBPBVwRW9wMQFutlCc5RyCoiAdf%2Fm5ZH41Ls78Zc3WJnswLc1rGoBbAGUhQPgQCjXahQ%2B6lTVx8J9CkA5zaxy%2Ff%2BTIkWIjgE0PjwD1Onzwu2SPDT%2BimIALi2KBBevWdYkdZoed5MsNmGK2hWwaAXA7nxOHACWSAEk8gP9xNaz8bzPtzr5GQ%2F0Q3tIuIgXkEMkD8BBdShVMw0NAmL1f6PxIbPWLWl3hAVl1dFXSFQbuAwtVShtcdaHZ0qYAx8bGViYnJ%2F8JP3yCSmNlS5zpFTU8JtHcpMQoa1KtbAIlw%2FVE1u%2BnSY1lpfuwhOmsWEhLNuoxSyesVMQee2eQO8C0p%2BGPT2zv1vOASDEn8oGHJF6aA0CcD6tlBITfgk2wjtK31nG%2FlNI9YqWy4iDK7bgE13V4%2FLpw9OhRKGssTRnkdDD3Jt4%2FfARLgj5o9R2WOHcZ9RXBAMeJ11YAELmSTAKsIMdxnpYtRhWuK4kOKXY%2BALYj8fuGhEcOZggCBIuv4rLGcTeXm9%2BWAPGF4Eomk7kMZWM6WDqyEgCkc3NSVPY%2BnU4EpjYgySg8X0es2TOyHFnt6JcYJg37PyhB94BEjF6AQ64N0L9mwDTqG%2BZBM%2FH48eNMVmfpKzqh4gRSHnxYwmQHiEJN7YQ%2FdcFsXb0iuvWg75EY92MPZ1G09QMPCs7bEnXdJ9XRE6CKOTDQL%2FnQ%2Bf7y8vJ7Zr9GfUuAXIB0c9ocSqt%2BRXzHk9LoozhqYRBsxQkcDsAsgSqCzACkbt1SyfZLWRC5nd3iH30MOROg8WDUx4cme1skNMKm77U0MWdA0XmY4jZqc6%2BO5kpZYjh79OHPijeNGotTCyuHlfAAFg3mo8lpxkqoxM%2F2in%2FoGN5XUjqQtCWQFVjn8Z%2F%2B11JaJYfthThp%2FBW%2B%2BBkWdgo34WmZjp4oLqLOokJIGOGAqi0Sw%2B82cKfgdsmGS9YQAyZ4sJ7%2Bh6PcHA%2FDvb29q1ppk59dGeQ6AOEHyW2ADJiAKSZibuyH4w9KYFlRRzoVYa5TqQZSwWcQnx%2BR4BZ3Cs6aZPBvg4ODLcFx3a4%2ByEkw7e%2Fx3eV1KqbvGKHJAwAIYHbfrzgbpXIUIXq0r6JChIzqGiFz1IHscAEAf1gz1PRvWybmarDmzs%2FPfwU58TsogR%2BiDxEgRZt8M6%2FFeAskAFUAe5xD4aEDa%2FAQ%2Fjzm%2FhTfEn957NgxvkXtKm0DNJrm5uZ6sMk30J7Bpg%2FWAqVPAmAMAGoVHzApBIY5tzH%2FBQTbL1A1Foyudvo9AzRKUacHETjPgNmvA0Qvv3jxWAYTxvivyC4Y4xHqN7j%2FMxynps3avfT7Bmg2mZ2dHQZz4zDj03j7y5BFmLcM1l7CvZ%2BMjIy0TMRGT7P%2BngEaxTD9CILg02B0AAy%2BjO%2FRE2bsXvr%2FAx2ptl%2F0braeAAAAAElFTkSuQmCC)](https://firecracker-microvm.github.io) [![中文](https://img.shields.io/badge/LANG-%E4%B8%AD%E6%96%87-DA3633?style=flat-square&labelColor=161B22)](README-zh.md)