A opção “bs” em “dd” realmente melhora a velocidade?

51

De vez em quando, me disseram que, para aumentar a velocidade de um "dd", eu deveria escolher cuidadosamente um "tamanho de bloco" adequado.

Mesmo aqui, no ServerFault, outra pessoa escreveu que " ... o tamanho de bloco ideal depende do hardware ... " ( iain) ou " ... o tamanho perfeito dependerá do seu barramento do sistema, do controlador do disco rígido, da própria unidade específica e dos drivers de cada um deles ... " (chris-s)

Como meu sentimento era um pouco diferente ( BTW: Eu pensei que o tempo necessário para ajustar profundamente o parâmetro bs era muito maior do que o ganho recebido, em termos de economia de tempo, e que o padrão era razoável ), hoje eu acabei de fazer alguns benchmarks rápidos e sujos.

Para diminuir as influências externas, decidi ler:

  • de um cartão MMC externo
  • de uma partição interna

e:

  • com sistemas de arquivos relacionados umounted
  • enviando a saída para / dev / null para evitar problemas relacionados à "velocidade de gravação";
  • evitando alguns problemas básicos de armazenamento em cache do HDD, pelo menos quando envolve o HDD.

Na tabela a seguir, eu relatei minhas descobertas, lendo 1 GB de dados com valores diferentes de "bs" ( você pode encontrar os números brutos no final desta mensagem ):

Basicamente, ele capta isso:

  • MMC: com um bs = 4 (sim! 4 bytes), atingi uma taxa de transferência de 12MB / s. Valores não tão distantes até o máximo 14.2 / 14.3 que obtive de bs = 5 e acima;

  • HDD: com um bs = 10 eu alcancei 30 MB / s. Certamente menor que os 95,3 MB com o padrão bs = 512 mas ... significativo também.

Além disso, ficou muito claro que o tempo de processamento da CPU era inversamente proporcional ao valor bs (mas isso parece razoável, pois quanto menor o bs, maior o número de chamadas sys geradas pelo dd).

Tendo dito o acima, agora a pergunta: alguém pode explicar (um hacker de kernel?) quais são os principais componentes / sistemas envolvidos em tal taxa de transferência, e se realmente vale o esforço em especificar um bs maior que o padrão?

Caso MMC - números brutos

bs = 1M

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1M count=1000
1000+0 record dentro
1000+0 record fuori
1048576000 byte (1,0 GB) copiati, 74,1239 s, 14,1 MB/s

real    1m14.126s
user    0m0.008s
sys     0m1.588s

bs = 1k

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1k count=1000000
1000000+0 record dentro
1000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 72,7795 s, 14,1 MB/s

real    1m12.782s
user    0m0.244s
sys     0m2.092s

bs = 512

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=512 count=2000000
2000000+0 record dentro
2000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 72,867 s, 14,1 MB/s

real    1m12.869s
user    0m0.324s
sys     0m2.620s

bs = 10

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=10 count=100000000
100000000+0 record dentro
100000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 70,1662 s, 14,3 MB/s

real    1m10.169s
user    0m6.272s
sys     0m28.712s

bs = 5

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=5 count=200000000
200000000+0 record dentro
200000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 70,415 s, 14,2 MB/s

real    1m10.417s
user    0m11.604s
sys     0m55.984s

bs = 4

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=4 count=250000000
250000000+0 record dentro
250000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 80,9114 s, 12,4 MB/s

real    1m20.914s
user    0m14.436s
sys     1m6.236s

bs = 2

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=2 count=500000000
500000000+0 record dentro
500000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 161,974 s, 6,2 MB/s

real    2m41.976s
user    0m28.220s
sys     2m13.292s

bs = 1

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1 count=1000000000
1000000000+0 record dentro
1000000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 325,316 s, 3,1 MB/s

real    5m25.318s
user    0m56.212s
sys     4m28.176s

Caso do HDD - números brutos

bs = 1

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1 count=1000000000
1000000000+0 record dentro
1000000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 341,461 s, 2,9 MB/s

real    5m41.463s
user    0m56.000s
sys 4m44.340s

bs = 2

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=2 count=500000000
500000000+0 record dentro
500000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 164,072 s, 6,1 MB/s

real    2m44.074s
user    0m28.584s
sys 2m14.628s

bs = 4

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=4 count=250000000
250000000+0 record dentro
250000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 81,471 s, 12,3 MB/s

real    1m21.473s
user    0m14.824s
sys 1m6.416s

bs = 5

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=5 count=200000000
200000000+0 record dentro
200000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 66,0327 s, 15,1 MB/s

