tasas: SDD 25 al día — §4 confirmado sobre artefactos, §9 con cuatro medidos
- §0 y §4.bis: el «sin MEMCG» deja de ser deducción del defconfig. Los ONCE .config sellados traen `# CONFIG_MEMCG is not set` y `# CONFIG_PSI is not set`, y ninguno tiene CFS_BANDWIDTH (⇒ tampoco existe `cpu.max`; hoy nadie lo pide). Y se nombra por qué sobrevivió: el kernel de la máquina de desarrollo SÍ los trae — el fallo sólo existe del lado del artefacto. - §4.ter: el guardián `hammer kernel contract`, con las tres decisiones de diseño (por perfil, contra el .config y no la receta, apagado ≠ ausente). - §3: de tres sorpresas a cinco (taskstats no es más rápido que /proc; el sondeo es ciego, no lento). - §9: reescrita. Cuatro de los seis experimentos nombrados quedaron medidos con root; siguen abiertos el iterador BPF (detrás de H7) y el Intel con PTI. - §5, §7 y §10: filas medidas, H1 marcado como pendiente-pero-vigilado, H8 (el contrato es parte del release) y H9 (reflink alimenta SDD 18). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACUcwo9mZsE5ocYVE9npih
This commit is contained in:
+194
-20
@@ -28,6 +28,12 @@ El espejo de este documento para el lado tawasuyu es
|
||||
3. **La medición encontró un bug cruzado que no se buscaba**: los kernels de hammer se
|
||||
construyen **sin `CONFIG_MEMCG`**, y arje/sandokan escriben `memory.max` ignorando el
|
||||
error. Un límite de memoria pedido por una Card **no se aplica y nadie se entera**. §4.
|
||||
Confirmado después sobre los **11 `.config` sellados**, no deducido del defconfig (§4.bis), y
|
||||
ya vigilado por `hammer kernel contract` (§4.ter): 2 de 11 cumplen su perfil.
|
||||
4. **Sondear `/proc` no es lento, es ciego** (§9.1): de 200 procesos de vida mínima, un sondeo
|
||||
cada 100 ms vio **cero**; el proc connector, los 200. Y **el «copiar en O(1)» existe pero no en
|
||||
ext4**: en xfs/btrfs un reflink de 512 MiB tarda 0,020 ms contra 512,7 ms de `read+write`
|
||||
(§9.2).
|
||||
|
||||
## 1. Método y condiciones — leer antes de citar un número
|
||||
|
||||
@@ -41,6 +47,9 @@ El espejo de este documento para el lado tawasuyu es
|
||||
- Cada medida son 7–9 rondas; se reporta **mínimo** (mejor caso, el estimador robusto al
|
||||
ruido del scheduler) y **mediana**. Las corridas marcadas «pinneado» fijan el proceso a un
|
||||
cpu para sacar de en medio la cola del planificador.
|
||||
- **SEGUNDA CORRIDA, mismo día, con root** (§9): la máquina estaba mucho más suelta —load ~1,3
|
||||
sobre 4 vCPU y 4,3 GiB libres— y por eso **los absolutos de las dos corridas NO se comparan
|
||||
entre sí**. Cada cociente que se cita abajo sale de una sola corrida, y se dice de cuál.
|
||||
- Fuentes y salidas crudas: `docs/evidencia/tasas-kernel-2026-08-29/`.
|
||||
- **Piso de referencia**: una syscall nula (`getppid`) cuesta **78,7 ns**. El vDSO
|
||||
(`clock_gettime`) cuesta 31,2 ns y por syscall 143,8 ns ⇒ **cruzar al kernel son ~110 ns**.
|
||||
@@ -221,7 +230,7 @@ ruido. Gratis, y ya está en mainline.
|
||||
`pthread_create`+`join` = **11,9 µs**, contra 109 µs de `fork+_exit` con el padre vacío:
|
||||
**9×**, y la distancia crece con el tamaño del padre (T1).
|
||||
|
||||
## 3. Las tres sorpresas
|
||||
## 3. Las cinco sorpresas
|
||||
|
||||
Las anoto aparte porque contradicen el consejo de manual:
|
||||
|
||||
@@ -231,6 +240,13 @@ Las anoto aparte porque contradicen el consejo de manual:
|
||||
futuro; sobre datos cacheados el futuro pierde 2,8×.
|
||||
3. **`stat` cuesta lo mismo en tmpfs que en ext4** (T8) — invalida la reacción natural
|
||||
(«movamos el árbol a tmpfs y vuela»): el coste está en el VFS.
|
||||
4. **`taskstats` binario NO es más rápido que parsear `/proc`** (§9.1) — 2 688 vs 2 697 ns por
|
||||
consulta. La intuición «binario le gana a texto» falla porque el ida y vuelta de netlink cuesta
|
||||
lo mismo que `open`+`read`+parse. Su valor es el **contenido** (delay accounting, que `/proc` no
|
||||
da) y la estabilidad bajo carga, no la velocidad.
|
||||
5. **Sondear `/proc` no es lento: es CIEGO** (§9.1) — de 200 procesos de vida mínima lanzados uno
|
||||
cada 10 ms, un sondeo cada 100 ms vio **cero**. Toda la discusión de «cuánto cuesta el barrido»
|
||||
(T3) presupone que el barrido VE lo que hay, y para procesos cortos no lo ve.
|
||||
|
||||
## 4. El hallazgo cruzado: los kernels de hammer no tienen `MEMCG`
|
||||
|
||||
@@ -263,6 +279,59 @@ match std::fs::write(&path, format!("{mem}\n")) {
|
||||
que todo fue bien*. La jaula que no está se comporta igual que la jaula que sí está, hasta
|
||||
que hace falta.
|
||||
|
||||
### 4.bis · Confirmado sobre los artefactos, no deducido del defconfig
|
||||
|
||||
Lo de arriba se dedujo leyendo `x86_64_defconfig`. Se comprobó después contra los **`.config` que
|
||||
las recetas instalan** en `boot/config-<versión>`, que es la prueba dura porque incluye lo que hizo
|
||||
`olddefconfig`. Los **11 kernels sellados del store** —cinco nombres de artefacto: `linux`,
|
||||
`linux-generic`, `linux-metal`, `linux-metal-dual`, `linux-gioser`— traen literalmente:
|
||||
|
||||
```
|
||||
# CONFIG_MEMCG is not set
|
||||
# CONFIG_PSI is not set
|
||||
```
|
||||
|
||||
y ninguno tiene `CFS_BANDWIDTH` (⇒ `cpu.max`, la cuota dura de CPU, tampoco existe; hoy nadie la
|
||||
pide, pero cuando `pacha` la quiera será otro re-hasheo). Lo que **sí** está en los once:
|
||||
`CGROUP_SCHED`+`FAIR_GROUP_SCHED` (`cpu.weight`), `CGROUP_PIDS` (`pids.max`), `CPUSETS`
|
||||
(`cpuset.cpus`), `BLK_CGROUP`+`BLK_CGROUP_IOCOST` (`io.weight`, con la sintaxis «default N» que
|
||||
arje ya usa), `TASKSTATS`+`CONNECTOR`+`PROC_EVENTS`, `SECCOMP_FILTER`, `SECURITY_LANDLOCK`,
|
||||
`FANOTIFY`, `OVERLAY_FS` con metacopy e `IO_URING`.
|
||||
|
||||
**Y por qué el bug sobrevivió meses**: el kernel de la máquina de desarrollo (Artix 7.1.4) **sí**
|
||||
trae `MEMCG`, `PSI` y `CFS_BANDWIDTH`. El fallo sólo existe del lado del artefacto sellado, que es
|
||||
el lado que nadie mira con un depurador.
|
||||
|
||||
### 4.ter · El guardián: `hammer kernel contract`
|
||||
|
||||
Un hallazgo escrito en un documento no impide que vuelva a pasar. El contrato vive en
|
||||
`docs/state/kernel-contract.toml` y declara, por capacidad: los símbolos que la construyen, la
|
||||
interfaz que aparece o no aparece (`memory.max`, `pids.max`, `landlock_restrict_self`…), **el
|
||||
consumidor con ruta y símbolo**, y **cómo falla hoy si no está**. Se comprueba contra un `.config`
|
||||
ya producido:
|
||||
|
||||
```sh
|
||||
hammer --store ./store kernel contract --sealed # barre los kernels sellados
|
||||
hammer kernel contract --profile anfitrion-cards # el kernel vivo de esta máquina
|
||||
hammer kernel contract --list # qué promete hammer (esto es el W6)
|
||||
```
|
||||
|
||||
Tres decisiones que valen la pena nombrar:
|
||||
|
||||
1. **Por perfil, no global** — misma lección que el gate de hardware. `linux.toml` es el kernel de
|
||||
QEMU del selfhost-verify: no hospeda Cards y su hash es load-bearing del baseline `of_tree`.
|
||||
Exigirle contabilidad de memoria sería rechazar una receta sana, así que ahí los límites por
|
||||
unidad son `wants` y no `requires`.
|
||||
2. **Contra el `.config`, no contra la receta** — entre el `scripts/config -e X` y el `.config`
|
||||
está `olddefconfig`, que puede tragarse el símbolo sin decir nada (es justo lo que
|
||||
`hammer kernel diff-back` ya vigila para los planes).
|
||||
3. **Distingue apagado de ausente** — un símbolo que el `.config` ni nombra puede ser un
|
||||
renombrado entre versiones. Cuenta igual como capacidad ausente, pero se informa aparte; y un
|
||||
kernel sin perfil declarado queda **SIN COMPROBAR** en vez de contar como aprobado.
|
||||
|
||||
Estado medido hoy: **2 de 11 configs sellados cumplen su perfil** (los dos `linux`), los 9 de
|
||||
perfil `anfitrion-cards` fallan por `MEMCG`. El kernel vivo de esta máquina pasa las 11 exigidas.
|
||||
|
||||
Lo que **sí** funciona en un kernel hammer: `cpu.weight` (CGROUP_SCHED), `pids.max`
|
||||
(CGROUP_PIDS), `cpu.stat` (rstat del core) y `cgroup.freeze` — este último porque el freezer
|
||||
v2 es `obj-y` en `kernel/cgroup/Makefile`, no el `CONFIG_CGROUP_FREEZER` de v1.
|
||||
@@ -276,11 +345,12 @@ v2 es `obj-y` en `kernel/cgroup/Makefile`, no el `CONFIG_CGROUP_FREEZER` de v1.
|
||||
| T3 `/proc` texto | `getrusage`, `taskstats` | 11× |
|
||||
| T4 sumar `/proc` por unidad | agregado de cgroup v2 | O(1) vs O(N), cruce en N=2 |
|
||||
| T5 liveness por `/proc` | `pidfd` (+ sin carrera de PID) | 2,9× y correctitud |
|
||||
| T3 enumerar procesos | proc connector (netlink): eventos push | deja de sondear |
|
||||
| T3 enumerar procesos | proc connector (netlink): eventos push | **0 vs 200 procesos vistos** (§9.1) |
|
||||
| T6 señales | `eventfd`/`signalfd`/`pidfd` | 15 syscalls → 1 |
|
||||
| T8 tormenta de `stat` | `getdents64`, `fstatat(dirfd,…)` | 3,9×–12× |
|
||||
| T9 hermetismo de rutas | `openat2 RESOLVE_BENEATH` | ~gratis |
|
||||
| T10 materializar árbol | `link()` | 15,4× en ext4 |
|
||||
| T11 copiar un fichero entero | `FICLONE`/reflink **en xfs o btrfs** | **25 600× a 512 MiB** (§9.2) |
|
||||
| T15 cerrar fds | `close_range` | 102 µs → ~0 |
|
||||
|
||||
**Ninguna de estas exige un módulo, un parche ni un kernel propio.** Es la primera conclusión
|
||||
@@ -315,7 +385,10 @@ Su precio, concreto:
|
||||
- **H1 · `-e MEMCG -e PSI` en las cuatro recetas de kernel.** Cierra §4 y habilita
|
||||
`memory.current` (T4) y las señales de presión. **Precio declarado**: re-hashea todos los
|
||||
artefactos de kernel ⇒ hacerlo en la misma tanda que cualquier otro cambio de kernel, nunca
|
||||
suelto.
|
||||
suelto. **Sigue PENDIENTE a propósito** — pero ya no puede olvidarse: desde §4.ter
|
||||
`hammer kernel contract --sealed` sale distinto de cero mientras falte. Cuando se pague, el
|
||||
mismo comando es la prueba de que se pagó. Nota de alcance: en `linux.toml` (perfil
|
||||
`qemu-serial`) NO corre — su hash es el baseline del selfhost-verify y ahí no hay Cards.
|
||||
- **H2 · `MODULES=n` se queda.** Si algún día hace falta código de kernel, es built-in y
|
||||
parcheado en la receta. Queda escrito para no rediscutirlo.
|
||||
- **H3 · `harkaq` usa `openat2 RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS`** donde hoy valida rutas
|
||||
@@ -329,6 +402,15 @@ Su precio, concreto:
|
||||
granja corra apretada de RAM (T13).
|
||||
- **H7 · `DEBUG_INFO_BTF` sigue apagado** hasta que haya un consumidor real de BPF; cuando lo
|
||||
haya, la deuda es pahole en el lab y un re-hasheo, no un rediseño.
|
||||
- **H8 · El contrato de capacidades es parte del release del kernel** (§4.ter). Toda receta de
|
||||
kernel nueva declara su `[[target]]` con perfil; un kernel sin perfil sale **SIN COMPROBAR**, no
|
||||
aprobado. Y toda capacidad nueva entra con consumidor —ruta y símbolo— o no entra: «estaría bueno
|
||||
tener» no es un contrato.
|
||||
- **H9 · El experimento de reflink cambia el cálculo de SDD 18, no el de hoy.** Con `.dmerge` sobre
|
||||
ext4 el hardlink sigue siendo la elección correcta (T10). Lo que §9.2 agrega es que un store
|
||||
sobre **xfs o btrfs** compraría semántica de copia —mutación privada, sin la contrapartida de
|
||||
retener lo borrado— al mismo precio. Es un argumento para wawafs, medido; no un cambio de
|
||||
filesystem decidido acá.
|
||||
|
||||
## 8. Propuestas — lado tawasuyu
|
||||
|
||||
@@ -337,7 +419,9 @@ Detalle en el handoff espejo. En una línea cada una:
|
||||
- **W1 · `pidfd` para liveness y señales** en `sandokan-local` (hoy `access("/proc/<pid>")` y
|
||||
`waitpid(WNOHANG)` en sondeo). Se gana correctitud (carrera de PID) antes que velocidad.
|
||||
- **W2 · Telemetría por unidad desde el cgroup**, no sumando `/proc` (T4). Con **sonda de
|
||||
capacidad**: si `memory.current` no existe (kernel sin MEMCG), decirlo, no callarlo.
|
||||
capacidad**: si `memory.current` no existe (kernel sin MEMCG), decirlo, no callarlo. Del lado
|
||||
hammer esa sonda ya tiene con qué contrastarse: `hammer kernel contract --list --json` publica
|
||||
qué promete cada perfil de kernel (§4.ter), que es el W6 en formato de dato.
|
||||
- **W3 · `arje-incarnate` con `posix_spawn`** donde el `pre_exec` no sea imprescindible (T1),
|
||||
y `close_range` en el que quede.
|
||||
- **W4 · Los errores de cgroup dejan de descartarse.** `let _ = write(...)` y `warn!` sobre un
|
||||
@@ -348,27 +432,106 @@ Detalle en el handoff espejo. En una línea cada una:
|
||||
la lista de símbolos garantizados (verificable con `hammer kernel probe`); tawasuyu elige
|
||||
backend en runtime.
|
||||
|
||||
## 9. Lo que NO pude medir (experimentos nombrados)
|
||||
## 9. Los experimentos nombrados — cuatro medidos, dos abiertos
|
||||
|
||||
Ninguno se omite en silencio:
|
||||
La primera corrida los dejó nombrados y sin medir, todos por privilegios o por herramienta
|
||||
ausente. **Cuatro cayeron el mismo día, con root.** Condiciones distintas a la corrida de arriba
|
||||
(load ~1,3 sobre 4 vCPU, 4,3 GiB libres) ⇒ los números de acá **no se cruzan** con los de §2.
|
||||
|
||||
1. **proc connector y `taskstats`**: suscribirse al netlink pide `CAP_NET_ADMIN`; el uid de
|
||||
la sesión es 1001. Experimento: un binario chico corriendo como root en la granja,
|
||||
midiendo latencia de evento `fork/exec/exit` contra el sondeo de `/proc`.
|
||||
2. **Copia con reflink** (T11): exige `mkfs` sobre un loop (root). Experimento: xfs y btrfs
|
||||
en loop, `copy_file_range` de 64 MiB, esperado O(1) contra los 2 837 MB/s de ext4.
|
||||
3. **Iterador BPF contra `/proc`** (T3): exige BTF y privilegios. Va detrás de H7.
|
||||
4. **io_uring con `SQPOLL`**: exige `CAP_SYS_NICE`. Cambiaría el veredicto de T12 para el
|
||||
caso «muchas operaciones que bloquean».
|
||||
5. **Coste real de una tanda de hammer en syscalls**: sin `strace`/`perf` en esta máquina no
|
||||
se puede atribuir. Experimento: instalarlos en la granja y contar `stat`/`open` por
|
||||
invocación de compilador, para saber si T8 vale segundos o minutos por receta.
|
||||
6. **Un Intel con PTI**: todos los pisos de syscall de acá son de un AMD sin PTI. En el
|
||||
laptop (TigerLake) las mismas medidas darían peor, y ahí T3/T6 duelen más.
|
||||
### 9.1 · proc connector y `taskstats` — MEDIDO (`bench_connector.c`, `connector.txt`)
|
||||
|
||||
**a) Latencia.** Esperar el evento `PROC_EVENT_EXIT` del connector **no cuesta más** que el
|
||||
`waitpid` que el padre ya hace: 116,0 µs contra 114,8 µs por `fork+_exit` (mínimo de 7 rondas de
|
||||
200), es decir dentro del ruido, con **0 eventos perdidos de 1 400**. Con una advertencia dura que
|
||||
salió del propio experimento: el multicast del connector **no reintenta**. Si el buffer del socket
|
||||
se llena, el evento se pierde y quien lo espera se cuelga para siempre — la primera versión del
|
||||
programa se colgó exactamente así. Un supervisor sobre connector necesita `SO_RCVBUF` grande **y
|
||||
un plazo**, no una espera infinita.
|
||||
|
||||
**b) Cobertura — el resultado que importa.** 200 procesos de vida mínima, uno cada 10 ms:
|
||||
|
||||
| observador | vistos | CPU |
|
||||
|---|---|---|
|
||||
| sondeo de `/proc` cada 100 ms (23 barridos) | **0 de 200** | 10,5 ms |
|
||||
| proc connector (eventos) | **200 de 200** | 95,4 ms |
|
||||
|
||||
El sondeo no es caro: es **ciego**. Y la CPU del connector de esa tabla es cota superior — el
|
||||
programa lo lee con espera activa de 200 µs, que no es el modo de un supervisor real (sería
|
||||
`epoll`, donde el coste es despertar por evento).
|
||||
|
||||
**c) `taskstats`.** La familia genetlink existe y responde. Por consulta: **2 688 ns** contra
|
||||
**2 697 ns** de `open`+`read`+parse de `/proc/self/stat`. **No gana en velocidad** (sorpresa §3.4).
|
||||
Lo que da y `/proc` no: contabilidad de retrasos (delay accounting) y una estructura binaria
|
||||
estable en vez de un texto que hay que parsear posicionalmente.
|
||||
|
||||
### 9.2 · Copia con reflink — MEDIDO (`bench_reflink.c`, `reflink.txt`)
|
||||
|
||||
`mkfs` sobre un loop, xfs con `reflink=1` y btrfs por defecto. Copiar un fichero **entero**:
|
||||
|
||||
| | ext4 | xfs (loop) | btrfs (loop) |
|
||||
|---|---|---|---|
|
||||
| `FICLONE` (reflink) | **no soportado** | 0,010 ms | 0,006 ms |
|
||||
| `copy_file_range` | 13,66 ms | 0,010 ms | 0,006 ms |
|
||||
| `read+write` (1 MiB) | 14,46 ms | 10,96 ms | 31,32 ms |
|
||||
|
||||
Y la prueba de que es O(1) y no «rápido»: **con el fichero ocho veces más grande (512 MiB), el
|
||||
reflink pasa de 0,010 a 0,020 ms** —el doble, no ocho veces— mientras `read+write` pasa de 10,96 a
|
||||
512,7 ms. **25 600× a 512 MiB en xfs.** En btrfs, 0,006 → 0,015 ms.
|
||||
|
||||
Confirma T11 por el lado contrario: en ext4 `copy_file_range` no gana nada (13,66 contra 14,46 ms,
|
||||
un 6%) **porque ext4 no tiene reflink**; el «copiar en O(1)» que la gente espera de esa syscall es
|
||||
una propiedad del filesystem, no de la syscall. Material directo para SDD 18 (wawafs): con reflink
|
||||
se obtiene semántica de **copia** al precio del hardlink, y sin la contrapartida del hardlink —que
|
||||
`.dmerge` ya paga: retener en la caché lo que se borró del store.
|
||||
|
||||
### 9.3 · io_uring con `SQPOLL` — MEDIDO (`bench_sqpoll.c`, `sqpoll.txt`)
|
||||
|
||||
4K aleatorios en caché, profundidad 32, fd registrado:
|
||||
|
||||
| ns/op | ext4 | tmpfs |
|
||||
|---|---|---|
|
||||
| `pread` | **554** | **749** |
|
||||
| io_uring sin SQPOLL | 618 | 2 030 |
|
||||
| io_uring con SQPOLL | 868 | 1 409 |
|
||||
|
||||
**No cambia el veredicto de T12.** Sobre datos cacheados `SQPOLL` sigue perdiendo contra la
|
||||
syscall (1,6× peor en ext4), y aunque en tmpfs mejora al io_uring normal (1,4×), sigue estando
|
||||
1,9× por detrás de `pread`. Encima **se come un core** con el hilo del kernel, que en una máquina
|
||||
de 4 vCPU es el 25% de la granja. `SQPOLL` es para operaciones que **de verdad bloquean**, no para
|
||||
amortizar cruces sobre caché.
|
||||
|
||||
### 9.4 · Coste en syscalls de un compilado — MEDIDO (`syscalls-compilador.txt`)
|
||||
|
||||
La corrida original decía «sin `strace`/`perf` en esta máquina no se puede atribuir». **El
|
||||
`strace` estaba en el propio corpus** (`store/3c1fd8c0…-strace`, 6.19): la distro se paga a sí
|
||||
misma la herramienta de diagnóstico. Un `-c` de un `main()` trivial con stdio/stdlib/string:
|
||||
|
||||
| | syscalls | con error | el grueso |
|
||||
|---|---|---|---|
|
||||
| `cc -O2 -c` (gcc 16) | 1 803 | **1 095 (61%)** | **919 de 923 `readlink` FALLAN** |
|
||||
| `zig cc -O2 -c` (zig 0.16) | 3 608 | 214 (6%) | 1 104 `futex` (70% del tiempo en syscall) |
|
||||
|
||||
Dos lecturas:
|
||||
|
||||
- **La tormenta de rutas de T8 existe y es de `readlink`, no de `stat`** — canonicalización de
|
||||
rutas de gcc, que T8 no medía. Pero **al piso de 78,7 ns, 1 803 cruces son 0,14 ms sobre 30,5 ms
|
||||
de compilado: el 0,5%.** La respuesta a la pregunta original («¿vale segundos o minutos por
|
||||
receta?») es **milisegundos por invocación**: segundos por millar de compilados. No es ahí donde
|
||||
está el tiempo de una tanda.
|
||||
- **`zig cc` tiene otro perfil**: casi no falla rutas, pero coordina hilos. El tiempo que
|
||||
`strace -c` le atribuye es espera **bloqueada**, no CPU — y por eso `strace -c` no sirve para
|
||||
comparar compiladores, sólo para contar llamadas.
|
||||
|
||||
### 9.5 · Lo que sigue abierto
|
||||
|
||||
1. **Iterador BPF contra `/proc`** (T3): exige BTF y privilegios. Va detrás de H7 —
|
||||
`DEBUG_INFO_BTF` está apagado en las cuatro recetas y su deuda (pahole) ya está medio pagada.
|
||||
2. **Un Intel con PTI**: todos los pisos de syscall de acá son de un AMD sin PTI. En el laptop
|
||||
(TigerLake) las mismas medidas darían peor, y ahí T3/T6 duelen más.
|
||||
|
||||
## 10. Evidencia
|
||||
|
||||
`docs/evidencia/tasas-kernel-2026-08-29/` — cuatro programas en C
|
||||
`docs/evidencia/tasas-kernel-2026-08-29/` — **primera corrida**: cuatro programas en C
|
||||
(`bench_proc.c`, `bench_io.c`, `bench_extra.c`, `bench_pin.c`) y sus cinco salidas crudas
|
||||
(`proc.txt`, `io-ext4.txt`, `io-tmpfs.txt`, `extra.txt`, `pin.txt`). Se compilan con
|
||||
`cc -O2` (`bench_io` pide `-luring`, `bench_proc`/`bench_pin` piden `-lpthread`) y se corren
|
||||
@@ -377,3 +540,14 @@ sin argumentos salvo `bench_io <dir>` y `bench_pin <estatico> <dinamico> <musl>`
|
||||
**Nota de unidad**: en `pin.txt` la sección de fallos de página imprime ns/página × 1000 por
|
||||
un factor de escala equivocado en el programa; los valores citados en T13 son los de esa
|
||||
salida divididos por 1000, y coinciden con `io-ext4.txt`, que sí está en la unidad correcta.
|
||||
|
||||
**Segunda corrida (§9, con root)**: `bench_connector.c` → `connector.txt`; `bench_reflink.c` →
|
||||
`reflink.txt` (xfs y btrfs sobre loop, montados y desmontados por el propio guion);
|
||||
`bench_sqpoll.c` → `sqpoll.txt`; y `syscalls-compilador.txt`, hecho con el `strace` **del store**.
|
||||
Se compilan igual que los otros (`bench_sqpoll` pide `-luring`) y los tres primeros piden root:
|
||||
`bench_connector` por `CAP_NET_ADMIN`, `bench_reflink` por `mkfs`+`mount`, `bench_sqpoll` por
|
||||
`CAP_SYS_NICE`.
|
||||
|
||||
**Contrato de capacidades**: `docs/state/kernel-contract.toml` (el dato) y
|
||||
`hammer kernel contract --list` (la vista). Los ficheros de esta carpeta no cambian; el contrato sí
|
||||
—cada vez que un consumidor nuevo usa el kernel por nombre.
|
||||
|
||||
Reference in New Issue
Block a user