Por que escrever tamanhos de arquivos variados resulta em velocidades variadas? [duplicado]

0

Aqui estão alguns resultados do comando dd :

$ dd if=/dev/zero of=test.file bs=10M count=1
1+0 records in
1+0 records out
10485760 bytes (10 MB) copied, 0.130214 s, 80.5 MB/s
$ dd if=/dev/zero of=test.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.00683995 s, 153 MB/s
$ dd if=/dev/zero of=test.file bs=512k count=1
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 0.0029348 s, 179 MB/s
$ dd if=/dev/zero of=test.file bs=10k count=1
1+0 records in
1+0 records out
10240 bytes (10 kB) copied, 0.000199126 s, 51.4 MB/s
$ dd if=/dev/zero of=test.file bs=1k count=1
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.000133526 s, 7.7 MB/s
$ dd if=/dev/zero of=test.file bs=1 count=1
1+0 records in
1+0 records out
1 byte (1 B) copied, 0.000149828 s, 6.7 kB/s

Por que existe uma velocidade "corcunda" a 10k?
Por que parece que a velocidade é MUITO mais lenta em tamanhos de arquivo muito pequenos?

    
por agz 09.04.2013 / 01:33

2 respostas

3

O efeito observado é essencialmente correto, mas o método é defeituoso por pelo menos duas razões.

  • Vários tamanhos de buffer são testados, não vários tamanhos de arquivo. Isso ocorre porque o dd é instruído a ler e gravar dos mesmos dois arquivos, enquanto apenas o parâmetro bs= (tamanho dos blocos de leitura e gravação) é alterado.

  • A velocidade de saída de / dev / zero será afetada pelo tamanho (ou buffer) da solicitação de leitura, pois fornecerá a quantidade solicitada de bytes. Isso é relatado pelos registros in-out.

O aparente abrandamento em 1 byte é causado pelo fato de que é necessário mais tempo para criar o arquivo do que para ler e gravar o conteúdo, enquanto na velocidade de 10K, a criação do arquivo deixa de dominar o geral tempo para o julgamento. A degradação da velocidade a partir daí é governada pela velocidade de gravação seqüencial (burst-write) da mídia em que o arquivo de teste está localizado.

Para realizar uma referência da velocidade relativa de vários tamanhos de arquivo, você teria dividido uma quantidade definida de dados entre arquivos, como:

100MB to 10 files 
10MB  to 100 files, 
1MB   to 100 files,
500KB to 204 files, 
64K   to 1600 files
1K    to 102400 files. 

Outros fatores também são reproduzidos, como o tamanho de bloco / setor da mídia e o tamanho mínimo de alocação do sistema de arquivos (tamanho de bloco) para um único arquivo.

Reações a um comentário por serragem.

The "bs" in the dd command is for block size, and combined with the count, a suitable transfer size is specified to calculate I/O rate

Um tamanho adequado e exato pode ser escolhido com esses dois, mas a taxa de E / S será pior para muito baixo bs= . Pelo que eu sei (man dd, GNU Coreutils), o parâmetro dd bs=BYTES é explicado com "ler e gravar bytes Bytes de cada vez". Para mim, parece que:

int bs  // read upto bs bytes in each read operation.
byte[] buffer
while ( bs = file.readIntobufferAndReturnBytesRead(buffer) ) {
     ... use data in buffer
}

Em outras palavras, muitas leituras e gravações pequenas demoram mais que uma grande. Se você acha que se trata de uma declaração falsa, experimente um experimento onde você preenche um balde de 5L com colheres de chá primeiro e compare o tempo necessário para concluir a mesma tarefa usando xícaras. Se você estiver mais familiarizado com o funcionamento interno de dd , apresente sua evidência de porque bs= é "tamanho de bloco" e o que isso significa no código.

Aqui, por que minha segunda afirmação faz sentido:

fixed trial.sh:

MB10="
10MB   1
1MB    10
512KB  20
256KB  40
128KB  80
64KB   160
32KB   320
16KB   640
4KB    2560
1KB    10240
512    20480
64     163840
1      10485760
"

