¿Por qué fsync() toma mucho más tiempo en Linux kernel 3.1.*Que kernel 3.0
linux-kernel (2)
Tengo un programa de prueba. Tarda unos 37 segundos en el núcleo de Linux 3.1. *, Pero solo lleva alrededor de 1 segundo en kernel 3.0.18 (simplemente reemplazo el kernel en la misma máquina que antes). Por favor, dame una pista sobre cómo mejorarlo en Kernel 3.1. ¡Gracias!
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int my_fsync(int fd)
{
// return fdatasync(fd);
return fsync(fd);
}
int main(int argc, char **argv)
{
int rc = 0;
int count;
int i;
char oldpath[1024];
char newpath[1024];
char *writebuffer = calloc(1024, 1);
snprintf(oldpath, sizeof(oldpath), "./%s", "foo");
snprintf(newpath, sizeof(newpath), "./%s", "foo.new");
for (count = 0; count < 1000; ++count) {
int fd = open(newpath, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
if (fd == -1) {
fprintf(stderr, "open error! path: %s/n", newpath);
exit(1);
}
for (i = 0; i < 10; i++) {
rc = write(fd, writebuffer, 1024);
if (rc != 1024) {
fprintf(stderr, "underwrite!/n");
exit(1);
}
}
if (my_fsync(fd)) {
perror("fsync failed!/n");
exit(1);
}
if (close(fd)) {
perror("close failed!/n");
exit(1);
}
if (rename(newpath, oldpath)) {
perror("rename failed!/n");
exit(1);
}
}
return 0;
}
# strace -c ./testfsync
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
98.58 0.068004 68 1000 fsync
0.84 0.000577 0 10001 write
0.40 0.000275 0 1000 rename
0.19 0.000129 0 1003 open
0.00 0.000000 0 1 read
0.00 0.000000 0 1003 close
0.00 0.000000 0 1 execve
0.00 0.000000 0 1 1 access
0.00 0.000000 0 3 brk
0.00 0.000000 0 1 munmap
0.00 0.000000 0 2 setitimer
0.00 0.000000 0 68 sigreturn
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 mprotect
0.00 0.000000 0 2 writev
0.00 0.000000 0 2 rt_sigaction
0.00 0.000000 0 6 mmap2
0.00 0.000000 0 2 fstat64
0.00 0.000000 0 1 set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00 0.068985 14099 1 total
Kernel 3.1. * Está haciendo la sincronización, 3.0.18 está fingiendo. Tu código tiene 1,000 escrituras sincronizadas. Como trunca el archivo, cada escritura también amplía el archivo. Entonces realmente tienes 2.000 operaciones de escritura. La latencia típica de escritura en el disco duro es de aproximadamente 20 milisegundos por E / S. Entonces 2,000 * 20 = 40,000 milisegundos o 40 segundos. Entonces parece correcto, asumiendo que estás escribiendo en un disco duro típico.
Básicamente, al sincronizar después de cada escritura, no le da al kernel la capacidad de almacenar en caché o solapar las escrituras de manera eficiente y forzar el comportamiento del peor de los casos en cada operación. Además, el disco duro termina teniendo que ir y venir entre donde se escriben los datos y dónde se escriben los metadatos una vez para cada escritura.
Encontrado el motivo. Barreras del sistema de archivos habilitadas por defecto en ext3 para kernel 3.1 de Linux (http://kernelnewbies.org/Linux_3.1). Después de desactivar las barreras, se vuelve mucho más rápido.