cómo contar el número de diferencias en grandes flujos de forma rápida?

Quiero contar la cantidad de diferencias (diferentes bytes) en dos grandes flujos (dispositivos / files). Por ejemplo, dos discos duros o un disco duro y /dev/zero .

El progtwig (s) involucrado debe ser rápido, tan rápido como entran las transmisiones (digamos 1GB / s, aunque 0.2GB / s probablemente esté bien), y pueden usar como máximo unos pocos GB de RAM y de files tmp. En particular, no hay un sistema de files disponible que sea lo suficientemente grande como para almacenar las diferencias que se contarán. Las secuencias tienen varios TB de tamaño.

El recuento no necesita (y de hecho no debe) tratar el espacio en blanco o las líneas de alimentación de forma diferente a otros caracteres. Las secuencias son solo binarias y no interpretables como text.

Dije streams, aunque los dispositivos son realmente buscables. Pero, por razones de velocidad, todo debe hacerse preferiblemente con un solo pase de transmisión sin búsquedas, si es posible.

Lo que intenté hasta ahora:

 cmp -l /dev/sda /dev/sdb | wc 

Pero esta es una manera de desacelerar; wc solo usa un núcleo de CPU> 50% y la salida es solo de aproximadamente 2 MB / s, que es demasiado lenta en un factor de 100.

Con files buscables, puede paralelizar esto. Por ejemplo, podría hacer algo como esto (no probado):

 # Number of jobs to run at once jobs=4 # Block size bs=512 # Total number of block to work with size=1000000 # Or, to calculate the size automatically for one of the disks, #size=$(( $(df -B 1 /dev/sda | tail -n1 | awk '{ print $2 }') / $bs )) # Number of blocks per job count=$(( $size / $jobs )) for i in $(seq 1 $jobs) ; do seek=$(( ($i - 1) * $count )) cmp -l <(dd bs=$bs skip=$seek count=$count if=/dev/sdb1) <(dd bs=$bs skip=$seek count=$count if=/dev/sdb2) | wc & done 

dd solo searchá una vez cuando comience por primera vez.

No obtendrá 1GB / s a ​​less que su hardware lo admita. Los discos duros más rápidos de 7200 rpm pueden alcanzar 200MB / s en una parte de su superficie, y más de 100MB a 150MB en toda la superficie. Así que su figura "probablemente está bien" está por encima de la cifra ideal a less que tenga unidades inusualmente rápidas ( 10krpm, RAID0).

cmp -l | wc cmp -l | wc puede estar limitado por la CPU porque le está pidiendo a wc que cuente palabras, lo cual es un poco complicado. cmp -l | wc -l cmp -l | wc -l networkingucirá la carga en la CPU.

A less que tenga discos muy rápidos, cmp -l | wc -l cmp -l | wc -l probablemente ya esté vinculado a IO. Si está utilizando todo el ancho de banda del disco, la paralelización no lo ayudará.

Si cmp -l | wc -l cmp -l | wc -l aún está vinculado a la CPU, o si desea liberar su CPU para hacer otras cosas, un progtwig ad hoc que realice la count tendrá un mejor performance. Advertencia, no probado.

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define BUFFER_SIZE 1048576 unsigned char buf1[BUFFER_SIZE]; unsigned char buf2[BUFFER_SIZE]; int main (int argc, char *argv[]) { FILE *f1, *f2; unsigned long long total = 0, diffs = 0; unsigned n1, n2, n, i; f1 = fopen(argv[1], "r"); if (f1 == NULL) {perror(argv[1]); return 2;} f2 = fopen(argv[2], "r"); if (f2 == NULL) {perror(argv[2]); return 2;} do { n1 = fread(buf1, 1, BUFFER_SIZE, f1); n2 = fread(buf2, 1, BUFFER_SIZE, f2); if (n1 > n2) n = n2; else n = n1; for (i = 0; i < n; i++) if (buf1[i] != buf2[i]) ++diffs; total += n; } while (n1 == BUFFER_SIZE && n2 == BUFFER_SIZE); printf("%llu\n", diffs); if (ferror(f1)) {perror(argv[1]);} if (ferror(f2)) {perror(argv[2]);} if (n1 != n2) { fprintf(stderr, "Stopped after %llu bytes.\n", total); return 1; } return 0; }