SDD 26: la ganancia del PGO, medida — y sale al revés de lo esperable

DOM+layout+strings, FUERA del corpus:  23.540 -> 21.327 ms   -9,4%
  SunSpider 3d-raytrace, DENTRO:         16.034 -> 15.878 ms   -1,0%

Mismo rootfs, mismo script, corridas intercaladas A/B/A/B, mediana de 7,
calentamiento descartado; lo único que cambia entre variantes es un --ro-bind de
/usr/lib/firefox. Los rangos no se solapan en ninguna de las dos, así que ambas
diferencias son reales y no ruido.

Yo esperaba lo contrario: que medir sobre el conjunto de ENTRENAMIENTO inflara
la ganancia. Da el número MÁS BAJO, y la razón es mejor que la predicción:
3d-raytrace es aritmética pura en un bucle caliente, y ese bucle no lo ejecuta
el C++ de SpiderMonkey sino código máquina que el JIT genera en runtime. El PGO
optimiza el intérprete, el GC y el propio JIT — no lo que el JIT emite. Un
benchmark JIT-bound es casi ciego al PGO por construcción.

Donde se ve es en DOM/layout/arranque, que es C++ de punta a punta, y que además
es lo que el usuario percibe: la medición cubre el ciclo completo del proceso
(arrancar, renderizar, capturar, salir), no el régimen de una página cargada.

Corolario anotado: el corpus de entrenamiento está sesgado hacia JS justo donde
el PGO menos rinde. Un corpus con más maquetación probablemente daría más. Es su
propia unidad de trabajo.
This commit is contained in:
Sergio
2026-09-07 16:20:20 +00:00
parent 70026f5730
commit acccbc0a2c
+28
View File
@@ -227,6 +227,34 @@ llevan `-fprofile-use`**, el configure encontró `llvm-profdata`, y no hay ni un
no cuadre. `libxul.so` pasa de 226.078.752 a 227.802.816 bytes, consistente con inlining de caminos
calientes. Es evidencia de build, no de artefacto, y conviene decirlo así.
**LA GANANCIA, MEDIDA (2026-09-07).** Mismo rootfs, mismo script, corridas INTERCALADAS A/B/A/B
para que la deriva de carga afecte a las dos, mediana de 7, calentamiento descartado. Lo único que
cambia entre variantes es un `--ro-bind` de `/usr/lib/firefox`.
| página | sin PGO | con PGO | |
|---|---|---|---|
| DOM+layout+strings, **fuera** del corpus de entrenamiento | 23.540 ms | 21.327 ms | **9,4 %** |
| SunSpider `3d-raytrace`, **dentro** del corpus | 16.034 ms | 15.878 ms | 1,0 % |
Los rangos no se solapan en ninguna de las dos (23.18523.654 vs 21.03021.650), así que las dos
diferencias son reales y no ruido.
**Y el resultado sale al revés de lo esperable, que es lo interesante.** La intuición dice que
medir sobre el conjunto de ENTRENAMIENTO infla la ganancia; acá el corpus da el número MÁS BAJO. La
razón es que `3d-raytrace` es aritmética pura en un bucle caliente, y ese bucle **no lo ejecuta el
C++ de SpiderMonkey: lo ejecuta código máquina que el JIT genera en tiempo de ejecución**. El PGO
optimiza el intérprete, el GC y el propio compilador JIT — no el código que el JIT emite. Un
benchmark JIT-bound es casi ciego al PGO por construcción.
Donde sí se ve es en el camino DOM/layout/arranque, que es C++ de principio a fin. Y eso es también
lo que un usuario percibe: la medición cubre el ciclo COMPLETO del proceso (arrancar → renderizar →
capturar → salir), no el rendimiento en régimen de una página ya cargada. De ahí que hasta la página
de SunSpider tarde 16 s: casi todo es arranque.
**Corolario para el corpus de entrenamiento:** está sesgado hacia JS (SunSpider domina en número de
páginas) justo donde el PGO menos rinde. Un corpus con más maquetación y menos aritmética
probablemente daría más ganancia. Es una unidad de trabajo propia y no se hace de paso.
**Y la pregunta que un insumo no determinista obliga a hacer, respondida: `firefox` SIGUE
REPRODUCIENDO bit a bit** (`verificar-repro.sh`: REPRODUCEN 1, DERIVA 0, NO-DETERMINISMO 0). Era el
riesgo real de esta unidad, no el rendimiento: si el `-fprofile-use` hubiera metido cualquier