Files
takana/docs/plan-variantes-cpu.md
T

85 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan — variantes por nivel de CPU (x86-64-v3) sobre el CAS
**Fecha:** 2026-07-16 · **Origen:** el linaje Solus (hwcap dirs AVX2 ~2017, lista corta medida)
→ Red Hat (niveles x86-64-v2/v3/v4 + `glibc-hwcaps` en glibc 2.33, selección en el loader)
→ CachyOS (repos enteros v3/v4 + LTO + scheduler). Análisis de qué forma toma eso en hammer.
**Tesis:** hammer ya tiene la mitad difícil gratis. Una variante optimizada no es un mecanismo
nuevo: es **la misma receta con otros `flags`**, que sella a otro hash en el mismo store. Lo que
las distros binarias resuelven con subdirectorios mágicos del loader, hammer lo resuelve con lo
que ya es: contenido direccionado por hash + hydrate.
---
## 1. La restricción que ordena todo el diseño: musl no tiene hwcaps
El mecanismo `glibc-hwcaps` es del loader de **glibc**. El ldso de musl no busca en
subdirectorios por microarquitectura y no va a hacerlo. Conclusión estructural:
> **La selección de variante en hammer ocurre en HYDRATE (por máquina), no en runtime (por
> proceso).** Cada máquina hidrata la variante que su CPU soporta; el árbol instalado tiene UNA
> copia de cada lib, la correcta. Sin dispatch, sin dobles copias en disco, sin loader parcheado.
Esto no es una limitación disfrazada: es el modelo más simple de los dos, y el único compatible
con el resto de hammer (un artefacto = un hash = un contenido; "elige en runtime" rompería la
correspondencia instalado↔sellado que usa todo, del journal a CVE-por-grafo).
Costo honesto: una imagen/USB "para cualquier máquina" debe llevar baseline (o dos hydrates).
El punto de selección es `hammer hydrate` / el instalador, con sonda de CPU (`cpuid` → nivel).
## 2. Mecanismo: variante = flags, cero framework nuevo
Hoy el sandbox fija `CC="zig cc -mcpu=baseline"` (`sandbox.rs:415`) precisamente para NO hornear
la ISA del builder. Una variante v3 es el mismo contrato con otro valor pineado:
- **T1 — campo `variant` en la receta** (o sección `[variants.v3]` que sólo sobreescribe
`flags`/`mcpu`). Regla dura: la variante **hereda todo lo demás** de la receta canónica —
misma fuente, mismos patches, mismas deps. Si diverge en algo más, no es una variante, es
otra receta.
- **T2 — `mcpu=x86_64_v3` pineado por nombre de nivel**, nunca `native` (mismo argumento que
baseline: la ISA del builder no puede filtrarse; el nivel es el contrato).
- **T3 — el índice firmado publica `(nombre, versión, nivel, hash)`**. El nivel es un eje más
del catálogo, no un repo aparte (donde CachyOS mantiene N repos, hammer tiene N hashes).
- **T4 — sonda de nivel en hydrate/instalador**: detectar v2/v3/v4 y resolver el hash
correspondiente, con fallback a baseline. Idempotente como todo hydrate.
La bit-repro no se toca: la reproducibilidad es por-(receta, flags); una variante v3 reproduce
contra sí misma en la granja exactamente igual que hoy reproduce baseline.
## 3. Alcance: lista caliente (Solus), NO repo entero (CachyOS)
Recompilar el catálogo entero por nivel multiplica la granja por N para ganancias que en el 90%
de los paquetes son ruido. Solus lo midió hace una década: el beneficio se concentra en un
puñado de libs con kernels vectorizables. Lista caliente inicial (todas ya en el catálogo):
| candidata | por qué |
|---|---|
| `zlib`, `zstd`, `xz` | (de)compresión en cada operación del propio hammer |
| `mesa` | el caso con más ganancia medible en GUI/juegos (llvmpipe/ACO vectorizan) |
| códecs (ffmpeg-clase, cuando entren) | el caso clásico AVX2 |
| `pixman`, `cairo` | raster 2D — **frontera GUI: sólo en worker** (gotcha zig-skew) |
- **T5 — piloto medido**: v3 de `zlib` + `zstd`, benchmark antes/después con carga real de
hammer (pack/hydrate de N artefactos). Si la ganancia no es medible ahí, la lista se corta
temprano y barato.
- **T6 — regla de admisión**: una lib entra a la lista caliente con benchmark que lo
justifique, no por vibras. La lista vive en el repo junto a los números.
## 4. Lo que NO se hace
- **Repo entero v3/v4** — coste de granja ×N por ganancia marginal fuera de la lista caliente.
- **Dispatch en runtime / hwcaps** — no existe en musl y el modelo por-máquina es mejor para
hammer de todos modos (§1).
- **`-mcpu=native` jamás** — ni en variantes: el nivel nombrado es el contrato reproducible.
- **LTO generalizado como campaña** — hammer ya linkea estático con zig; el LTO por-receta se
evalúa donde el benchmark de T5/T6 lo pida, no como política global.
## Orden propuesto
1. **T5** (piloto zlib/zstd en worker, benchmark) — decide si el frente vale antes de tocar
framework.
2. **T1T2** (campo variant + mcpu pineado) — sólo si T5 da ganancia medible.
3. **T3T4** (índice + sonda en hydrate) — cierra el ciclo usable.
4. **mesa v3** — el premio gordo para juegos; coordinar con el plan de jaula de juegos
(`plan-jaula-juegos.md`), siempre en worker.