BLOCKS100="
10MB 100
1MB 100
512KB 100
256KB 100
128KB 100
64KB 100
32KB 100
16KB 100
4KB 100
1KB 100
512 100
256 100
128 100
64 100
32 100
16 100
4 100
1 100
"
function trial {
    BS=('echo -e "$1" | awk '{print $1}'')
    CO=('echo -e "$1" | awk '{print $2}'')

    printf "%-8s %-18s %7s %12s %8s\n" bs count data time speed

    for ((i=0;i<${#BS[@]};i++ )); do 
        printf "%-8s %-18s" "bs=${BS[i]}" "count=${CO[i]}"
        dd if=/dev/zero of=/dev/null bs=${BS[i]} count=${CO[i]} \
            |& awk '/bytes/ { printf "%10s  %-12s %8s\n", $3" "$4, $6, $8""$9 }'

    done
    echo
}

trial "$BLOCKS100"
trial "$MB10"

.

$ sh trial.sh
bs       count                 data         time    speed
bs=10MB  count=100           (1.0 GB)  0.781882      1.3GB/s
bs=1MB   count=100           (100 MB)  0.0625649     1.6GB/s
bs=512KB count=100            (51 MB)  0.0193581     2.6GB/s
bs=256KB count=100            (26 MB)  0.00990991    2.6GB/s
bs=128KB count=100            (13 MB)  0.00517942    2.5GB/s
bs=64KB  count=100           (6.4 MB)  0.00299067    2.1GB/s
bs=32KB  count=100           (3.2 MB)  0.00166215    1.9GB/s
bs=16KB  count=100           (1.6 MB)  0.00111013    1.4GB/s
bs=4KB   count=100           (400 kB)  0.000552862   724MB/s
bs=1KB   count=100           (100 kB)  0.000385104   260MB/s
bs=512   count=100            (51 kB)  0.000357936   143MB/s
bs=256   count=100            (26 kB)  0.000509282  50.3MB/s
bs=128   count=100            (13 kB)  0.000419117  30.5MB/s
bs=64    count=100           (6.4 kB)  0.00035179   18.2MB/s
bs=32    count=100           (3.2 kB)  0.000352209   9.1MB/s
bs=16    count=100           (1.6 kB)  0.000341594   4.7MB/s
bs=4     count=100            (400 B)  0.000336425   1.2MB/s
bs=1     count=100            (100 B)  0.000345085   290kB/s

bs       count                 data         time    speed     
bs=10MB  count=1              (10 MB)  0.0177581     563MB/s   566MB/s    567MB/s
bs=1MB   count=10             (10 MB)  0.00759677    1.3GB/s   1.3GB/s    1.2GB/s
bs=512KB count=20             (10 MB)  0.00545376    1.9GB/s   1.9GB/s    1.8GB/s
bs=256KB count=40             (10 MB)  0.00416945    2.5GB/s   2.4GB/s    2.4GB/s
bs=128KB count=80             (10 MB)  0.00396747    2.6GB/s   2.5GB/s    2.6GB/s
bs=64KB  count=160            (10 MB)  0.00446215    2.3GB/s   2.5GB/s    2.5GB/s
bs=32KB  count=320            (10 MB)  0.00451118    2.3GB/s   2.4GB/s    2.4GB/s
bs=16KB  count=640            (10 MB)  0.003922      2.6GB/s   2.5GB/s    2.5GB/s
bs=4KB   count=2560           (10 MB)  0.00613164    1.7GB/s   1.6GB/s    1.7GB/s
bs=1KB   count=10240          (10 MB)  0.0154327     664MB/s   655MB/s    626MB/s
bs=512   count=20480          (10 MB)  0.0279125     376MB/s   348MB/s    314MB/s
bs=64    count=163840         (10 MB)  0.212944     49.2MB/s  50.5MB/s   52.5MB/s
bs=1     count=10485760       (10 MB)  16.0154       655kB/s   652kB/s    640kB/s

A parte relevante para a segunda falha é quando o tamanho dos dados é constante (10 MB). As velocidades são obviamente mais lentas para pedaços muito pequenos. Não sei como explicar o "drop" em bs = 10MB, mas eu poderia adivinhar que é devido a como dd lida com buffering para grandes pedaços.

Eu tive que chegar ao fundo disso (graças à serragem por desafiar minha suposição) ...

Parece que minha suposição sobre o tamanho do buffer == bs está incorreta, mas não é totalmente falso porque o parâmetro bs influencia o tamanho como demonstrado com Um dd que imprime o tamanho do buffer. Isso significa que minha segunda falha não é relevante para arquivos < 8K em sistemas onde o tamanho da página é 4K:

$ ./dd  if=/dev/zero of=/dev/null  bs=1  count=1
OUTPUT_BLOCK_SLOP: 4095
MALLOC INPUT_BLOCK_SLOP: 8195, ibuf: 8196
1+0 records in
1+0 records out
1 byte (1 B) copied, 0.000572 s, 1.7 kB/s


$ ./dd  if=/dev/zero of=/dev/null  bs=1805  count=1
OUTPUT_BLOCK_SLOP: 4095
MALLOC INPUT_BLOCK_SLOP: 8195, ibuf: 10000
1+0 records in
1+0 records out
1805 bytes (1.8 kB) copied, 0.000450266 s, 4.0 MB/s

(dd.c de coreutils 8.20)

 line:text
   21:   #define SWAB_ALIGN_OFFSET 2
   97:   #define INPUT_BLOCK_SLOP (2 * SWAB_ALIGN_OFFSET + 2 * page_size - 1)
   98:   #define OUTPUT_BLOCK_SLOP (page_size - 1)

 1872:  real_buf = malloc (input_blocksize + INPUT_BLOCK_SLOP);         // ibuf
 1889:      real_obuf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP);  // obuf
                 // if conversion is on, othervise obuf=ibuf 

 2187:  page_size = getpagesize ();

homem 3 memcpy

   void *memcpy(void *dest, const void *src, size_t n);

   The memcpy() function copies n bytes from memory area src to memory area
   dest.  The memory areas must not overlap.  Use memmove(3) if the  memory
   areas do overlap.
    
por 09.04.2013 / 02:42
0

Arquivos pequenos exigem que o SO pare e crie entradas de diretório para cada arquivo. Então, um 100mb tem uma entrada de diretório e, em seguida, os dados. A 100 arquivos 1mb de tamanho tem 100 entradas de diretório cada um leva tempo para criar. Também leva tempo para localizar o próximo setor livre e um pouco mais de tempo para pular para aquele setor e começar a escrever. Arquivos realmente pequenos terão intervalos imprecisos. A operação é feita na memória e escrita no disco sempre que o sistema operacional se parece. O tempo representa então o tempo que levou para fazer isso na memória e não no disco. A menos que você tenha um RAID, SSD ou qualquer outro armazenamento super rápido, > 100mb / s é um tempo de memória.

    
por 09.04.2013 / 01:51