Pipe

管道和重定向速度,pv 和 UUOC

  • September 4, 2020

我正在測試不同的方法來產生隨機垃圾,並通過管道輸出來比較它們的速度pv,如下所示:

$ cmd | pv -s "$size" -S > /dev/null

我還想要一個“基準參考”,所以我測量了最快的“生成器”,cat具有最快的源,/dev/zero

$ cat /dev/zero | pv -s 100G -S > /dev/null
100GiB 0:00:33 [2,98GiB/s] [=============================>] 100%   

3GB/s **,**這非常令人印象深刻,特別是與我從/dev/urandom.

但是,嘿,對於/dev/zero我不需要的特殊情況cat!只是為了好玩,我刪除了這本教科書UUOC

$ < /dev/zero pv -s 100G -S > /dev/null
100GiB 0:00:10 [9,98GiB/s] [=============================>] 100%            

什麼???幾乎10GB/秒? 怎樣才能將cat管道的拆除速度提高三倍以上?如果使用較慢的源,例如/dev/urandom差異可以忽略不計。是pv在做一些巫毒魔法嗎?所以我測試了:

$ dd if=/dev/zero iflag=count_bytes count=200G of=/dev/null status=progress
205392969728 bytes (205 GB, 191 GiB) copied, 16 s, 12,8 GB/s

12,8 GB/秒!與 相同的球場pv,比使用管道快 4 倍。

cat罪魁禍首嗎?管道與重定向有很大不同嗎?畢竟,兩者都去pvas stdin,對吧?什麼可以解釋這種巨大的差異?

殺手鐧是使用兩個程序。

With cat | pv, catreads and writes, and pvreads and writes, 兩個程序都需要執行:

$ perf stat sh -c 'cat /dev/zero | pv -s 100G -S > /dev/null'
100GiB 0:00:26 [3.72GiB/s] [====================================================================================>] 100%            

Performance counter stats for 'sh -c cat /dev/zero | pv -s 100G -S > /dev/null':

        34,048.63 msec task-clock                #    1.267 CPUs utilized          
        1,676,706      context-switches          #    0.049 M/sec                  
            3,678      cpu-migrations            #    0.108 K/sec                  
              304      page-faults               #    0.009 K/sec                  
  119,270,941,758      cycles                    #    3.503 GHz                      (74.89%)
  137,822,862,590      instructions              #    1.16  insn per cycle           (74.94%)
   32,379,369,104      branches                  #  950.974 M/sec                    (75.14%)
      216,658,446      branch-misses             #    0.67% of all branches          (75.04%)

     26.865741948 seconds time elapsed

      1.257950000 seconds user
     38.893870000 seconds sys

pv只需要讀取和pv寫入,不需要上下文切換(或幾乎不需要):

$ perf stat sh -c '< /dev/zero pv -s 100G -S > /dev/null'
100GiB 0:00:07 [13.3GiB/s] [====================================================================================>] 100%            

Performance counter stats for 'sh -c < /dev/zero pv -s 100G -S > /dev/null':

         7,501.68 msec task-clock                #    1.000 CPUs utilized          
               37      context-switches          #    0.005 K/sec                  
                0      cpu-migrations            #    0.000 K/sec                  
              198      page-faults               #    0.026 K/sec                  
   27,916,420,023      cycles                    #    3.721 GHz                      (75.00%)
   62,787,377,126      instructions              #    2.25  insn per cycle           (74.99%)
   15,361,951,954      branches                  # 2047.801 M/sec                    (75.03%)
       51,741,595      branch-misses             #    0.34% of all branches          (74.98%)

      7.505304560 seconds time elapsed

      1.768600000 seconds user
      5.733786000 seconds sys

有一些並行性(“使用了 1.267 個 CPU”),但這並不能彌補上下文切換數量上的巨大差異。

考慮到數據路徑,情況可能會更糟——在第一種情況下,數據似乎/dev/zerocat核心pv/dev/null第二個,數據從核心流向pv,返回核心。但在第一種情況下,pv用於splice從管道複製數據,避免通過核心擁有的記憶體。

引用自:https://unix.stackexchange.com/questions/607737