#!/usr/bin/env bash # # TP6 — Durchlauf 2: dieselbe Saettigung wie tp6-bufferbloat-messung.sh, aber mit laufendem # Videocall, mit Phasenmarken auf derselben Zeitachse wie Sampler + Konsole — und mit einer # Anleitung, die waehrend des Calls auf der Konsole steht. # # Messparameter BEWUSST identisch mit Durchlauf 1 (3 Flows x 430 KB/s, 24 Pings, 30 s Settle). # # 🔴 Der Treiber schreibt phase.json im 5-Sekunden-Takt. Die Konsole erkennt daran, dass # ueberhaupt gemessen wird — ohne das geht ein Start-Klick still ins Leere, der Call # laeuft ohne Last, und "keine Probleme" liest sich wie ein Ergebnis, obwohl es eine # Nicht-Messung ist. (Am 2026-08-20 genau so passiert: 5,5 Minuten Call, nichts gemessen.) # # Misst nur. Aendert nichts am Netz. set -uo pipefail RUN_DIR="${TP6_RUN_DIR:-/private/tmp/claude-501/-Users-christophemsenhuber-dev-bf-network-r6/0d86ebd1-035f-4513-a231-5cca8111ecfd/scratchpad/tp6-run2}" mkdir -p "$RUN_DIR" MARKERS="$RUN_DIR/markers.csv" PIDFILE="$RUN_DIR/flows.pid" STATE="$RUN_DIR/phase.json" GO_FLAG="$RUN_DIR/go.flag" ABORT_FLAG="$RUN_DIR/abort.flag" TARGET="1.1.1.1" PINGS=24 SETTLE=30 UPLOAD_RATE_KB=430 C0=90 C1=60 STEPS=8 UPLOAD_FILE="$(mktemp -t tp6-upload).bin" CF_UA="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" CF_REF="https://speed.cloudflare.com/" [[ -f "$MARKERS" ]] || echo "ts_epoch,ts_local,marker" > "$MARKERS" MODE="wartet"; PHASE="—"; TITLE=""; INST=""; STEP=0; ENDS=0 # Zustand fuer die Konsole. Wird zusaetzlich vom Heartbeat im 5-s-Takt neu geschrieben, # damit die Konsole einen toten Treiber erkennt. put_state() { # 🔴 Atomar schreiben (tmp + mv): die Konsole liest die Datei im Sekundentakt und # bekaeme sonst halb geschriebenes JSON zu sehen. python3 - "$STATE" "$MODE" "$PHASE" "$TITLE" "$INST" "$STEP" "$STEPS" "$ENDS" <<'PY' import json, os, sys p, mode, phase, title, inst, step, steps, ends = sys.argv[1:9] tmp = p + ".tmp" with open(tmp, "w") as fh: json.dump({"mode": mode, "phase": phase, "title": title, "instruction": inst, "step": int(step), "steps": int(steps), "ends": int(ends)}, fh) os.replace(tmp, p) PY } mark() { printf '%s,%s,%s\n' "$(date +%s)" "$(date +%H:%M:%S)" "$1" >> "$MARKERS"; } phase() { # phase PHASE="$1"; local dur="$2"; TITLE="$3"; INST="$4" STEP=$((STEP + 1)); ENDS=$(( $(date +%s) + dur )); MODE="messung" put_state; mark "PHASE_$PHASE" printf '\n\033[1;36m== %s ==\033[0m %s\n' "$PHASE" "$(date +%H:%M:%S)" } aborted() { [[ -f "$ABORT_FLAG" ]]; } cleanup_flows() { if [[ -f "$PIDFILE" ]]; then while read -r p; do [[ "$p" =~ ^[0-9]+$ ]] && kill "$p" 2>/dev/null; done < "$PIDFILE" : > "$PIDFILE" fi } # 🔴 Der Heartbeat aktualisiert NUR die mtime. Er darf den Zustand nicht schreiben: eine # Subshell sieht die Variablen vom Fork-Zeitpunkt und wuerde die Anzeige dauerhaft auf # den Anfangszustand zuruecksetzen (und sich mit dem Hauptprozess ueberschreiben). ( while true; do touch "$STATE" 2>/dev/null; sleep 5; done ) & HEARTBEAT=$! trap 'kill $HEARTBEAT 2>/dev/null; cleanup_flows; rm -f "$UPLOAD_FILE"' EXIT # --- warten auf den Start-Klick ------------------------------------------------------- rm -f "$GO_FLAG" "$ABORT_FLAG"; : > "$PIDFILE" MODE="wartet"; PHASE="BEREIT"; STEP=0; ENDS=0 TITLE="Warte auf den Start-Klick" INST="Sobald der Call steht: 📞 Call verbunden drücken. Vorher nichts weiter tun — Telefon in die Halterung, keine Downloads." put_state echo "Warte auf den Start-Klick …" while [[ ! -f "$GO_FLAG" ]]; do sleep 0.5; done mkfile 200M "$UPLOAD_FILE" 2>/dev/null || dd if=/dev/zero of="$UPLOAD_FILE" bs=1m count=200 2>/dev/null # --- C0: Call ohne Last --------------------------------------------------------------- phase "C0" $((C0 + 25)) "Baseline — Call ohne Last" \ "Einfach reden. Nichts tun: Telefon nicht bewegen, nichts herunterladen, Kamera anlassen. Das ist der Vergleichsmaßstab für alles Folgende." ping -c "$PINGS" "$TARGET" > "$RUN_DIR/ping_C0.txt" 2>&1 sleep "$C0" # --- U: Upload-Saettigung ------------------------------------------------------------- phase "U-settle" "$SETTLE" "Upload-Last baut sich auf" \ "Ab jetzt ist Stocken erwartbar — und zwar eher bei Geli: sie hört/sieht dich schlechter. Wenn sie etwas meldet: 🟠 drücken. Nicht eingreifen." for _ in 1 2 3; do curl -s -o /dev/null -A "$CF_UA" -e "$CF_REF" --limit-rate "${UPLOAD_RATE_KB}K" \ --data-binary @"$UPLOAD_FILE" "https://speed.cloudflare.com/__up" & echo $! >> "$PIDFILE" done sleep "$SETTLE" if aborted; then mark "U_ABGEBROCHEN_waehrend_settle" else phase "U-ping" $((PINGS + 2)) "Upload-Last + Messung läuft" \ "Die eigentliche Messung. Weiterreden, Probleme klicken (🟠 Geli / 🔴 du / 🎬 Versatz). Nur wenn der Call abzubrechen droht: ⛔." ping -c "$PINGS" "$TARGET" > "$RUN_DIR/ping_U.txt" 2>&1 aborted && mark "U_ABGEBROCHEN_waehrend_ping" fi cleanup_flows phase "U-recovery" 30 "Last ist weg — erholt sich der Call?" \ "Genau hinhören: wird es sofort wieder gut? Dann 🟢 drücken. Das ist der Beweis, dass die Last die Ursache war." sleep 30 rm -f "$ABORT_FLAG" # --- D: Download-Saettigung ----------------------------------------------------------- phase "D-settle" "$SETTLE" "Download-Last baut sich auf" \ "Jetzt andersherum: eher du hörst/siehst schlechter. Bei Problemen 🔴 drücken." : > "$PIDFILE" for _ in 1 2 3; do curl -s -o /dev/null -A "$CF_UA" -e "$CF_REF" "https://speed.cloudflare.com/__down?bytes=2000000000" & echo $! >> "$PIDFILE" done sleep "$SETTLE" if aborted; then mark "D_ABGEBROCHEN_waehrend_settle" else phase "D-ping" $((PINGS + 2)) "Download-Last + Messung läuft" \ "Letzte Lastphase. Weiterreden, Probleme klicken. Not-Aus nur, wenn es kippt." ping -c "$PINGS" "$TARGET" > "$RUN_DIR/ping_D.txt" 2>&1 aborted && mark "D_ABGEBROCHEN_waehrend_ping" fi cleanup_flows rm -f "$ABORT_FLAG" # --- C1: Ruhiger Abschluss ------------------------------------------------------------ phase "C1" $((C1 + 25)) "Abschluss — Call ohne Last" \ "Last ist weg. Noch eine Minute ruhig reden, damit der Vergleich zum Anfang sauber ist. Danach ist die Messung durch." ping -c "$PINGS" "$TARGET" > "$RUN_DIR/ping_C1.txt" 2>&1 sleep "$C1" # --- Langzeit-Modus: Aufzeichnung laeuft weiter, Messung ist fertig -------------------- MODE="langzeit"; PHASE="LANGZEIT"; STEP=$STEPS; ENDS=0 TITLE="Messung abgeschlossen — Aufzeichnung läuft weiter" INST="Die TP6-Zahlen sind im Kasten. Ab jetzt wird nur noch dein WLAN-Link mitgeschrieben, beliebig lange.

Roaming-Test, wenn du magst: mit laufendem Call 🚶 drücken, langsam in den entferntesten Raum gehen, dort 📍 drücken und ~60 s stehen bleiben, dann zurück (wieder 🚶 / 📍). Alles, was dabei stockt oder asynchron wird, bitte klicken — dann sehe ich, ob genau dann der AP gewechselt hat.

Wenn Schluss ist: 📴." put_state; mark "PHASE_LANGZEIT" echo echo "Messung fertig. Langzeit-Aufzeichnung laeuft — Treiber laeuft weiter (Ctrl-C beendet ihn)." while true; do sleep 5; done