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…
tasas: los 4 experimentos que §9 dejó nombrados, medidos con root
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}