/* bench_io.c — metadatos de FS, resolucion de rutas, copia, io_uring, fallos de pagina, namespaces. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char **environ; static volatile long sink; static inline double now_ns(void){ struct timespec t; clock_gettime(CLOCK_MONOTONIC,&t); return t.tv_sec*1e9+t.tv_nsec; } static int cmpd(const void*a,const void*b){ double x=*(const double*)a,y=*(const double*)b; return (x>y)-(x=0){ (void)!write(fd,"x",1); close(fd);} } /* ruta profunda: base/d/d/d/... (12 niveles) con un fichero al fondo */ char deep[600]; snprintf(deep,sizeof deep,"%s/deep",base); mkdir(deep,0755); for(int i=0;i<12;i++){ strcat(deep,"/d"); mkdir(deep,0755); } char df[700]; snprintf(df,sizeof df,"%s/x",deep); int fd=open(df,O_CREAT|O_WRONLY,0644); if(fd>=0){(void)!write(fd,"x",1);close(fd);} } static void rm_tree(const char *base){ char c[700]; snprintf(c,sizeof c,"rm -rf '%s'",base); (void)!system(c); } static void metadata(const char *base,const char *etiqueta){ char flat[600]; snprintf(flat,sizeof flat,"%s/flat",base); int dfd=open(flat,O_RDONLY|O_DIRECTORY); printf("\n### metadatos sobre %s (%d ficheros en un directorio)\n",etiqueta,NFILES); printf("%-40s %10s %10s\n","BENCH (ns/fichero)","min","mediana"); BENCH("stat() por ruta completa", NFILES, {struct stat s;char f[700];snprintf(f,sizeof f,"%s/f%05d",flat,(int)(i%NFILES));sink=stat(f,&s);}); BENCH("fstatat(dirfd, nombre)", NFILES, {struct stat s;char f[32];snprintf(f,sizeof f,"f%05d",(int)(i%NFILES));sink=fstatat(dfd,f,&s,0);}); BENCH("statx(dirfd,nombre,DONT_SYNC)", NFILES, {struct statx s;char f[32];snprintf(f,sizeof f,"f%05d",(int)(i%NFILES));sink=syscall(SYS_statx,dfd,f,AT_STATX_DONT_SYNC,STATX_BASIC_STATS,&s);}); BENCH("openat(dirfd,nombre)+close", NFILES, {char f[32];snprintf(f,sizeof f,"f%05d",(int)(i%NFILES));int fd=openat(dfd,f,O_RDONLY);if(fd>=0)close(fd);}); { struct open_how how; memset(&how,0,sizeof how); how.flags=O_RDONLY; how.resolve=RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS; int probe=syscall(SYS_openat2,dfd,"f00000",&how,sizeof how); if(probe>=0){ close(probe); BENCH("openat2 RESOLVE_BENEATH+NO_SYMLINKS",NFILES,{char f[32];snprintf(f,sizeof f,"f%05d",(int)(i%NFILES));int fd=syscall(SYS_openat2,dfd,f,&how,sizeof how);if(fd>=0)close(fd);}); } else printf("openat2: no disponible (%s)\n",strerror(errno)); } /* getdents64: barrido completo, coste por entrada */ { double r[ROUNDS]; long cnt=0; for(int q=0;q0){ long off=0; while(offd_reclen; } } close(fd); r[q]=(now_ns()-t0)/(double)c; cnt=c; } report("getdents64 (barrido, sin stat)",r,ROUNDS,cnt); } close(dfd); /* profundidad de ruta */ { char shallow[700],deep[700]; snprintf(shallow,sizeof shallow,"%s/flat/f00000",base); snprintf(deep,sizeof deep,"%s/deep",base); for(int i=0;i<12;i++) strcat(deep,"/d"); strcat(deep,"/x"); BENCH("open ruta corta (2 componentes bajo base)",20000,{int fd=open(shallow,O_RDONLY);if(fd>=0)close(fd);}); BENCH("open ruta 13 componentes mas profunda", 20000,{int fd=open(deep,O_RDONLY);if(fd>=0)close(fd);}); } } static void copia(const char *base){ const long SZ = 64L*1024*1024; char src[700],dst[700]; snprintf(src,sizeof src,"%s/src.bin",base); snprintf(dst,sizeof dst,"%s/dst.bin",base); int fd=open(src,O_CREAT|O_WRONLY|O_TRUNC,0644); char *buf=malloc(1<<20); memset(buf,0xA5,1<<20); for(long w=0;w>20); printf("%-40s %10s %10s\n","BENCH (MB/s)","max","mediana"); double r[ROUNDS]; for(int q=0;q0) (void)!write(d,b,n); r[q]=SZ/((now_ns()-t0)/1e9)/1e6; close(s);close(d);} qsort(r,ROUNDS,sizeof(double),cmpd); printf("%-40s %10.1f %10.1f\n","read()+write() 64K",r[ROUNDS-1],r[ROUNDS/2]); for(int q=0;q0){ ssize_t n=syscall(SYS_copy_file_range,s,&io,d,&oo,left,0); if(n<=0)break; left-=n; } r[q]=SZ/((now_ns()-t0)/1e9)/1e6; close(s);close(d);} qsort(r,ROUNDS,sizeof(double),cmpd); printf("%-40s %10.1f %10.1f\n","copy_file_range()",r[ROUNDS-1],r[ROUNDS/2]); /* materializacion de arbol: hardlink vs copia, 2000 ficheros pequeños */ char lk[700]; snprintf(lk,sizeof lk,"%s/mat",base); mkdir(lk,0755); printf("\n### materializar 2000 ficheros de 1 byte (el problema del store)\n"); BENCH("link() [hardlink]",2000,{char a[700],b[700];snprintf(a,sizeof a,"%s/flat/f%05d",base,(int)i);snprintf(b,sizeof b,"%s/mat/l%05d",base,(int)i);unlink(b);sink=link(a,b);}); BENCH("open+read+write+close [copia]",2000,{char a[700],b[700];char c[64];snprintf(a,sizeof a,"%s/flat/f%05d",base,(int)i);snprintf(b,sizeof b,"%s/mat/c%05d",base,(int)i);int s=open(a,O_RDONLY),d=open(b,O_CREAT|O_WRONLY|O_TRUNC,0644);ssize_t n=read(s,c,sizeof c);(void)!write(d,c,n);close(s);close(d);}); unlink(src); unlink(dst); } static void uring(const char *base){ const long SZ=64L*1024*1024; const int BS=4096; const int DEPTH=32; char src[700]; snprintf(src,sizeof src,"%s/u.bin",base); int fd=open(src,O_CREAT|O_RDWR|O_TRUNC,0644); char *b=malloc(1<<20); memset(b,7,1<<20); for(long w=0;w1?argv[1]:"/tmp/bench-linux"; snprintf(root,sizeof root,"%s",base); rm_tree(root); mk_tree(root); metadata(root, base); copia(root); uring(root); if(argc<=2){ memoria(); namespaces(); } rm_tree(root); return 0; }