gioser

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 1572Shell 203Rust 109Markdown 993728 Definitions

⎇ main docs/evidencia/tasas-kernel-2026-08-29/bench_proc.c C · 147 lines · 7.6 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_proc.c — piso de syscall, control de procesos, /proc, IPC, scheduler.
2 * Método: R rondas; se reporta MIN (mejor caso, robusto al ruido) y MEDIANA. */
3#define _GNU_SOURCE
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <time.h>
10#include <errno.h>
11#include <signal.h>
12#include <sched.h>
13#include <pthread.h>
14#include <spawn.h>
15#include <dirent.h>
16#include <sys/syscall.h>
17#include <sys/wait.h>
18#include <sys/resource.h>
19#include <sys/eventfd.h>
20#include <sys/socket.h>
21#include <sys/stat.h>
22
23extern char **environ;
24static volatile long sink;
25
26static inline double now_ns(void){ struct timespec t; clock_gettime(CLOCK_MONOTONIC,&t); return t.tv_sec*1e9+t.tv_nsec; }
27static int cmpd(const void*a,const void*b){ double x=*(const double*)a,y=*(const double*)b; return (x>y)-(x<y); }
28
29#define ROUNDS 9
30static void report(const char*name,double*r,int n,long it){
31  qsort(r,n,sizeof(double),cmpd);
32  printf("%-38s %10.1f %10.1f   (n=%ld)\n",name,r[0],r[n/2],it); fflush(stdout);
33}
34#define BENCH(name,iters,...) do{ double _r[ROUNDS]; long _N=(iters); \
35  for(int _q=0;_q<ROUNDS;_q++){ double _t0=now_ns(); for(long i=0;i<_N;i++){ __VA_ARGS__; } \
36    _r[_q]=(now_ns()-_t0)/(double)_N; } report(name,_r,ROUNDS,_N);}while(0)
37
38/* ---------- helpers ---------- */
39static void pin(int cpu){ cpu_set_t s; CPU_ZERO(&s); CPU_SET(cpu,&s); sched_setaffinity(0,sizeof s,&s); }
40
41static long read_stat_utime(int fd){
42  char buf[1024]; ssize_t n=pread(fd,buf,sizeof buf-1,0); if(n<=0) return -1; buf[n]=0;
43  char *p=strrchr(buf,')'); if(!p) return -1; p+=2;
44  int f=1; long v=0; while(*p&&f<12){ if(*p==' ')f++; p++; }
45  v=strtol(p,NULL,10); return v;
46}
47static long parse_vmrss(void){
48  int fd=open("/proc/self/status",O_RDONLY); if(fd<0) return -1;
49  char buf[4096]; ssize_t n=read(fd,buf,sizeof buf-1); close(fd); if(n<=0)return -1; buf[n]=0;
50  char*p=strstr(buf,"VmRSS:"); return p?strtol(p+6,NULL,10):-1;
51}
52
53static volatile sig_atomic_t got;
54static void h(int s){ (void)s; got=1; }
55
56/* RTT entre dos hilos pinneados al MISMO cpu */
57struct rtt { int a[2], b[2]; int kind; long iters; };
58static void rd1(int fd,int kind){ if(kind==2){uint64_t v;(void)!read(fd,&v,8);} else {char c;(void)!read(fd,&c,1);} }
59static void wr1(int fd,int kind){ if(kind==2){uint64_t v=1;(void)!write(fd,&v,8);} else {char c=1;(void)!write(fd,&c,1);} }
60static void*echo(void*p){ struct rtt*r=p; pin(3);
61  for(long i=0;i<r->iters;i++){ rd1(r->a[0],r->kind); wr1(r->b[1],r->kind); } return 0; }
62
63static double rtt_bench(int kind,long iters){
64  struct rtt r; r.kind=kind; r.iters=iters;
65  if(kind==0){ if(pipe(r.a)||pipe(r.b)) return -1; }
66  else if(kind==1){ if(socketpair(AF_UNIX,SOCK_STREAM,0,r.a)||socketpair(AF_UNIX,SOCK_STREAM,0,r.b)) return -1; }
67  else { r.a[0]=r.a[1]=eventfd(0,0); r.b[0]=r.b[1]=eventfd(0,0); }
68  pthread_t t; pthread_create(&t,0,echo,&r); pin(3);
69  double best=1e18;
70  for(int q=0;q<3;q++){ long n=iters/3; double t0=now_ns();
71    for(long i=0;i<n;i++){ wr1(r.a[1],kind); rd1(r.b[0],kind); }
72    double v=(now_ns()-t0)/n; if(v<best)best=v; }
73  pthread_join(t,0);
74  return best;
75}
76
77int main(void){
78  pin(3);
79  printf("%-38s %10s %10s\n","BENCH (ns/op)","min","mediana");
80  printf("--- A. piso de syscall ---\n");
81  BENCH("getppid (syscall nulo)",              300000, sink=syscall(SYS_getppid));
82  BENCH("clock_gettime MONOTONIC (vDSO)",      300000, {struct timespec t;clock_gettime(CLOCK_MONOTONIC,&t);sink=t.tv_nsec;});
83  BENCH("clock_gettime MONOTONIC (syscall)",   200000, {struct timespec t;syscall(SYS_clock_gettime,CLOCK_MONOTONIC,&t);sink=t.tv_nsec;});
84  BENCH("getpid (vDSO no; glibc syscall)",     300000, sink=getpid());
85  BENCH("sched_yield",                         200000, sched_yield());
86
87  printf("--- B. contabilidad de proceso propio ---\n");
88  BENCH("getrusage(RUSAGE_SELF)",              200000, {struct rusage u;getrusage(RUSAGE_SELF,&u);sink=u.ru_utime.tv_usec;});
89  BENCH("clock_gettime(PROCESS_CPUTIME)",      200000, {struct timespec t;clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t);sink=t.tv_nsec;});
90  { int fd=open("/proc/self/stat",O_RDONLY);
91    BENCH("pread+parse /proc/self/stat (fd abierto)", 100000, sink=read_stat_utime(fd));
92    close(fd); }
93  BENCH("open+read+parse /proc/self/stat",      50000, {int fd=open("/proc/self/stat",O_RDONLY);sink=read_stat_utime(fd);close(fd);});
94  BENCH("open+read+parse /proc/self/status(RSS)",30000, sink=parse_vmrss());
95
96  printf("--- C. liveness de otro proceso ---\n");
97  { pid_t me=getpid(); char p[64]; snprintf(p,sizeof p,"/proc/%d",me);
98    int pfd=syscall(SYS_pidfd_open,me,0);
99    BENCH("access(/proc/<pid>) [lo que se usa hoy]",200000, sink=access(p,F_OK));
100    BENCH("kill(pid,0)",                            300000, sink=kill(me,0));
101    if(pfd>=0){ BENCH("pidfd_send_signal(fd,0) [sin carrera]",300000, sink=syscall(SYS_pidfd_send_signal,pfd,0,NULL,0)); }
102    else printf("pidfd_send_signal: no disponible (%s)\n",strerror(errno));
103    BENCH("pidfd_open+close",                      100000, {int f=syscall(SYS_pidfd_open,me,0); if(f>=0)close(f);});
104    if(pfd>=0) close(pfd); }
105
106  printf("--- D. barrido de /proc (enumeracion) ---\n");
107  { int nproc=0;
108    double r1[ROUNDS],r2[ROUNDS];
109    for(int q=0;q<ROUNDS;q++){
110      double t0=now_ns(); int c=0;
111      DIR*d=opendir("/proc"); struct dirent*e;
112      while((e=readdir(d))){ if(e->d_name[0]<'0'||e->d_name[0]>'9')continue; c++; }
113      closedir(d); r1[q]=now_ns()-t0; nproc=c;
114      t0=now_ns(); d=opendir("/proc");
115      while((e=readdir(d))){ if(e->d_name[0]<'0'||e->d_name[0]>'9')continue;
116        char p[512]; snprintf(p,sizeof p,"/proc/%s/stat",e->d_name);
117        int fd=open(p,O_RDONLY); if(fd<0)continue; sink=read_stat_utime(fd); close(fd); }
118      closedir(d); r2[q]=now_ns()-t0; }
119    qsort(r1,ROUNDS,sizeof(double),cmpd); qsort(r2,ROUNDS,sizeof(double),cmpd);
120    printf("procesos vivos = %d\n",nproc);
121    printf("%-38s %10.1f %10.1f   (us/barrido)\n","solo readdir(/proc)",r1[0]/1000,r1[ROUNDS/2]/1000);
122    printf("%-38s %10.1f %10.1f   (us/barrido)\n","readdir + stat de cada pid",r2[0]/1000,r2[ROUNDS/2]/1000);
123    printf("%-38s %10.1f %10.1f   (ns/proceso)\n","  => coste por proceso",r2[0]/nproc,r2[ROUNDS/2]/nproc); }
124
125  printf("--- E. creacion de procesos ---\n");
126  BENCH("fork + _exit + waitpid",                  400, {pid_t p=fork(); if(p==0)_exit(0); int st;waitpid(p,&st,0);});
127  BENCH("vfork + execve(/bin/true) + wait",         300, {pid_t p=vfork(); if(p==0){char*a[]={"/bin/true",0};execve(a[0],a,environ);_exit(127);} int st;waitpid(p,&st,0);});
128  { BENCH("posix_spawn(/bin/true) + wait",          300, {pid_t p;char*a[]={"/bin/true",0};if(posix_spawn(&p,a[0],0,0,a,environ)==0){int st;waitpid(p,&st,0);} }); }
129
130  printf("--- F. IPC: round-trip entre 2 hilos (mismo cpu) ---\n");
131  { pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
132    BENCH("pthread_mutex lock+unlock (sin disputa)",1000000,{pthread_mutex_lock(&m);pthread_mutex_unlock(&m);}); }
133  printf("%-38s %10.1f            (RTT)\n","pipe read/write",      rtt_bench(0,60000));
134  printf("%-38s %10.1f            (RTT)\n","socketpair AF_UNIX",   rtt_bench(1,60000));
135  printf("%-38s %10.1f            (RTT)\n","eventfd",              rtt_bench(2,60000));
136  { signal(SIGUSR1,h);
137    BENCH("kill(self,SIGUSR1) + handler",         200000, {got=0;kill(getpid(),SIGUSR1);sink=got;}); }
138
139  printf("--- G. temporizadores ---\n");
140  { double r[ROUNDS];
141    for(int q=0;q<ROUNDS;q++){ struct timespec req={0,1000000},rem; double t0=now_ns();
142      for(int i=0;i<20;i++) nanosleep(&req,&rem);
143      r[q]=(now_ns()-t0)/20 - 1000000.0; }
144    qsort(r,ROUNDS,sizeof(double),cmpd);
145    printf("%-38s %10.1f %10.1f   (sobrecoste ns sobre 1ms)\n","nanosleep(1ms) overshoot",r[0],r[ROUNDS/2]); }
146  return 0;
147}