diff --git a/scripts/pgo-corpus/perfilar.sh b/scripts/pgo-corpus/perfilar.sh new file mode 100755 index 00000000..b9ff162e --- /dev/null +++ b/scripts/pgo-corpus/perfilar.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# perfilar.sh — corrida de entrenamiento PGO: recorre el corpus con el firefox INSTRUMENTADO y deja +# los `.profraw` en /salida. Pensado para correr dentro de un bwrap con: +# --ro-bind / --ro-bind /pgo --bind /salida --unshare-pid +# +# ══ TRES DEFENSAS QUE NO SON PARANOIA: LAS TRES SE PAGARON ═════════════════════════════════════ +# +# 1. `--unshare-pid` EN EL BWRAP (fuera de este script). Sin él los hijos SOBREVIVEN al sandbox: un +# `http.server` quedó vivo 19 HORAS, retuvo el puerto y envenenó las corridas siguientes. +# +# 2. PUERTO ALEATORIO POR CORRIDA. Elimina la colisión de raíz en vez de detectarla: si otro proceso +# tiene un puerto, este arranque usa otro y no se entera. +# +# 3. MARCADOR ÚNICO POR CORRIDA, servido desde una copia ESCRIBIBLE del corpus. La primera versión +# horneaba el marcador como constante del script, y eso rompía justo lo que el chequeo existe +# para probar: un servidor ajeno servía el MISMO fichero de marca y el chequeo lo daba por bueno. +# Verificaba «alguien sirve este contenido», no «este servidor es el mío». +# +# ⚠ Y LOS SANDBOXES DE FIREFOX VAN APAGADOS. Con ellos los procesos hijo mueren con SIGNAL 11, el +# que renderiza no llega a nacer, el servidor registra 0 GET y el único `.profraw` es el del padre +# arrancando: un perfil de nada, con todo en verde. Es lo mismo que hace el `profileserver.py` de +# Mozilla. Sólo aplica al entrenamiento; el firefox que se distribuye lleva sus sandboxes intactos. +set -u +export HOME=/tmp/home; mkdir -p "$HOME" +export LANG=C.UTF-8 MOZ_HEADLESS=1 LIBGL_ALWAYS_SOFTWARE=1 +export MOZ_DISABLE_CONTENT_SANDBOX=1 MOZ_DISABLE_GMP_SANDBOX=1 MOZ_DISABLE_RDD_SANDBOX=1 MOZ_DISABLE_SOCKET_PROCESS_SANDBOX=1 +export LLVM_PROFILE_FILE=/salida/ff-%p-%m.profraw + +MARCA="pgo-$$-$(cat /proc/sys/kernel/random/uuid 2>/dev/null || echo ${RANDOM:-0}${RANDOM:-0})" +PUERTO=$(( 20000 + $$ % 20000 )) + +# Copia ESCRIBIBLE del corpus (tmpfs): hace falta para poner el marcador dentro de lo que se sirve. +SERVIR=/tmp/servir; mkdir -p "$SERVIR"; cp -a /pgo/. "$SERVIR"/ 2>/dev/null +printf '%s\n' "$MARCA" > "$SERVIR/marca.txt" + +cd "$SERVIR" && /usr/bin/python3 -m http.server "$PUERTO" --bind 127.0.0.1 > /salida/httpd.log 2>&1 & + +# Espera CON REINTENTO (un `sleep` fijo concluía «no responde» sobre un servidor que sí iba a +# responder) y exigiendo el marcador de ESTA corrida. +i=0 +while [ $i -lt 25 ]; do + got=$(/usr/bin/python3 -c "import urllib.request +try: print(urllib.request.urlopen('http://127.0.0.1:$PUERTO/marca.txt',timeout=3).read().decode().strip()) +except Exception: pass" 2>/dev/null) + [ "$got" = "$MARCA" ] && break + i=$((i+1)); sleep 1 +done +[ $i -lt 25 ] || { + echo "!! en $PUERTO no contesta MI servidor (marca leída: '${got:-nada}') — abortando antes de" >&2 + echo " generar perfiles de páginas que nunca se cargaron." >&2 + tail -3 /salida/httpd.log >&2 + exit 1 +} +echo "== servidor propio OK en $PUERTO" + +n=0 +for f in $(cd "$SERVIR" && find . -name '*.html' | sed 's|^\./||' | sort); do + n=$((n+1)) + LD_LIBRARY_PATH=/usr/lib/firefox timeout 200 /usr/lib/firefox/firefox --headless \ + --screenshot /salida/shot.png "http://127.0.0.1:$PUERTO/$f" >/dev/null 2>&1 + printf '.' +done +echo "" +echo "== páginas recorridas: $n" +echo "== GETs servidos: $(grep -c GET /salida/httpd.log 2>/dev/null)" +echo "== .profraw: $(ls /salida/*.profraw 2>/dev/null | wc -l)"