Por que um gunzip para pipeline dd desacelera no final?

4

meu comando:

gunzip -c serial2udp.image.gz |
sudo dd of=/dev/mmcblk0 conv=fsync,notrunc status=progress bs=4M

minha saída:

15930949632 bytes (16 GB, 15 GiB) copied, 1049 s, 15.2 MB/s    

0+331128 records in
0+331128 records out
15931539456 bytes (16 GB, 15 GiB) copied, 1995.2 s, 8.0 MB/s

o cartão: Cartão de memória SanDisk Ultra 32GB MicroSDHC classe 10 velocidade até 30MB / s
distribuição: 16.0.4 xenial com xfce
versão do kernel: 4.13.0.37-generic

eu entendo ter 17 minutos parece razoável do que eu li. brincar com tamanho de bloco realmente não parece fazer muita diferença (bs = 100M ainda exibe esse comportamento com timestamps similares). Por que as atualizações estão suspensas e não produz um relatório finalizado por mais 16 minutos?

iotop me diz que mmcqd / 0 ainda está rodando em segundo plano neste momento (em 99% IO), então eu acho que há um cache em algum lugar que está atrasando os 5MB finais mas eu achei que o fsync deveria ter certeza que não aconteça A iotop não mostra nenhuma travessia de tráfego neste momento para o dd. ctrl-c é praticamente inútil e eu não quero corromper meu disco depois de escrever para ele.

    
por cts 09.09.2018 / 14:03

3 respostas

12

I figure there is a cache somewhere that is holding up the final 5MB but I thought fsync should make sure that doesn't happen

conv=fsync significa gravar todos os caches chamando fsync - após dd ter escrito todos os dados. Pendurar no final é exatamente o que ele fará.

Quando o arquivo de saída é mais lento que o arquivo de entrada, os dados gravados por dd podem se acumular em caches. O cache do kernel pode, às vezes, preencher uma fração significativa da RAM do sistema. Isso faz com que informações de progresso sejam muito enganosas. Seu "5MB final" foi apenas um artefato de como dd mostra o progresso.

Se o seu sistema estava realmente armazenando em cache cerca de 8 GB (ou seja, metade dos 16 GB de dados gravados), então acho que você deve ter cerca de 32 GB de RAM ou ter mexido em certas opções do kernel. Veja o link do lwn.net abaixo. Concordo que não obter informações sobre o progresso por 15 minutos é muito frustrante.

Existem alternativas de comandos dd que você pode usar. Se você quiser que dd mostre um progresso mais preciso, talvez seja necessário aceitar mais complexidade. Espero que o seguinte funcione sem degradar seu desempenho, embora talvez a realidade tenha outras idéias além das minhas.

gunzip -c serial2udp.image.gz |
dd iflag=fullblock bs=4M |
sudo dd iflag=fullblock oflag=direct conv=fsync status=progress bs=4M of=/dev/mmcblk0
  • oflag=direct iflag=fullblock evita o empilhamento do cache do kernel, porque ele o ignora completamente.
  • iflag=fullblock é necessário em tal comando AFAIK (por exemplo, porque você está lendo de um pipe e escrevendo usando IO direto). O efeito de perder fullblock é outra complexidade infeliz de dd . Algumas postagens neste site usam isso para argumentar que você deve sempre preferir usar um comando diferente. É difícil encontrar outra maneira de direcionar ou sincronizar o IO.
  • conv=fsync ainda deve ser usado para gravar o cache dispositivo .
  • Eu adicionei um dd extra após gunzip para armazenar em buffer a saída descompactada em paralelo com a gravação em disco. Esse é um dos problemas que torna o desempenho com oflag=direct ou oflag=sync um pouco complexo. O IO normal (não-direto, não-sync) não deve precisar disso, já que ele é armazenado em buffer pelo cache do kernel. Você também pode não precisar do buffer extra se estiver gravando em um disco rígido com 4M de cache de write-back, mas não presumo que um cartão SD tenha tanto.

Você pode usar alternativamente oflag=direct,sync (e não precisa de conv=fsync ). Isso pode ser útil para obter boas informações sobre o progresso se você tiver um dispositivo de saída estranho com centenas de megabytes de cache . Mas normalmente eu penso em oflag=sync como uma barreira potencial para o desempenho.

Existe um artigo link de 2013 que menciona atrasos de um minuto como o seu. Muitas pessoas vêem essa capacidade de armazenar em cache minutos de dados de write-back como indesejáveis. O problema era que o limite do tamanho do cache era aplicado indiscriminadamente, tanto para dispositivos rápidos quanto lentos. Note que não é trivial para o kernel medir a velocidade do dispositivo, porque varia de acordo com os locais dos dados. Por exemplo. se as gravações em cache estiverem espalhadas em locais aleatórios, um disco rígido levará mais tempo para mover repetidamente a cabeça de gravação.

why do the updates hang

O fsync() é uma chamada de sistema única que se aplica a todo o intervalo do dispositivo file . Ele não retorna nenhuma atualização de status antes de ser feito.

    
por 09.09.2018 / 16:59
0

Você deseja usar fullblock . notrunc não tem efeito nos arquivos do dispositivo.

dd of=/dev/mmcblk0 iflag=fullblock status=progress bs=4M
    
por 09.09.2018 / 15:09
0

Não é uma resposta como tal, mas mais um diagnóstico. Use o pv para ver como estão indo as respectivas taxas de fluxo de tubulação, por exemplo. :

pv -c -N raw serial2udp.image.gz |
gunzip |
pv -c -N uncompressed |
sudo dd of=/dev/mmcblk0 conv=fsync,notrunc status=progress bs=4M

Hipóteses:

  1. se ficar lento no final, pode ser que o arquivo .gz seja mais compactado no final, ou está dando gunzip mais trabalho para fazer.
  2. Outra possibilidade é que a própria mídia de gravação seja mais lenta em alguns parte dele, talvez devido a uma peculiaridade de design ou mesmo blocos ruins / marginais. um teste de leitura / escrita não destrutivo pode ser feito com: badblocks -nv /dev/mmcblk0
por 23.09.2018 / 23:15