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_reflink.c C · 106 lines · 4.0 KB History Who touched what raw

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

1/* bench_reflink.c — copiar un fichero: reflink (FICLONE), copy_file_range y read+write.
2 *
3 * Cierra el experimento 2 de SDD 25 seccion 9 (T11), que quedo sin medir porque exige mkfs sobre
4 * un loop, o sea root. La pregunta: el "copiar en O(1)" que la gente espera de copy_file_range,
5 * cuanto vale de verdad, y en que filesystem.
6 *
7 * Uso: bench_reflink <dir> <etiqueta>   (el dir debe estar en el FS que se quiere medir)
8 * Se compila con: cc -O2 -o bench_reflink bench_reflink.c
9 */
10#define _GNU_SOURCE
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <time.h>
17#include <errno.h>
18#include <sys/ioctl.h>
19#include <sys/stat.h>
20#include <linux/fs.h>
21
22#define MB (1024*1024)
23static long SIZE = 64*MB;   /* se puede fijar por argv[3] en MiB: la copia O(1) hay que verla PLANA */
24#define ROUNDS 7
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); }
28static void report(const char*n,double*r,int c){
29  qsort(r,c,sizeof(double),cmpd);
30  double min=r[0],med=r[c/2];
31  /* El MB/s se imprime solo cuando la copia MUEVE datos. Con reflink el tiempo no depende del
32   * tamano, asi que dividir por el ni significa nada ni se puede citar. */
33  if(min > 1e6) printf("%-40s %9.3f ms %9.3f ms   %8.0f MB/s\n",n,min/1e6,med/1e6,(double)SIZE/(min/1e9)/1e6);
34  else          printf("%-40s %9.3f ms %9.3f ms   (plano: no mueve datos)\n",n,min/1e6,med/1e6);
35  fflush(stdout);
36}
37
38static int src_fd(const char *dir,char *path,size_t n){
39  snprintf(path,n,"%s/origen.bin",dir);
40  int fd=open(path,O_CREAT|O_RDWR|O_TRUNC,0644);
41  if(fd<0) return -1;
42  char *b=malloc(MB); memset(b,0xA5,MB);
43  for(long i=0;i<SIZE/MB;i++) if(write(fd,b,MB)!=MB){ free(b); close(fd); return -1; }
44  free(b);
45  fsync(fd);
46  /* Se deja en cache a proposito: se mide el camino de COPIA, no el de lectura de disco. */
47  return fd;
48}
49
50int main(int argc,char**argv){
51  if(argc<3){ fprintf(stderr,"uso: %s <dir> <etiqueta> [MiB]\n",argv[0]); return 2; }
52  const char *dir=argv[1], *etiqueta=argv[2];
53  if(argc>3) SIZE=atol(argv[3])*MB;
54  char src[512],dst[512];
55  int in=src_fd(dir,src,sizeof src);
56  if(in<0){ fprintf(stderr,"no pude crear el origen en %s: %s\n",dir,strerror(errno)); return 1; }
57  snprintf(dst,sizeof dst,"%s/copia.bin",dir);
58
59  printf("\n### copia de %ld MiB sobre %s\n",SIZE/MB,etiqueta);
60  printf("%-40s %12s %12s\n","BENCH","min","mediana");
61
62  double r[ROUNDS];
63  int ok=0;
64
65  /* 1. reflink de fichero entero: la copia O(1) de verdad (comparte extents COW). */
66  for(int q=0;q<ROUNDS;q++){
67    unlink(dst);
68    int out=open(dst,O_CREAT|O_WRONLY|O_TRUNC,0644);
69    double t0=now_ns();
70    int rc=ioctl(out,FICLONE,in);
71    r[q]=now_ns()-t0;
72    close(out);
73    if(rc<0){ printf("%-40s no soportado (%s)\n","FICLONE (reflink entero)",strerror(errno)); ok=-1; break; }
74  }
75  if(ok==0) report("FICLONE (reflink entero)",r,ROUNDS);
76
77  /* 2. copy_file_range: la API portable. En un FS con reflink cae en el mismo camino; en ext4
78   *    cae a una copia DENTRO del kernel. */
79  for(int q=0;q<ROUNDS;q++){
80    unlink(dst);
81    int out=open(dst,O_CREAT|O_WRONLY|O_TRUNC,0644);
82    loff_t off_in=0,off_out=0; size_t left=(size_t)SIZE;
83    double t0=now_ns();
84    while(left){ ssize_t c=copy_file_range(in,&off_in,out,&off_out,left,0); if(c<=0) break; left-=c; }
85    r[q]=now_ns()-t0;
86    close(out);
87  }
88  report("copy_file_range",r,ROUNDS);
89
90  /* 3. read+write en trozos de 1 MiB: lo que hace un cp cualquiera. */
91  char *buf=malloc(MB);
92  for(int q=0;q<ROUNDS;q++){
93    unlink(dst);
94    int out=open(dst,O_CREAT|O_WRONLY|O_TRUNC,0644);
95    lseek(in,0,SEEK_SET);
96    double t0=now_ns();
97    for(long i=0;i<SIZE/MB;i++){ ssize_t n=read(in,buf,MB); if(n>0) (void)!write(out,buf,n); }
98    r[q]=now_ns()-t0;
99    close(out);
100  }
101  report("read+write (1 MiB)",r,ROUNDS);
102  free(buf);
103
104  unlink(dst); unlink(src); close(in);
105  return 0;
106}