#!/bin/bash
# Docker Desktop benchmark rerun, October 2026. Commands follow
# audit/interviews/docker-desktop-rerun.md; every adaptation is written to adaptations.txt.
# Raw outputs are appended unedited to one file per benchmark.
set -u
# Results land next to this script, wherever the folder lives.
OUT="$(cd "$(dirname "$0")" && pwd)"
WORK="$HOME/dd-bench-2026-10"
mkdir -p "$OUT" "$WORK/data" "$WORK/out"
exec > >(tee -a "$OUT/run.log") 2>&1
echo "=== run started $(date -u +%FT%TZ)"
step() { echo; echo "=== $1  ($(date -u +%T))"; }

step "machine info"
{
  echo "date: $(date -u +%FT%TZ)"; sw_vers; echo
  echo "cpu: $(sysctl -n machdep.cpu.brand_string)"; echo "memsize: $(sysctl -n hw.memsize)"; echo "ncpu: $(sysctl -n hw.ncpu)"; echo
  docker version; echo; docker info; echo; docker desktop version 2>&1; echo; docker desktop status 2>&1
} > "$OUT/machine-info.txt" 2>&1
cat >> "$OUT/adaptations.txt" <<'A'
- Docker Desktop's settings file (~/Library/Group Containers/group.com.docker/settings-store.json) is not readable from this terminal (macOS TCC: Operation not permitted), so it was not backed up, not changed, and the file-sharing implementation could not be switched. All runs use the current setting; the mode is to be read from the Docker Desktop GUI (Settings > General > file sharing) and written into summary.md by hand.
A

step "tools"
{ which hyperfine || brew install hyperfine; which iperf3 || brew install iperf3; } > "$OUT/install.txt" 2>&1
echo "- hyperfine and iperf3 installed with Homebrew (hyperfine is the tool the post's own commands use; iperf3 install was pre-approved)." >> "$OUT/adaptations.txt"
docker images --format '{{.Repository}}:{{.Tag}}' > "$WORK/images-before.txt"

step "1 hyperfine container start x3"
for i in 1 2 3; do
  { echo "## attempt $i  $(date -u +%T)"; hyperfine -i -p 'docker stop ubuntu || :' 'docker run -it --rm ubuntu echo' 2>&1; echo; } >> "$OUT/hyperfine.txt"
done

step "2 bind-mount copy 1 GB"
cd "$WORK"
dd if=/dev/zero of=data/data.img bs=1M count=1000 2>> "$OUT/copy-1gb.txt"
printf 'FROM ubuntu:latest\n\nVOLUME /data\n\nCMD ["bash"]\n' > Dockerfile
docker build -t virtiofs-demo:latest . >> "$OUT/copy-1gb.txt" 2>&1
docker rm -f vfs-demo >/dev/null 2>&1
docker run -d --name vfs-demo -v "$WORK/data:/data" virtiofs-demo sleep infinity >> "$OUT/copy-1gb.txt" 2>&1
docker ps >> "$OUT/copy-1gb.txt"
for i in 1 2 3; do
  { echo "## attempt $i  $(date -u +%T)"; rm -f out/data.img; { time docker cp vfs-demo:/data/data.img out/data.img; } 2>&1; echo; } >> "$OUT/copy-1gb.txt"
done
echo "- Container is started detached with 'sleep infinity' (the post ran it interactively) and named vfs-demo; docker cp writes to a separate out/ directory instead of back onto the bind-mounted source file." >> "$OUT/adaptations.txt"

step "3 bind-mount copy 10 GB"
dd if=/dev/zero of=data/data.img bs=1M count=10000 2>> "$OUT/copy-10gb.txt"
for i in 1 2 3; do
  { echo "## attempt $i  $(date -u +%T)"; rm -f out/data.img; { time docker cp vfs-demo:/data/data.img out/data.img; } 2>&1; echo; } >> "$OUT/copy-10gb.txt"
done
rm -f data/data.img out/data.img

step "4 redis build over a bind mount x3"
rm -rf "$WORK/redis"
docker run --rm -v "$WORK:/w" alpine sh -c 'cd /w ; apk add git ; git clone https://github.com/redis/redis --depth 1' >> "$OUT/redis-build.txt" 2>&1
for i in 1 2 3; do
  { echo "## attempt $i  $(date -u +%T)"; docker run --rm -v "$WORK/redis:/tmp/redis" ubuntu bash -c 'cd /tmp/redis ; apt update >/dev/null 2>&1 && apt install -y make gcc >/dev/null 2>&1 ; make distclean >/dev/null 2>&1 ; time make' 2>&1 | tail -8; echo; } >> "$OUT/redis-build.txt"
done
echo "- Redis clone goes under $WORK instead of /tmp; apt output is suppressed and only the tail of make is kept (the build log is thousands of lines); timing is the 'real' line of 'time make' inside the container, as in the post." >> "$OUT/adaptations.txt"