real    1m6.035s
user    0m11.176s
sys 0m54.668s

bs = 10

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=10 count=100000000
100000000+0 record dentro
100000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 33,4151 s, 29,9 MB/s

real    0m33.417s
user    0m5.692s
sys 0m27.624s

bs = 512 (compensando a leitura, para evitar o armazenamento em cache)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=512 count=2000000 skip=6000000
2000000+0 record dentro
2000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 10,7437 s, 95,3 MB/s

real    0m10.746s
user    0m0.360s
sys 0m2.428s

bs = 1k (compensando a leitura, para evitar o armazenamento em cache)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1k count=1000000 skip=6000000
1000000+0 record dentro
1000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 10,6561 s, 96,1 MB/s

real    0m10.658s
user    0m0.164s
sys 0m1.772s

bs = 1k (compensando a leitura, para evitar o armazenamento em cache)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1M count=1000 skip=7000
1000+0 record dentro
1000+0 record fuori
1048576000 byte (1,0 GB) copiati, 10,7391 s, 97,6 MB/s

real    0m10.792s
user    0m0.008s
sys 0m1.144s
    
por Damiano Verzulli 08.12.2014 / 21:34

2 respostas

23

O que você fez é apenas um teste de velocidade de leitura. se você estiver copiando blocos para outro dispositivo, você tem pausas na leitura enquanto o outro dispositivo está aceitando os dados que deseja gravar, quando isso acontece, é possível atingir problemas de latência rotacional no dispositivo de leitura (se for um disco rígido) e Geralmente, é mais rápido ler os blocos de 1M do disco rígido quando você se depara com a latência rotacional com menos frequência.

Eu sei que quando estou copiando discos rígidos, obtenho uma taxa mais rápida especificando bs=1M do que usando bs=4k ou o padrão. Estou falando de melhorias de velocidade de 30 a 300%. Não há necessidade de ajustá-lo para o melhor absoluto, a menos que seja tudo o que você faz todos os dias. mas escolher algo melhor que o padrão pode reduzir as horas do tempo de execução.

Quando você estiver usando para valer, experimente alguns números diferentes e envie o sinal dd process a SIGUSR1 para que ele emita um relatório de status para que você possa ver como está indo.

✗ killall -SIGUSR1 dd
1811+1 records in
1811+1 records out
1899528192 bytes (1.9 GB, 1.8 GiB) copied, 468.633 s, 4.1 MB/s
    
por 09.12.2014 / 01:57
8

Com relação ao disco rígido interno, pelo menos - quando você está lendo do dispositivo, a camada de bloco pelo menos tem que recuperar um setor de 512 bytes.

Portanto, ao manipular uma leitura de 1 byte, você só leu realmente do disco na recuperação de byte alinhada do setor. Os restantes 511 vezes são servidos pelo cache.

Você pode provar isso da seguinte maneira, neste exemplo sdb é um disco de interesse:

# grep sdb /proc/diskstats
8      16 sdb 767 713 11834 6968 13710 6808 12970792 6846477 0 76967 6853359
...
# dd if=/dev/sdb of=/dev/null bs=1 count=512
512+0 records in
512+0 records out
512 bytes (512 B) copied, 0.0371715 s, 13.8 kB/s
# grep sedb /proc/diskstats
8      16 sdb 768 713 11834 6968 13710 6808 12970792 6846477 0 76967 6853359
...

A quarta coluna (que conta as leituras) indica que apenas 1 leitura ocorreu, apesar do fato de você ter solicitado leituras de 1 byte. Esse é o comportamento esperado, já que esse dispositivo (um disco SATA 2) precisa no mínimo retornar seu tamanho de setor. O kernel simplesmente está armazenando todo o setor em cache.

O maior fator em jogo nessas solicitações de tamanho é a sobrecarga de emissão de uma chamada de sistema para uma leitura ou gravação. De fato, emitindo a chamada para < 512 é ineficiente. Leituras muito grandes requerem menos chamadas do sistema ao custo de mais memória sendo usada para fazê-lo.

4096 é tipicamente um número "seguro" para leitura porque:

  • Ao ler com cache ativado (o padrão), uma página é 4k. Preencher uma página com < Leituras de 4k são mais complicadas do que manter o tamanho de páginas e páginas iguais.
  • A maioria dos tamanhos de bloco do sistema de arquivos é definida como 4k.
  • Não é um número pequeno o suficiente (talvez para SSDs agora é) para causar sobrecarga syscall, mas não um número grande o suficiente para consumir muita memória.
por 12.01.2015 / 03:36