volumen solicitud sata rigido reparar realizar puedo puede porque por pendrive pasar para macbook inicializar grandes grande formato formatear error duro dispositivo disco demasiado copiar archivos c file-io buffer

solicitud - porque no puedo pasar archivos a mi usb



¿Qué sucede detrás de las cortinas durante la E/S del disco? (2)

Cuando busco alguna posición en un archivo y escribo una pequeña cantidad de datos (20 bytes), ¿qué sucede tras bambalinas?

Mi punto de vista

Que yo sepa, la unidad de datos más pequeña que se puede escribir o leer desde un disco es un sector (tradicionalmente, 512 bytes, pero ese estándar ahora está cambiando). Eso significa que para escribir 20 bytes, necesito leer todo un sector, modificar parte de él en la memoria y grabarlo en el disco.

Esto es lo que espero que suceda en E / S sin búfer. También espero que la E / S en búfer haga aproximadamente lo mismo, pero sé inteligente acerca de su caché. Por lo tanto, habría pensado que si destruyo la localidad por la ventana haciendo búsquedas y escrituras aleatorias, tanto la E / S con búfer como la que no tiene búfer deberían tener un rendimiento similar ... tal vez con un búffer un poco mejor.

Entonces, una vez más, sé que es una locura que la E / S en búfer solo almacene en búfer un sector, por lo que también podría esperar que tenga un desempeño terrible.

Mi aplicación

Estoy almacenando valores recopilados por un controlador de dispositivo SCADA que recibe telemetría remota por más de cien mil puntos. Hay datos adicionales en el archivo, de modo que cada registro es de 40 bytes, pero solo se deben escribir 20 bytes durante una actualización.

Pre-implementación de referencia

Para comprobar que no necesito soñar con una solución brillantemente diseñada en exceso, he realizado una prueba utilizando unos pocos millones de registros aleatorios escritos en un archivo que podría contener un total de 200,000 registros. Cada prueba siembra el generador de números aleatorios con el mismo valor para ser justo. Primero borro el archivo y lo coloco a la longitud total (aproximadamente 7.6 megas), luego recorro unos millones de veces, pasando un desplazamiento aleatorio del archivo y algunos datos a una de las dos funciones de prueba:

void WriteOldSchool( void *context, long offset, Data *data ) { int fd = (int)context; lseek( fd, offset, SEEK_SET ); write( fd, (void*)data, sizeof(Data) ); } void WriteStandard( void *context, long offset, Data *data ) { FILE *fp = (FILE*)context; fseek( fp, offset, SEEK_SET ); fwrite( (void*)data, sizeof(Data), 1, fp ); fflush(fp); }

Tal vez no hay sorpresas?

El método OldSchool salió en la parte superior - por mucho. Fue más de 6 veces más rápido (1.48 millones versus 232000 registros por segundo). Para asegurarme de que no había encontrado el almacenamiento en caché de hardware, amplié el tamaño de mi base de datos a 20 millones de registros (tamaño de archivo de 763 megas) y obtuve los mismos resultados.

Antes de señalar la llamada obvia a fflush , permítame decir que eliminarlo no tuvo ningún efecto. Me imagino que esto se debe a que el caché debe estar comprometido cuando busco lo suficientemente lejos, que es lo que hago la mayor parte del tiempo.

Entonces, ¿qué está pasando?

Me parece que la E / S en búfer debe estar leyendo (y posiblemente escribiendo todo) una gran parte del archivo cada vez que intento escribir. Debido a que casi nunca aprovecho su caché, esto es extremadamente inútil.

Además (y no conozco los detalles del almacenamiento en caché de hardware en el disco), si la E / S en búfer está intentando escribir un grupo de sectores cuando cambio solo uno, se reduciría la eficacia de la caché de hardware.

¿Hay expertos en discos por ahí que puedan comentar y explicar esto mejor que mis hallazgos experimentales? =)


De hecho, al menos en mi sistema con GNU libc, parece que stdio está leyendo bloques de 4kB antes de volver a escribir la parte modificada. Me parece falso, pero me imagino que alguien pensó que era una buena idea en ese momento.

Lo comprobé escribiendo un programa trivial en C para abrir un archivo, escribir una pequeña cantidad de datos una vez y salir; luego lo ejecutó bajo la estrategia, para ver qué syscalls realmente activó. Escribiendo a una compensación de 10000, vi estos syscalls:

lseek(3, 8192, SEEK_SET) = 8192 read(3, "/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0"..., 1808) = 1808 write(3, "hello", 5) = 5

Parece que querrás seguir con la E / S de estilo Unix de bajo nivel para este proyecto, ¿eh?


Las funciones de la biblioteca estándar de C realizan búferes adicionales y, en general, están optimizadas para lecturas de transmisión, en lugar de IO aleatorias. En mi sistema, no observo las lecturas falsas que Jamey Sharp vio que solo veo lecturas falsas cuando el desplazamiento no está alineado con el tamaño de una página, podría ser que la biblioteca C siempre intente mantener su búfer IO alineado a 4kb o alguna cosa.

En su caso, si está realizando muchas lecturas y escrituras aleatorias en un conjunto de datos razonablemente pequeño, es probable que le sirvan mejor utilizando pread/pwrite para evitar tener que realizar búsquedas de búsqueda, o simplemente crear un mapa de datos y escribir en él. en la memoria (es probable que sea el más rápido, si su conjunto de datos cabe en la memoria).