1# Plan — variantes por nivel de CPU (x86-64-v3) sobre el CAS
2
3**Fecha:** 2026-07-16 · **Origen:** el linaje Solus (hwcap dirs AVX2 ~2017, lista corta medida)
4→ Red Hat (niveles x86-64-v2/v3/v4 + `glibc-hwcaps` en glibc 2.33, selección en el loader)
5→ CachyOS (repos enteros v3/v4 + LTO + scheduler). Análisis de qué forma toma eso en takana.
6
7**Tesis:** takana ya tiene la mitad difícil gratis. Una variante optimizada no es un mecanismo
8nuevo: es **la misma receta con otros `flags`**, que sella a otro hash en el mismo store. Lo que
9las distros binarias resuelven con subdirectorios mágicos del loader, takana lo resuelve con lo
10que ya es: contenido direccionado por hash + hydrate.
11
12---
13
14## 1. La restricción que ordena todo el diseño: musl no tiene hwcaps
15
16El mecanismo `glibc-hwcaps` es del loader de **glibc**. El ldso de musl no busca en
17subdirectorios por microarquitectura y no va a hacerlo. Conclusión estructural:
18
19> **La selección de variante en takana ocurre en HYDRATE (por máquina), no en runtime (por
20> proceso).** Cada máquina hidrata la variante que su CPU soporta; el árbol instalado tiene UNA
21> copia de cada lib, la correcta. Sin dispatch, sin dobles copias en disco, sin loader parcheado.
22
23Esto no es una limitación disfrazada: es el modelo más simple de los dos, y el único compatible
24con el resto de takana (un artefacto = un hash = un contenido; "elige en runtime" rompería la
25correspondencia instalado↔sellado que usa todo, del journal a CVE-por-grafo).
26
27Costo honesto: una imagen/USB "para cualquier máquina" debe llevar baseline (o dos hydrates).
28El punto de selección es `takana hydrate` / el instalador, con sonda de CPU (`cpuid` → nivel).
29
30## 2. Mecanismo: variante = flags, cero framework nuevo
31
32Hoy el sandbox fija `CC="zig cc -mcpu=baseline"` (`sandbox.rs:415`) precisamente para NO hornear
33la ISA del builder. Una variante v3 es el mismo contrato con otro valor pineado:
34
35- **T1 — campo `variant` en la receta** (o sección `[variants.v3]` que sólo sobreescribe
36 `flags`/`mcpu`). Regla dura: la variante **hereda todo lo demás** de la receta canónica —
37 misma fuente, mismos patches, mismas deps. Si diverge en algo más, no es una variante, es
38 otra receta.
39- **T2 — `mcpu=x86_64_v3` pineado por nombre de nivel**, nunca `native` (mismo argumento que
40 baseline: la ISA del builder no puede filtrarse; el nivel es el contrato).
41- **T3 — el índice firmado publica `(nombre, versión, nivel, hash)`**. El nivel es un eje más
42 del catálogo, no un repo aparte (donde CachyOS mantiene N repos, takana tiene N hashes).
43- **T4 — sonda de nivel en hydrate/instalador**: detectar v2/v3/v4 y resolver el hash
44 correspondiente, con fallback a baseline. Idempotente como todo hydrate.
45
46La bit-repro no se toca: la reproducibilidad es por-(receta, flags); una variante v3 reproduce
47contra sí misma en la granja exactamente igual que hoy reproduce baseline.
48
49## 3. Alcance: lista caliente (Solus), NO repo entero (CachyOS)
50
51Recompilar el catálogo entero por nivel multiplica la granja por N para ganancias que en el 90%
52de los paquetes son ruido. Solus lo midió hace una década: el beneficio se concentra en un
53puñado de libs con kernels vectorizables. Lista caliente inicial (todas ya en el catálogo):
54
55| candidata | por qué |
56|---|---|
57| `zlib`, `zstd`, `xz` | (de)compresión en cada operación del propio takana |
58| `mesa` | el caso con más ganancia medible en GUI/juegos (llvmpipe/ACO vectorizan) |
59| códecs (ffmpeg-clase, cuando entren) | el caso clásico AVX2 |
60| `pixman`, `cairo` | raster 2D — **frontera GUI: sólo en worker** (gotcha zig-skew) |
61
62- **T5 — piloto medido (2026-07-17, laptop TigerLake, clang 3 variantes base/v3/v4,
63 corpus 200MB mixto fuente+binarios):**
64 - **zstd: v3/v4 NO pagan — CORTADO de la lista.** Bench interno (`-b3 -i7`, estable):
65 base 144.2 vs v4 146.5 MB/s comprimiendo, 702 vs 692 descomprimiendo = ruido. Causa
66 conocida: zstd ya hace dispatch BMI2/AVX2 en **runtime** ⇒ el `-march` del build casi no
67 toca los kernels calientes. (Un +24% aparente de v4 en la 1ª tanda desapareció con i7:
68 era calentamiento — lección para T6: sólo benchs con control de varianza.)
69 - **zlib (madler): INCONCLUSO en laptop con carga** (el mismo binario base osciló 112–157
70 MB/s entre tandas). Pero la pregunta estaba mal hecha: la respuesta buena no es una
71 variante v3 de zlib sino **zlib-ng** (fork con SIMD y dispatch en runtime, drop-in ABI;
72 Fedora 40 ya lo adoptó como zlib del sistema) ⇒ un solo artefacto, cero maquinaria de
73 variantes. Candidato a receta; medir zlib-ng vs zlib en máquina quieta cuando toque.
74 - **Consecuencia estructural**: los compresores modernos ya resuelven esto con dispatch
75 interno ⇒ la lista caliente de variantes se concentra donde NO hay dispatch: **mesa**
76 (llvmpipe/ACO compilan según -march) y códecs sin runtime-detect. El mecanismo T1–T4
77 sigue válido pero su primer cliente real es mesa, no la dupla zlib/zstd.
78- **T6 — regla de admisión**: una lib entra a la lista caliente con benchmark que lo
79 justifique, no por vibras. La lista vive en el repo junto a los números.
80
81## 4. Lo que NO se hace
82
83- **Repo entero v3/v4** — coste de granja ×N por ganancia marginal fuera de la lista caliente.
84- **Dispatch en runtime / hwcaps** — no existe en musl y el modelo por-máquina es mejor para
85 takana de todos modos (§1).
86- **`-mcpu=native` jamás** — ni en variantes: el nivel nombrado es el contrato reproducible.
87- **LTO generalizado como campaña** — takana ya linkea estático con zig; el LTO por-receta se
88 evalúa donde el benchmark de T5/T6 lo pida, no como política global.
89
90## Orden propuesto
91
921. **T5** (piloto zlib/zstd en worker, benchmark) — decide si el frente vale antes de tocar
93 framework.
942. **T1–T2** (campo variant + mcpu pineado) — sólo si T5 da ganancia medible.
953. **T3–T4** (índice + sonda en hydrate) — cierra el ciclo usable.
964. **mesa v3** — el premio gordo para juegos; coordinar con el plan de jaula de juegos
97 (`plan-jaula-juegos.md`), siempre en worker.
plan-variantes-cpu.md
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 takana.
Tesis: takana 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, takana 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 takana 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 takana (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 takana 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, takana 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 takana |
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 (2026-07-17, laptop TigerLake, clang 3 variantes base/v3/v4,
corpus 200MB mixto fuente+binarios):
- zstd: v3/v4 NO pagan — CORTADO de la lista. Bench interno (
-b3 -i7, estable):
base 144.2 vs v4 146.5 MB/s comprimiendo, 702 vs 692 descomprimiendo = ruido. Causa
conocida: zstd ya hace dispatch BMI2/AVX2 en runtime ⇒ el -march del build casi no
toca los kernels calientes. (Un +24% aparente de v4 en la 1ª tanda desapareció con i7:
era calentamiento — lección para T6: sólo benchs con control de varianza.)
- zlib (madler): INCONCLUSO en laptop con carga (el mismo binario base osciló 112–157
MB/s entre tandas). Pero la pregunta estaba mal hecha: la respuesta buena no es una
variante v3 de zlib sino zlib-ng (fork con SIMD y dispatch en runtime, drop-in ABI;
Fedora 40 ya lo adoptó como zlib del sistema) ⇒ un solo artefacto, cero maquinaria de
variantes. Candidato a receta; medir zlib-ng vs zlib en máquina quieta cuando toque.
- Consecuencia estructural: los compresores modernos ya resuelven esto con dispatch
interno ⇒ la lista caliente de variantes se concentra donde NO hay dispatch: mesa
(llvmpipe/ACO compilan según -march) y códecs sin runtime-detect. El mecanismo T1–T4
sigue válido pero su primer cliente real es mesa, no la dupla zlib/zstd.
- 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
takana de todos modos (§1).
-mcpu=native jamás — ni en variantes: el nivel nombrado es el contrato reproducible.
- LTO generalizado como campaña — takana 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
- T5 (piloto zlib/zstd en worker, benchmark) — decide si el frente vale antes de tocar
framework.
- T1–T2 (campo variant + mcpu pineado) — sólo si T5 da ganancia medible.
- T3–T4 (índice + sonda en hydrate) — cierra el ciclo usable.
- mesa v3 — el premio gordo para juegos; coordinar con el plan de jaula de juegos
(
plan-jaula-juegos.md), siempre en worker.