Estou escrevendo blocos de 4 * 4 KB em um arquivo. É consistentemente cerca de 50% mais lento se eu usei fallocate()
para pré-alocar o arquivo com 9 blocos, em vez de apenas pré-alocar os 4 blocos. Por quê?
Parece haver um ponto de corte entre a pré-alocação de 8 e 9 blocos. Também estou me perguntando por que as gravações de primeiro e segundo bloco são consistentemente mais lentas.
Este teste é resumido em algum código de cópia de arquivo com o qual estou jogando. Inspirado por esta pergunta sobre dd
, eu Estou usando O_DSYNC
escreve para que eu possa medir o progresso real das gravações em disco. (A ideia era começar a copiar um bloco pequeno para medir a latência mínima e, em seguida, aumentar o tamanho do bloco de forma adaptável para melhorar o rendimento).
Estou testando o Fedora 28, em um laptop com um disco rígido giratório. Ele foi atualizado de um Fedora anterior, então o sistema de arquivos não é novinho em folha. Eu não acho que estou mexendo nos padrões do sistema de arquivos.
- Kernel: 4.17.19-200.fc28.x86_64
- Sistema de arquivos: ext4, no LVM.
- Opções de montagem: rw, relatime, seclabel
- Campos de
tune2fs -l
- Opções de montagem padrão: user_xattr acl
- Recursos do sistema de arquivos: has_journal ext_attr resize_inode dir_index tipo de arquivo needs_recovery extent 64 bits flex_bg sparse_super large_file huge_file dir_nlink extra_isize
- Sinalizadores do sistema de arquivos: signed_directory_hash
- Tamanho do bloco: 4096
- Blocos gratuitos: 7866091
Horários de strace -s3 -T test-program.py
:
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000048>
write(3, "#! /usr/bin/python3
import os
# Required third party module,
# install with "pip3 install --user fallocate".
from fallocate import fallocate
block = b'openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000048>
write(3, "#! /usr/bin/python3
import os
# Required third party module,
# install with "pip3 install --user fallocate".
from fallocate import fallocate
block = b'%pre%' * 4096
for alloc in [0, 4, 8, 9]:
# Open file for writing, with implicit fdatasync().
fd = os.open("out.tmp", os.O_WRONLY | os.O_DSYNC |
os.O_CREAT | os.O_TRUNC)
# Try to pre-allocate space
if alloc:
fallocate(fd, 0, alloc * 4096)
os.write(fd, block)
os.write(fd, block)
os.write(fd, block)
os.write(fd, block)
os.close(fd)
%pre%%pre%"..., 4096) = 4096 <0.036378>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033380>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033359>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033399>
close(3) = 0 <0.000033>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000110>
fallocate(3, 0, 0, 16384) = 0 <0.016467>
fsync(3) = 0 <0.000201>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033062>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.013806>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008324>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008346>
close(3) = 0 <0.000025>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000070>
fallocate(3, 0, 0, 32768) = 0 <0.019096>
fsync(3) = 0 <0.000311>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.032882>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.010824>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008188>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008266>
close(3) = 0 <0.000012>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000050>
fallocate(3, 0, 0, 36864) = 0 <0.022417>
fsync(3) = 0 <0.000260>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.032953>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033265>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033317>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033237>
close(3) = 0 <0.000019>
' * 4096
for alloc in [0, 4, 8, 9]:
# Open file for writing, with implicit fdatasync().
fd = os.open("out.tmp", os.O_WRONLY | os.O_DSYNC |
os.O_CREAT | os.O_TRUNC)
# Try to pre-allocate space
if alloc:
fallocate(fd, 0, alloc * 4096)
os.write(fd, block)
os.write(fd, block)
os.write(fd, block)
os.write(fd, block)
os.close(fd)
%pre%%pre%"..., 4096) = 4096 <0.036378>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033380>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033359>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033399>
close(3) = 0 <0.000033>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000110>
fallocate(3, 0, 0, 16384) = 0 <0.016467>
fsync(3) = 0 <0.000201>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033062>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.013806>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008324>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008346>
close(3) = 0 <0.000025>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000070>
fallocate(3, 0, 0, 32768) = 0 <0.019096>
fsync(3) = 0 <0.000311>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.032882>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.010824>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008188>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.008266>
close(3) = 0 <0.000012>
openat(AT_FDCWD, "out.tmp", O_WRONLY|O_CREAT|O_TRUNC|O_DSYNC|O_CLOEXEC, 0777) = 3 <0.000050>
fallocate(3, 0, 0, 36864) = 0 <0.022417>
fsync(3) = 0 <0.000260>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.032953>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033265>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033317>
write(3, "%pre%%pre%%pre%"..., 4096) = 4096 <0.033237>
close(3) = 0 <0.000019>
test-program.py:
%pre%