Download SmartTest.sh from HelloSun/sdcpp_zimage_opt: direct link, hf CLI and curl.
- Browser
- Download file 11.2 kB
-
https://huggingface.co/HelloSun/sdcpp_zimage_opt/resolve/main/SmartTest.sh
- Command line
-
hf download hf://HelloSun/sdcpp_zimage_opt/SmartTest.sh
-
curl -L -o SmartTest.sh https://huggingface.co/HelloSun/sdcpp_zimage_opt/resolve/main/SmartTest.sh
11.2 kB
| # SmartTest.sh - generate the same cat+snake image with every built variant and write a speed report. | |
| # | |
| # ./SmartTest.sh # all rows of the matrix, 1 repeat | |
| # REPEAT=3 ./SmartTest.sh # median of 3 runs per row | |
| # ./SmartTest.sh --only Q8 # only rows whose name contains "Q8" | |
| # | |
| # Output (in results/): | |
| # results.csv one line per run | |
| # results.md comparison table (medians), ready for the model card | |
| # hardware.txt machine configuration used for the run | |
| # images/*.png generated 512x512 images | |
| # logs/*.log raw sd-cli logs | |
| set -euo pipefail | |
| ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| WORK="${WORK:-$PWD/work}" | |
| BIN="$WORK/bin" | |
| MODELS="$WORK/models" | |
| OUT="${OUT:-$ROOT/results}" | |
| PY="$WORK/venv/bin/python"; [[ -x "$PY" ]] || PY="$(command -v python3)" | |
| THREADS="${THREADS:-$(nproc)}" | |
| CPUSET="${CPUSET:-0-$((THREADS - 1))}" | |
| REPEAT="${REPEAT:-1}" | |
| ONLY="${ONLY:-}" # env ONLY=<substring>, or argument: --only <substring> | |
| [[ "${1:-}" == "--only" ]] && ONLY="${2:?--only needs a substring}" | |
| SEED=42 | |
| STEPS=8 | |
| WIDTH=512 | |
| HEIGHT=512 | |
| PROMPT="cute cartoon cat and cute cartoon snake, best friends, hugging together, kawaii, simple clean background, children's book illustration, soft colors, adorable" | |
| NEGATIVE="blurry, low quality, realistic, photo" | |
| # name | variant | model key | extra env (- = none) | |
| MATRIX=( | |
| "stock-Q4_K|stock|Q4_K|-" | |
| "avx2-Q4_K|avx2|Q4_K|-" | |
| "avx512-Q4_K|avx512|Q4_K|-" | |
| "amx_lto-Q4_K|amx_lto|Q4_K|-" | |
| "amx_lto-Q4_K+AMXw|amx_lto|Q4_K|SD_CPU_EXTRA_BUFT=1" | |
| "amx_lto-Q4_K-ffn13|amx_lto|Q4_K-ffn13|-" | |
| "amx_lto-Q4_K-ffn13+AMXw|amx_lto|Q4_K-ffn13|SD_CPU_EXTRA_BUFT=1" | |
| "amx_lto-Q4_0|amx_lto|Q4_0|-" | |
| "amx_lto-Q8_0|amx_lto|Q8_0|-" | |
| "amx_lto-Q8_0+AMXw|amx_lto|Q8_0|SD_CPU_EXTRA_BUFT=1" | |
| # stage 1 (VAE decode): llamafile sgemm build, with and without conv-direct for the VAE | |
| "llamafile-Q4_K-ffn13+AMXw|llamafile|Q4_K-ffn13|SD_CPU_EXTRA_BUFT=1|" | |
| "llamafile-Q4_K-ffn13+AMXw+convdirect|llamafile|Q4_K-ffn13|SD_CPU_EXTRA_BUFT=1|--conv-direct auto,vae=on" | |
| # stage P2: refiner weights requantized Q8_0 -> Q4_K (speed-first, opt-in) | |
| "llamafile-Q4_K-ffn13-rq+AMXw+convdirect|llamafile|Q4_K-ffn13-rq|SD_CPU_EXTRA_BUFT=1|--conv-direct auto,vae=on" | |
| ) | |
| model_file() { | |
| case "$1" in | |
| Q4_K) echo "$MODELS/z_image_turbo-Q4_K.gguf" ;; | |
| Q4_K-ffn13) echo "$MODELS/z_image_turbo-Q4_K-ffn13.gguf" ;; | |
| Q4_K-ffn13-rq) echo "$MODELS/z_image_turbo-Q4_K-ffn13-rq.gguf" ;; | |
| Q4_0) echo "$MODELS/z_image_turbo-Q4_0.gguf" ;; | |
| Q8_0) echo "$MODELS/z_image_turbo-Q8_0.gguf" ;; | |
| *) return 1 ;; | |
| esac | |
| } | |
| log() { printf '\033[1;32m[smarttest]\033[0m %s\n' "$*"; } | |
| mkdir -p "$OUT/images" "$OUT/logs" | |
| CSV="$OUT/results.csv" | |
| # APPEND=1 keeps existing rows in results.csv (additive testing: only new rows are run). | |
| if [[ "${APPEND:-0}" != "1" || ! -s "$CSV" ]]; then | |
| echo "name,variant,model,env,rep,status,sampling_s,generate_s,wall_s,peak_rss_gib,diff_mean_vs_ref,diff_max_vs_ref,image" > "$CSV" | |
| fi | |
| # ------------------------------------------------------------ hardware report | |
| { | |
| echo "date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" | |
| echo "os: $(. /etc/os-release && echo "$PRETTY_NAME")" | |
| echo "kernel: $(uname -r)" | |
| echo "cpu: $(lscpu | awk -F: '/^Model name/ {sub(/^ +/,"",$2); print $2}')" | |
| echo "sockets: $(lscpu | awk -F: '/^Socket/ {sub(/^ +/,"",$2); print $2}')" | |
| echo "cores/threads per socket: $(lscpu | awk -F: '/^Core\(s\) per socket/ {sub(/^ +/,"",$2); print $2}') / $(lscpu | awk -F: '/^Thread\(s\) per core/ {sub(/^ +/,"",$2); print $2}') SMT" | |
| echo "numa nodes: $(lscpu | awk -F: '/^NUMA node\(s\)/ {sub(/^ +/,"",$2); print $2}')" | |
| echo "cpu flags: $(grep -o -E 'avx512f|avx512_vnni|avx512_bf16|amx_int8|amx_bf16|avx2' /proc/cpuinfo | sort -u | tr '\n' ' ')" | |
| echo "cgroup cpu quota: $(cat /sys/fs/cgroup/cpu.max 2>/dev/null || echo n/a)" | |
| echo "threads used: $THREADS cpuset: $CPUSET" | |
| echo "memory: $(free -g | awk '/^Mem:/ {print $2" GiB total"}')" | |
| echo "gpu: $(nvidia-smi -L 2>&1 | head -1) (no GPU backend used; CPU-only inference)" | |
| echo "gcc: $(gcc -dumpfullversion 2>/dev/null || echo n/a)" | |
| echo "cmake: $(cmake --version 2>/dev/null | head -1 || echo n/a)" | |
| echo "sd.cpp: $(git -C "$WORK/stable-diffusion.cpp" rev-parse HEAD 2>/dev/null || echo n/a)" | |
| echo "openvino env: $("$WORK/venv-ov/bin/python" -c 'import openvino, optimum.intel, diffusers; print(f"openvino {openvino.__version__}, optimum-intel {optimum.intel.__version__}, diffusers {diffusers.__version__}")' 2>/dev/null || echo n/a)" | |
| echo "openvino model: HelloSun/Z-Image-Turbo-OpenVINO-INT4 (transformer/text_encoder INT4, VAE INT8)" | |
| echo "prompt: $PROMPT" | |
| echo "negative: $NEGATIVE" | |
| echo "size/steps/seed/cfg: ${WIDTH}x${HEIGHT} / $STEPS / $SEED / 1.0 (euler, simple scheduler)" | |
| } > "$OUT/hardware.txt" | |
| # ------------------------------------------------------------ run cases | |
| REF_IMAGE="" | |
| [[ -f "$OUT/images/stock-Q4_K-r1.png" ]] && REF_IMAGE="$OUT/images/stock-Q4_K-r1.png" | |
| OV_DIR="$MODELS/Z-Image-Turbo-OpenVINO-INT4" | |
| OV_PY="$WORK/venv-ov/bin/python" | |
| # run_case <name> <variant> <model-label> <env-spec> <rep-command...> | |
| # The rep-command is executed under taskset; "__IMG__" is replaced by the output image path. | |
| # It must print sd-cli style timing lines (sampling / generate_image) on stderr. | |
| run_case() { | |
| local name="$1" variant="$2" mlabel="$3" envspec="$4"; shift 4 | |
| local extra=() | |
| if [[ -n "${RUN_EXTRA:-}" ]]; then read -ra extra <<< "$RUN_EXTRA"; fi | |
| local envprefix=() | |
| [[ "$envspec" != "-" ]] && envprefix=(env "$envspec") | |
| for rep in $(seq 1 "$REPEAT"); do | |
| local tag="${name}-r${rep}" | |
| local log_file="$OUT/logs/$tag.log" | |
| local img="$OUT/images/$tag.png" | |
| log "run $tag" | |
| local cmd=() a | |
| for a in "$@" "${extra[@]}"; do | |
| if [[ "$a" == "__IMG__" ]]; then cmd+=("$img"); else cmd+=("$a"); fi | |
| done | |
| # stdout and stderr of the generator both go to the log; measure_rss appends its summary line too. | |
| set +e | |
| "${envprefix[@]}" "$PY" "$ROOT/tools/measure_rss.py" taskset -c "$CPUSET" "${cmd[@]}" \ | |
| > "$log_file" 2>&1 | |
| local rc=$? | |
| set -e | |
| local rss_line sampling generate wall | |
| rss_line="$(grep -oE 'PEAK_RSS=[0-9.]+' "$log_file" | cut -d= -f2 | tail -1 || true)" | |
| sampling="$(grep -oE 'sampling completed, taking [0-9.]+' "$log_file" | grep -oE '[0-9.]+' | tail -1 || true)" | |
| generate="$(grep -oE 'generate_image completed in [0-9.]+' "$log_file" | grep -oE '[0-9.]+' | tail -1 || true)" | |
| wall="$(grep -oE 'WALL=[0-9.]+' "$log_file" | cut -d= -f2 | tail -1 || true)" | |
| local status="ok" diff_mean="" diff_max="" | |
| if [[ $rc -ne 0 || ! -s "$img" ]]; then | |
| status="failed(rc=$rc)" | |
| else | |
| [[ -z "$REF_IMAGE" ]] && REF_IMAGE="$img" | |
| read -r diff_mean diff_max < <("$PY" - "$REF_IMAGE" "$img" <<'PY' | |
| import sys | |
| import numpy as np | |
| from PIL import Image | |
| a = np.asarray(Image.open(sys.argv[1]).convert("RGB")).astype(int) | |
| b = np.asarray(Image.open(sys.argv[2]).convert("RGB")).astype(int) | |
| d = np.abs(a - b) | |
| print(f"{d.mean():.4f} {d.max()}") | |
| PY | |
| ) | |
| fi | |
| echo "$name,$variant,$mlabel,$envspec,$rep,$status,$sampling,$generate,$wall,$rss_line,$diff_mean,$diff_max,images/$tag.png" >> "$CSV" | |
| log " $status sampling=${sampling:-?}s generate=${generate:-?}s rss=${rss_line:-?}GiB diff_mean=${diff_mean:-n/a}" | |
| done | |
| } | |
| # ---- sd.cpp matrix | |
| for row in "${MATRIX[@]}"; do | |
| IFS='|' read -r name variant mkey envspec extra_args <<< "$row" | |
| if [[ -n "$ONLY" && "$name" != *"$ONLY"* ]]; then continue; fi | |
| sdbin="$BIN/$variant/sd-cli" | |
| model="$(model_file "$mkey")" | |
| if [[ ! -x "$sdbin" || ! -f "$model" ]]; then | |
| log "skip $name (missing binary or model)" | |
| echo "$name,$variant,$mkey,$envspec,0,missing,,,,,,,," >> "$CSV" | |
| continue | |
| fi | |
| RUN_EXTRA="${extra_args:-}" | |
| run_case "$name" "$variant" "$mkey" "$envspec" \ | |
| "$sdbin" \ | |
| --diffusion-model "$model" \ | |
| --vae "$MODELS/ae.safetensors" \ | |
| --llm "$MODELS/Qwen3-4B-Instruct-2507-Q4_K_M.gguf" \ | |
| -p "$PROMPT" -n "$NEGATIVE" \ | |
| -W "$WIDTH" -H "$HEIGHT" --steps "$STEPS" --cfg-scale 1.0 \ | |
| --seed "$SEED" --sampling-method euler --scheduler simple \ | |
| -t "$THREADS" -o "__IMG__" | |
| done | |
| # ---- OpenVINO INT4 (HelloSun/Z-Image-Turbo-OpenVINO-INT4), 8 steps to match sd.cpp; same prompt/seed/size | |
| for ov_row in "ov-int4-8step|8"; do | |
| IFS='|' read -r name steps <<< "$ov_row" | |
| if [[ -n "$ONLY" && "$name" != *"$ONLY"* ]]; then continue; fi | |
| if [[ ! -x "$OV_PY" || ! -d "$OV_DIR" ]]; then | |
| log "skip $name (missing OpenVINO venv or model; see build.sh)" | |
| echo "$name,openvino,OV-INT4,-,0,missing,,,,,,,," >> "$CSV" | |
| continue | |
| fi | |
| run_case "$name" "openvino" "OV-INT4" "-" \ | |
| "$OV_PY" "$ROOT/tools/ov_bench.py" \ | |
| --model-dir "$OV_DIR" -p "$PROMPT" \ | |
| -W "$WIDTH" -H "$HEIGHT" --steps "$steps" --seed "$SEED" -o "__IMG__" | |
| done | |
| # ------------------------------------------------------------ report (medians) | |
| "$PY" - "$CSV" "$OUT/results.md" <<'PY' | |
| import csv, statistics, sys | |
| from collections import OrderedDict | |
| rows = list(csv.DictReader(open(sys.argv[1]))) | |
| groups = OrderedDict() | |
| for r in rows: | |
| if r["status"] != "ok": | |
| continue | |
| groups.setdefault(r["name"], []).append(r) | |
| def med(values): | |
| vals = [float(v) for v in values if v not in ("", None)] | |
| return statistics.median(vals) if vals else None | |
| ref = None | |
| if "stock-Q4_K" in groups: | |
| ref = med([r["generate_s"] for r in groups["stock-Q4_K"]]) | |
| lines = [ | |
| "| # | 版本 (variant) | 模型 | 額外環境變數 | 採樣 (s) | 總生成 (s) | 相對 stock | 峰值 RSS (GiB) | 與 stock 像素差 (mean/max) |", | |
| "|---|---|---|---|---|---|---|---|---|", | |
| ] | |
| for i, (name, rs) in enumerate(groups.items(), 1): | |
| samp = med([r["sampling_s"] for r in rs]) | |
| gen = med([r["generate_s"] for r in rs]) | |
| rss = med([r["peak_rss_gib"] for r in rs]) | |
| dm = med([r["diff_mean_vs_ref"] for r in rs]) | |
| dmx = med([r["diff_max_vs_ref"] for r in rs]) | |
| f1 = lambda v: "n/a" if v is None else f"{v:.1f}" | |
| f2 = lambda v: "n/a" if v is None else f"{v:.2f}" | |
| speed = f"{ref / gen:.2f}x" if ref and gen else "n/a" | |
| diff = "ref" if name == "stock-Q4_K" else (f"{dm:.2f} / {dmx:.0f}" if dm is not None else "n/a") | |
| env = rs[0]["env"] if rs[0]["env"] != "-" else "-" | |
| if "convdirect" in name: | |
| env = (env + " + conv-direct") if env != "-" else "conv-direct" | |
| lines.append(f"| {i} | {rs[0]['variant']} | {rs[0]['model']} | {env} | {f1(samp)} | {f1(gen)} | {speed} | {f2(rss)} | {diff} |") | |
| lines.append("") | |
| lines.append(f"n = {max((len(v) for v in groups.values()), default=0)} run(s) per row (median). Speedup = stock-Q4_K generate time / row generate time.") | |
| open(sys.argv[2], "w").write("\n".join(lines) + "\n") | |
| print("\n".join(lines)) | |
| PY | |
| log "results: $CSV" | |
| log "table: $OUT/results.md" | |