tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 604Rust 56Shell 36Markdown 281227 Definitions

⎇ main docs/evidencia/tasas-kernel-2026-08-29/bench_extra.c C · 92 lines · 4.9 KB History Who touched what raw

SDD 25: las tasas del kernel medidas, y el MEMCG que falta en las recetas aeeaa6d07 · Sergio ·

1/* bench_extra.c — lo que las dos sorpresas piden aislar:
2 *  a) coste de fork EN FUNCION del espacio de direcciones del padre
3 *  b) contabilidad por cgroup v2 vs sumar /proc
4 *  c) tasa del enlazado dinamico en el exec
5 *  d) cierre de descriptores en el spawn  */
6#define _GNU_SOURCE
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11#include <fcntl.h>
12#include <time.h>
13#include <errno.h>
14#include <spawn.h>
15#include <dirent.h>
16#include <sched.h>
17#include <sys/syscall.h>
18#include <sys/wait.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21
22extern char **environ;
23static volatile long sink;
24static inline double now_ns(void){ struct timespec t; clock_gettime(CLOCK_MONOTONIC,&t); return t.tv_sec*1e9+t.tv_nsec; }
25static int cmpd(const void*a,const void*b){ double x=*(const double*)a,y=*(const double*)b; return (x>y)-(x<y); }
26#define ROUNDS 7
27static void rep(const char*n,double*r,int c){ qsort(r,c,sizeof(double),cmpd);
28  printf("%-44s %10.1f %10.1f\n",n,r[0],r[c/2]); fflush(stdout); }
29
30static double *area=NULL; static long area_sz=0;
31static void grow(long mb){
32  if(area) munmap(area,area_sz);
33  area_sz=mb*1024L*1024; if(mb==0){area=NULL;return;}
34  area=mmap(0,area_sz,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
35  madvise(area,area_sz,MADV_NOHUGEPAGE);          /* tablas de paginas reales, no THP */
36  for(long o=0;o<area_sz;o+=4096) ((char*)area)[o]=1;
37}
38static double t_fork(int n){ double t0=now_ns();
39  for(int i=0;i<n;i++){ pid_t p=fork(); if(p==0)_exit(0); int st; waitpid(p,&st,0);} return (now_ns()-t0)/n/1000; }
40static double t_vfork_exec(int n,const char*prog){ double t0=now_ns();
41  for(int i=0;i<n;i++){ pid_t p=vfork(); if(p==0){char*a[]={(char*)prog,0};execve(prog,a,environ);_exit(127);} int st; waitpid(p,&st,0);} return (now_ns()-t0)/n/1000; }
42static double t_fork_exec(int n,const char*prog){ double t0=now_ns();
43  for(int i=0;i<n;i++){ pid_t p=fork(); if(p==0){char*a[]={(char*)prog,0};execve(prog,a,environ);_exit(127);} int st; waitpid(p,&st,0);} return (now_ns()-t0)/n/1000; }
44static double t_spawn(int n,const char*prog){ double t0=now_ns();
45  for(int i=0;i<n;i++){ pid_t p; char*a[]={(char*)prog,0}; if(posix_spawn(&p,prog,0,0,a,environ)==0){int st;waitpid(p,&st,0);} } return (now_ns()-t0)/n/1000; }
46
47int main(int argc,char**argv){
48  const char *sta = argc>1?argv[1]:"/bin/true";
49  const char *dyn = argc>2?argv[2]:"/bin/true";
50  printf("%-44s %10s %10s\n","BENCH (us/op)","min","mediana");
51  printf("--- a) fork segun el espacio de direcciones del padre ---\n");
52  long mbs[]={0,16,64,256};
53  for(unsigned k=0;k<sizeof mbs/sizeof*mbs;k++){
54    grow(mbs[k]); double r[ROUNDS],r2[ROUNDS],r3[ROUNDS];
55    for(int q=0;q<ROUNDS;q++) r[q]=t_fork(150);
56    for(int q=0;q<ROUNDS;q++) r2[q]=t_fork_exec(120,sta);
57    for(int q=0;q<ROUNDS;q++) r3[q]=t_spawn(120,sta);
58    char n1[80],n2[80],n3[80];
59    snprintf(n1,sizeof n1,"  padre %3ld MB tocados: fork+_exit",mbs[k]);
60    snprintf(n2,sizeof n2,"  padre %3ld MB tocados: fork+exec",mbs[k]);
61    snprintf(n3,sizeof n3,"  padre %3ld MB tocados: posix_spawn(CLONE_VFORK)",mbs[k]);
62    rep(n1,r,ROUNDS); rep(n2,r2,ROUNDS); rep(n3,r3,ROUNDS); }
63  grow(0);
64
65  printf("--- c) tasa del enlazado dinamico en exec ---\n");
66  { double r[ROUNDS]; for(int q=0;q<ROUNDS;q++) r[q]=t_vfork_exec(150,sta); rep("  vfork+exec binario ESTATICO",r,ROUNDS);
67    for(int q=0;q<ROUNDS;q++) r[q]=t_vfork_exec(150,dyn); rep("  vfork+exec binario DINAMICO",r,ROUNDS); }
68
69  printf("--- d) cierre de descriptores antes del exec ---\n");
70  { int base=open("/dev/null",O_RDONLY); int fds[512]; for(int i=0;i<512;i++) fds[i]=dup(base);
71    double r[ROUNDS];
72    for(int q=0;q<ROUNDS;q++){ double t0=now_ns(); for(int i=0;i<512;i++){int f=dup(base); close(f);} r[q]=(now_ns()-t0)/512/1000; }
73    rep("  dup+close x512, uno a uno (us/fd)",r,ROUNDS);
74    for(int q=0;q<ROUNDS;q++){ int a[512]; for(int i=0;i<512;i++) a[i]=dup(base);
75      double t0=now_ns(); sink=syscall(SYS_close_range,a[0],a[511],0); r[q]=(now_ns()-t0)/512/1000; }
76    rep("  close_range(lo,hi) (us/fd)",r,ROUNDS);
77    for(int i=0;i<512;i++) close(fds[i]); close(base); }
78
79  printf("--- b) contabilidad: cgroup v2 vs sumar /proc ---\n");
80  { char cg[512]="", path[600]; FILE*f=fopen("/proc/self/cgroup","r");
81    if(f){ char line[512]; while(fgets(line,sizeof line,f)){ char*p=strstr(line,"0::"); if(p){ p+=3; p[strcspn(p,"\n")]=0; snprintf(cg,sizeof cg,"/sys/fs/cgroup%s",p);} } fclose(f);} 
82    if(cg[0]){ printf("  cgroup: %s\n",cg);
83      const char*campos[]={"cpu.stat","memory.current","pids.current"};
84      double r[ROUNDS];
85      for(int q=0;q<ROUNDS;q++){ int N=2000; double t0=now_ns();
86        for(int i=0;i<N;i++){ for(int c=0;c<3;c++){ snprintf(path,sizeof path,"%s/%s",cg,campos[c]);
87            int fd=open(path,O_RDONLY); if(fd<0)continue; char b[512]; sink=read(fd,b,sizeof b); close(fd);} }
88        r[q]=(now_ns()-t0)/N/1000; }
89      rep("  leer cpu.stat+memory.current+pids.current",r,ROUNDS);
90    } else printf("  sin cgroup v2 legible\n"); }
91  return 0;
92}