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 1576Shell 205Rust 111Markdown 993774 Definitions

⎇ 84e3737e10e17927380ed3e232e50cebfdd39123 docs/evidencia/tasas-kernel-2026-08-29/bench_sqpoll.c C · 112 lines · 4.4 KB History Who touched what raw

tasas: los 4 experimentos que §9 dejó nombrados, medidos con root 849c04144 · Sergio ·

1/* bench_sqpoll.c — io_uring con SQPOLL contra io_uring normal y contra pread.
2 *
3 * Cierra el experimento 4 de SDD 25 seccion 9: SQPOLL pide CAP_SYS_NICE, asi que la corrida
4 * original no pudo mirarlo. La pregunta que dejo abierta T12: io_uring pierde sobre datos ya
5 * cacheados porque el cruce al kernel no se amortiza — con SQPOLL NO HAY cruce (un hilo del
6 * kernel consume la cola), asi que este es el caso donde deberia ganar.
7 *
8 * Uso: bench_sqpoll <dir> <etiqueta>
9 * Se compila con: cc -O2 -o bench_sqpoll bench_sqpoll.c -luring
10 */
11#define _GNU_SOURCE
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <time.h>
18#include <errno.h>
19#include <liburing.h>
20
21#define MB (1024*1024)
22#define SIZE (64*MB)
23#define BS 4096
24#define ROUNDS 7
25#define DEPTH 32
26#define OPS 50000
27
28static volatile long sink;
29static inline double now_ns(void){ struct timespec t; clock_gettime(CLOCK_MONOTONIC,&t); return t.tv_sec*1e9+t.tv_nsec; }
30static int cmpd(const void*a,const void*b){ double x=*(const double*)a,y=*(const double*)b; return (x>y)-(x<y); }
31static void report(const char*n,double*r,int c,long it){ qsort(r,c,sizeof(double),cmpd);
32  printf("%-44s %10.1f %10.1f   (n=%ld)\n",n,r[0],r[c/2],it); fflush(stdout); }
33
34/* Un pase de OPS lecturas de 4K en profundidad DEPTH. Devuelve ns/op. */
35static double pase(struct io_uring *ring,int fd,char *buf,long nblk){
36  double t0=now_ns();
37  for(long done=0;done<OPS;){
38    int batch = (OPS-done<DEPTH)?(int)(OPS-done):DEPTH;
39    for(int k=0;k<batch;k++){
40      struct io_uring_sqe *s=io_uring_get_sqe(ring);
41      io_uring_prep_read(s,fd,buf+k*BS,BS,(long)(((done+k)*7919)%nblk)*BS);
42    }
43    io_uring_submit_and_wait(ring,batch);
44    struct io_uring_cqe *c; unsigned h; int seen=0;
45    io_uring_for_each_cqe(ring,h,c){ seen++; }
46    io_uring_cq_advance(ring,seen);
47    done+=batch;
48  }
49  return (now_ns()-t0)/(double)OPS;
50}
51
52int main(int argc,char**argv){
53  if(argc<3){ fprintf(stderr,"uso: %s <dir> <etiqueta>\n",argv[0]); return 2; }
54  char path[512]; snprintf(path,sizeof path,"%s/sqpoll.bin",argv[1]);
55  int fd=open(path,O_CREAT|O_RDWR|O_TRUNC,0644);
56  if(fd<0){ fprintf(stderr,"no pude crear %s: %s\n",path,strerror(errno)); return 1; }
57  char *b=malloc(MB); memset(b,0x5A,MB);
58  for(int i=0;i<SIZE/MB;i++) if(write(fd,b,MB)!=MB){ perror("write"); return 1; }
59  free(b);
60  /* Se lee entero una vez para dejarlo en cache: se mide el camino de ENTREGA, no el disco. */
61  char *buf=aligned_alloc(4096,DEPTH*BS);
62  for(long o=0;o<SIZE;o+=BS) sink=pread(fd,buf,BS,o);
63  long nblk=SIZE/BS;
64
65  printf("\n### 4K aleatorios en cache sobre %s (profundidad %d)\n",argv[2],DEPTH);
66  printf("%-44s %10s %10s\n","BENCH (ns/op)","min","mediana");
67
68  double r[ROUNDS];
69  for(int q=0;q<ROUNDS;q++){
70    double t0=now_ns();
71    for(long i=0;i<OPS;i++) sink=pread(fd,buf,BS,(long)((i*7919)%nblk)*BS);
72    r[q]=(now_ns()-t0)/(double)OPS;
73  }
74  report("pread 4K (una syscall por op)",r,ROUNDS,OPS);
75
76  struct io_uring ring;
77  if(io_uring_queue_init(256,&ring,0)==0){
78    for(int q=0;q<ROUNDS;q++) r[q]=pase(&ring,fd,buf,nblk);
79    report("io_uring sin SQPOLL",r,ROUNDS,OPS);
80    io_uring_queue_exit(&ring);
81  } else printf("io_uring: no disponible (%s)\n",strerror(errno));
82
83  struct io_uring_params p; memset(&p,0,sizeof p);
84  p.flags=IORING_SETUP_SQPOLL; p.sq_thread_idle=2000;
85  if(io_uring_queue_init_params(256,&ring,&p)==0){
86    /* Con SQPOLL el fd hay que registrarlo: el hilo del kernel no tiene la tabla de fds. */
87    int rc=io_uring_register_files(&ring,&fd,1);
88    int usar_fijo = (rc==0);
89    for(int q=0;q<ROUNDS;q++){
90      double t0=now_ns();
91      for(long done=0;done<OPS;){
92        int batch=(OPS-done<DEPTH)?(int)(OPS-done):DEPTH;
93        for(int k=0;k<batch;k++){
94          struct io_uring_sqe *s=io_uring_get_sqe(&ring);
95          io_uring_prep_read(s,usar_fijo?0:fd,buf+k*BS,BS,(long)(((done+k)*7919)%nblk)*BS);
96          if(usar_fijo) s->flags|=IOSQE_FIXED_FILE;
97        }
98        io_uring_submit_and_wait(&ring,batch);
99        struct io_uring_cqe *c; unsigned h; int seen=0;
100        io_uring_for_each_cqe(&ring,h,c){ if(c->res<0) sink=c->res; seen++; }
101        io_uring_cq_advance(&ring,seen);
102        done+=batch;
103      }
104      r[q]=(now_ns()-t0)/(double)OPS;
105    }
106    report(usar_fijo?"io_uring SQPOLL (fd registrado)":"io_uring SQPOLL (fd normal)",r,ROUNDS,OPS);
107    io_uring_queue_exit(&ring);
108  } else printf("SQPOLL: no disponible (%s) — pide CAP_SYS_NICE\n",strerror(errno));
109
110  unlink(path); close(fd);
111  return 0;
112}