単一のファイルにアクセスするtmpfsは、複数のファイルにアクセスするよりも遅いです。

単一のファイルにアクセスするtmpfsは、複数のファイルにアクセスするよりも遅いです。

さまざまな(1.6GB)ブロックを読む同じファイルストアのtmpfs最大速度は約20スレッドで2.5GB / sです。

ここに画像の説明を入力してください。

ただし、同じチャンクが別のファイルに分割されると、tmpfs22 GB / sになります。

ここに画像の説明を入力してください。

このボトルネックの原因は何ですか?tmpfs複数のファイルでできるだけ早く単一のファイルで作業する方法はありますか?

また現れる

書き込みは読み取りよりはるかに簡単ですが、問題と速度の違いは似ています。

$ cd /mnt/tmpfs
$ cores=$(seq 64)
$ # -u disables GNU Parallel's on-disk buffer
$ time parallel -n0 -u  'yes $(seq 1000) | head -c 1600M' ::: $cores > 100g

real    3m54.286s
user    1m10.592s
sys     246m42.804s

$ time parallel 'yes $(seq 1000) | head -c 1600M > {#}' ::: $cores

real    0m26.308s
user    1m21.283s
sys     24m45.152s

これには64個のコアと200GBのRAM(スワップなし)が必要ですtmpfsが、より小さなハードウェアで効果を再現できます。

GNU Parallel がない場合は、次のように似た数字を取得できます。

time (
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
yes $(seq 1000) | head -c 1600M & 
wait
) > 100g

time (
yes $(seq 1000) | head -c 1600M > 1 &
yes $(seq 1000) | head -c 1600M > 2 &
yes $(seq 1000) | head -c 1600M > 3 &
yes $(seq 1000) | head -c 1600M > 4 &
yes $(seq 1000) | head -c 1600M > 5 &
yes $(seq 1000) | head -c 1600M > 6 &
yes $(seq 1000) | head -c 1600M > 7 &
yes $(seq 1000) | head -c 1600M > 8 &
yes $(seq 1000) | head -c 1600M > 9 &
yes $(seq 1000) | head -c 1600M > 10 &
yes $(seq 1000) | head -c 1600M > 11 &
yes $(seq 1000) | head -c 1600M > 12 &
yes $(seq 1000) | head -c 1600M > 13 &
yes $(seq 1000) | head -c 1600M > 14 &
yes $(seq 1000) | head -c 1600M > 15 &
yes $(seq 1000) | head -c 1600M > 16 &
yes $(seq 1000) | head -c 1600M > 17 &
yes $(seq 1000) | head -c 1600M > 18 &
yes $(seq 1000) | head -c 1600M > 19 &
yes $(seq 1000) | head -c 1600M > 20 &
yes $(seq 1000) | head -c 1600M > 21 &
yes $(seq 1000) | head -c 1600M > 22 &
yes $(seq 1000) | head -c 1600M > 23 &
yes $(seq 1000) | head -c 1600M > 24 &
yes $(seq 1000) | head -c 1600M > 25 &
yes $(seq 1000) | head -c 1600M > 26 &
yes $(seq 1000) | head -c 1600M > 27 &
yes $(seq 1000) | head -c 1600M > 28 &
yes $(seq 1000) | head -c 1600M > 29 &
yes $(seq 1000) | head -c 1600M > 30 &
yes $(seq 1000) | head -c 1600M > 31 &
yes $(seq 1000) | head -c 1600M > 32 &
yes $(seq 1000) | head -c 1600M > 33 &
yes $(seq 1000) | head -c 1600M > 34 &
yes $(seq 1000) | head -c 1600M > 35 &
yes $(seq 1000) | head -c 1600M > 36 &
yes $(seq 1000) | head -c 1600M > 37 &
yes $(seq 1000) | head -c 1600M > 38 &
yes $(seq 1000) | head -c 1600M > 39 &
yes $(seq 1000) | head -c 1600M > 40 &
yes $(seq 1000) | head -c 1600M > 41 &
yes $(seq 1000) | head -c 1600M > 42 &
yes $(seq 1000) | head -c 1600M > 43 &
yes $(seq 1000) | head -c 1600M > 44 &
yes $(seq 1000) | head -c 1600M > 45 &
yes $(seq 1000) | head -c 1600M > 46 &
yes $(seq 1000) | head -c 1600M > 47 &
yes $(seq 1000) | head -c 1600M > 48 &
yes $(seq 1000) | head -c 1600M > 49 &
yes $(seq 1000) | head -c 1600M > 50 &
yes $(seq 1000) | head -c 1600M > 51 &
yes $(seq 1000) | head -c 1600M > 52 &
yes $(seq 1000) | head -c 1600M > 53 &
yes $(seq 1000) | head -c 1600M > 54 &
yes $(seq 1000) | head -c 1600M > 55 &
yes $(seq 1000) | head -c 1600M > 56 &
yes $(seq 1000) | head -c 1600M > 57 &
yes $(seq 1000) | head -c 1600M > 58 &
yes $(seq 1000) | head -c 1600M > 59 &
yes $(seq 1000) | head -c 1600M > 60 &
yes $(seq 1000) | head -c 1600M > 61 &
yes $(seq 1000) | head -c 1600M > 62 &
yes $(seq 1000) | head -c 1600M > 63 &
yes $(seq 1000) | head -c 1600M > 64 &
wait
)

tmpfsUbuntu 20.04のデフォルト値は次のとおりです。

$ uname -a
Linux r815 5.4.0-66-generic #74-Ubuntu SMP Wed Jan 27 22:54:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
$ mount
tmpfs on /mnt/tmpfs type tmpfs (rw,noatime)

これは私たちに役立つかもしれませんが、同様の状況がHDDブロックデバイスにも当てはまるようです。

# Read the full disk into cache
sudo pv /dev/sde >/dev/null
# Read the full disk again from cache
time sudo cat /dev/sde >/dev/null

real    1m20.100s
user    0m0.739s
sys     1m19.351s

# Read the full disk again from cache 64 times in parallel
seq 64 | time sudo parallel -N0 'cat /dev/sde >/dev/null'

297.64user 39359.17system 12:44.60elapsed 5186%CPU (0avgtext+0avgdata 19752maxresident)k
0inputs+8outputs (0major+117384minor)pagefaults 0swaps

# Read the full disk again from cache as 64 parts in parallel
time sudo parallel -a /dev/sde --pipepart --block -1 -u 'cat >/dev/null'
real    1m5.796s
user    0m13.331s
sys     67m34.396s

関連情報