step "5 pgbench x3"
for i in 1 2 3; do
  {
    echo "## attempt $i  $(date -u +%T)"
    IMG=postgres:alpine; NET=postgresnet; TESTDIR="$WORK/postgrestest/data"; PGNAME=postgrestest
    docker rm -f $PGNAME >/dev/null 2>&1; docker network rm $NET >/dev/null 2>&1
    docker network create $NET
    rm -rf "$TESTDIR"; mkdir -p "$TESTDIR"
    docker run --name=$PGNAME -e POSTGRES_PASSWORD=postgrespass --network $NET -p 5432:5432 -v "$TESTDIR:/var/lib/postgresql/data" -d $IMG
    for t in $(seq 1 60); do docker exec $PGNAME pg_isready -U postgres >/dev/null 2>&1 && break; sleep 1; done
    docker run --rm --network $NET -e PGPASSWORD=postgrespass $IMG sh -c 'pgbench --host=postgrestest -U postgres -i -s 10 postgres ; pgbench --host=postgrestest -U postgres -c 10 -t 10 postgres' 2>&1
    docker stop $PGNAME >/dev/null; docker rm $PGNAME >/dev/null; docker network rm $NET >/dev/null
    echo
  } >> "$OUT/pgbench.txt"
done
echo "- pgbench client runs from the postgres:alpine image itself instead of 'apk add postgresql' in a bare alpine container (the Alpine package name changed); the server is waited for with pg_isready instead of being hit immediately." >> "$OUT/adaptations.txt"

step "6 iperf3 x3 each"
IMG=networkstatic/iperf3
docker pull $IMG >/dev/null 2>&1
for i in 1 2 3; do
  { echo "## container-to-container attempt $i  $(date -u +%T)"
    NET=iperf3net; docker rm -f iperf3server >/dev/null 2>&1; docker network rm $NET >/dev/null 2>&1; docker network create $NET >/dev/null
    docker run --rm -d --name=iperf3server --network=$NET $IMG -s -1 >/dev/null; sleep 1
    docker run --rm --name=iperf3client --network=$NET $IMG -c iperf3server 2>&1
    docker rm -f iperf3server >/dev/null 2>&1; docker network rm $NET >/dev/null; echo; } >> "$OUT/iperf3-container-to-container.txt"
done
for i in 1 2 3; do
  { echo "## container-to-host attempt $i  $(date -u +%T)"
    iperf3 -s -1 >/dev/null 2>&1 & SP=$!; sleep 1
    docker run --rm $IMG -c host.docker.internal 2>&1
    kill $SP >/dev/null 2>&1; wait $SP 2>/dev/null; echo; } >> "$OUT/iperf3-container-to-host.txt"
done
for i in 1 2 3; do
  { echo "## host-to-container attempt $i  $(date -u +%T)"
    docker rm -f iperf3server >/dev/null 2>&1
    docker run --rm -d -p 5201:5201 --name=iperf3server $IMG -s -1 >/dev/null; sleep 1
    iperf3 -c localhost 2>&1
    docker rm -f iperf3server >/dev/null 2>&1; echo; } >> "$OUT/iperf3-host-to-container.txt"
done
echo "- iperf3 image is networkstatic/iperf3 (dockerpinata/iperf3:2.1, Docker's internal image, is not public). The image's entrypoint is iperf3, so arguments are passed directly." >> "$OUT/adaptations.txt"

step "7 Docker Desktop cold start x3"
for i in 1 2 3; do
  { echo "## attempt $i  $(date -u +%T)"
    docker desktop stop 2>&1; sleep 5
    t0=$(date +%s.%N); docker desktop start 2>&1; t1=$(date +%s.%N)
    until docker info >/dev/null 2>&1; do sleep 0.2; done; t2=$(date +%s.%N)
    echo "docker desktop start returned after: $(echo "$t1 - $t0" | bc) s"
    echo "docker info answered after: $(echo "$t2 - $t0" | bc) s"; echo; } >> "$OUT/startup.txt"
done
echo "- Startup is measured as wall time from 'docker desktop start' to the first successful 'docker info'; the post never stated its method." >> "$OUT/adaptations.txt"

step "cleanup"
docker rm -f vfs-demo iperf3server postgrestest >/dev/null 2>&1
docker rmi virtiofs-demo:latest >/dev/null 2>&1
docker images --format '{{.Repository}}:{{.Tag}}' > "$WORK/images-after.txt"
comm -13 <(sort "$WORK/images-before.txt") <(sort "$WORK/images-after.txt") | tee "$OUT/images-removed.txt" | xargs -n1 docker rmi >/dev/null 2>&1
cd /; rm -rf "$WORK"
echo "=== run finished $(date -u +%FT%TZ)"
