67979


  * 以下のコードはすべてWindows10のwsl1のUbuntu上で試しています。

私は以下のコードを試しました。(10秒ごとに手動でエンターキー押しています。)

[code]

    $cat /dev/random | pv  >a.txt
     615MiB 0:00:10 [59.4MiB/s]
    1.20GiB 0:00:20 [59.3MiB/s]
    1.80GiB 0:00:30 [61.7MiB/s]
    $cat /dev/random | pv  >>a.txt
     618MiB 0:00:10 [61.7MiB/s]
    1.23GiB 0:00:20 [65.1MiB/s]
    1.81GiB 0:00:30 [61.4MiB/s]
    
[/code]

若干追記のほうが早いですがあまり変わりません。  
また以下のコードを試しました。

[code]

    $cat /dev/random | pv > /dev/null
     740MiB 0:00:10 [70.7MiB/s]
    1.41GiB 0:00:20 [70.8MiB/s]
    2.11GiB 0:00:30 [70.6MiB/s]
    
    $cat /dev/random | pv >> /dev/null
     631MiB 0:00:10 [63.3MiB/s]
    1.22GiB 0:00:20 [61.1MiB/s]
    1.83GiB 0:00:30 [64.2MiB/s]
    
[/code]

こちらは明らかに追記のほうが遅いです。  
勝手な想像ですが、/dev/nullに書き込んでいるので実際のファイルに書き込んだり追記したりするよりも速度差はなくなるのかなと思っていました。

Q.この違いはどこからきているのでしょうか。  
（具体的に何がしたいとかではなく単純に疑問に思って質問しました。）


CC BY-SA 4.0
2020-06-24T15:05:32.133
67962
2020-06-26T15:05:48.627
17106
question
linux ubuntu shell
> /dev/nullと >>/dev/nullの速度の違いについての疑問


pvは`> /dev/null`のときにnullデバイスにwriteしていません。

`> /dev/null`と`>> /dev/null`の差はこれが理由です。

調査に使用したpvのバージョンは以下です。  
pv 1.6.6 - Copyright 2015 Andrew Wood andrew.wood@ivarch.com

* * *

この現象の差は`> /dev/null`と`>> /dev/null`の性能差ではなさそうです。  
pvの代わりにcatにを使ってtimeとstraceを実行してみましたが、有意な差は見受けられませんでした。  
`> /dev/null`と`>> /dev/null`のわずかな差がpvで拡大しているように見えます。

> Q.この違いはどこからきているのでしょうか。

謎の解決にはなっていませんが`pv`が主因のようです。

【追記】

理由がわかりました。  
`pv`は `> /dev/null`のときにwriteしていません。  
`>> /dev/null`のときはwriteしています。  
pvはパイプの性能を計測するのが主たる機能のようですので気を利かせているのかもしれません。

`strace -r -T -ff`を実行しwrieの回数を数えたところ、以下の結果となりました。  
`> /dev/null`は15回  
`>> /dev/null`は13916回

[code]

    openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
    dup2(3, 1)                = 1
    
[/code]

のあと、`write(1`のトレースはありませんでした。  
`pv`の代わりに`cat`を使ったときは当然ですがwriteしています。

* * *

以下は最初に計測したときの結果です。

システムコールの呼び出し回数は`cat > /dev/null`と`cat >> /dev/null`で差異はありませんでした。  
`pv > /dev/null`と`pv >> /dev/null`では大きな差があります。  
`>>
/dev/null`では`read/write/rt_sigaction/select/gettimeofday/time`の呼び出し回数が増えています。  
`splice`は`>> /dev/null`の方が少ないです。  
`alarm`は `>> /dev/null`の方だけに現れます。

【追記】  
よくみるとwriteの回数に大きな差異があります。

[code]

    ==> a.sh <==
    #!/bin/sh
    cat in.data | pv > /dev/null
    
    ==> b.sh <==
    #!/bin/sh
    cat in.data | pv >> /dev/null
    
    ==> aa.sh <==
    #!/bin/sh
    cat in.data | cat > /dev/null
    
    ==> bb.sh <==
    #!/bin/sh
    cat in.data | cat >> /dev/null
    
[/code]

in.dataは1,000,000,000バイトのファイルです。

[code]

    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    time ./a.sh
    ./a.sh の内容 ==>  cat in.data | pv > /dev/null
    ____________________________________________
     953MiB 0:00:00 [1.37GiB/s] [ <=>                                                                                              ]
    0.09user 0.76system 0:00.69elapsed 123%CPU (0avgtext+0avgdata 1008maxresident)k
    0inputs+0outputs (0major+726minor)pagefaults 0swaps
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    time ./b.sh
    ./b.sh の内容 ==>  cat in.data | pv >> /dev/null
    ____________________________________________
     953MiB 0:00:00 [1.27GiB/s] [ <=>                                                                                              ]
    0.10user 0.90system 0:00.75elapsed 133%CPU (0avgtext+0avgdata 1016maxresident)k
    0inputs+0outputs (0major+728minor)pagefaults 0swaps
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    time ./aa.sh
    ./aa.sh の内容 ==>  cat in.data | cat > /dev/null
    ____________________________________________
    0.03user 0.84system 0:00.61elapsed 141%CPU (0avgtext+0avgdata 796maxresident)k
    0inputs+0outputs (0major+683minor)pagefaults 0swaps
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    time ./bb.sh
    ./bb.sh の内容 ==>  cat in.data | cat >> /dev/null
    ____________________________________________
    0.01user 0.73system 0:00.63elapsed 117%CPU (0avgtext+0avgdata 800maxresident)k
    0inputs+0outputs (0major+683minor)pagefaults 0swaps
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    strace -c -f ./a.sh
    ./a.sh の内容 ==>  cat in.data | pv > /dev/null
    ____________________________________________
    strace: Process 3997 attached
    strace: Process 3998 attached
     953MiB 0:00:04 [ 237MiB/s] [         <=>                                                                                      ]
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.782999      391500         2           wait4
      0.00    0.000000           0      7639           read
      0.00    0.000000           0      7641           write
      0.00    0.000000           0        24         1 close
      0.00    0.000000           0        15        10 stat
      0.00    0.000000           0        16           fstat
      0.00    0.000000           0        19           mmap
      0.00    0.000000           0        12           mprotect
      0.00    0.000000           0         5           munmap
      0.00    0.000000           0         9           brk
      0.00    0.000000           0        24           rt_sigaction
      0.00    0.000000           0         2           rt_sigreturn
      0.00    0.000000           0        11         1 ioctl
      0.00    0.000000           0         9         9 access
      0.00    0.000000           0         1           pipe
      0.00    0.000000           0     15260           select
      0.00    0.000000           0         3           dup2
      0.00    0.000000           0         1           getpid
      0.00    0.000000           0         2           clone
      0.00    0.000000           0         3           execve
      0.00    0.000000           0         1         1 msgget
      0.00    0.000000           0         4           fcntl
      0.00    0.000000           0     15263           gettimeofday
      0.00    0.000000           0         1           getuid
      0.00    0.000000           0         1           getgid
      0.00    0.000000           0         3           geteuid
      0.00    0.000000           0         1           getegid
      0.00    0.000000           0         1           getppid
      0.00    0.000000           0         3           arch_prctl
      0.00    0.000000           0         9           time
      0.00    0.000000           0         1           fadvise64
      0.00    0.000000           0        24        12 openat
      0.00    0.000000           0     15260           splice
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.782999                 61270        34 total
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    strace -c -f ./b.sh
    ./b.sh の内容 ==>  cat in.data | pv >> /dev/null
    ____________________________________________
    strace: Process 4005 attached
    strace: Process 4006 attached
     953MiB 0:00:08 [ 116MiB/s] [                 <=>                                                                              ]
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.721400      360700         2           wait4
      0.00    0.000000           0     22899           read
      0.00    0.000000           0     15279           write
      0.00    0.000000           0        24         1 close
      0.00    0.000000           0        15        10 stat
      0.00    0.000000           0        16           fstat
      0.00    0.000000           0        19           mmap
      0.00    0.000000           0        12           mprotect
      0.00    0.000000           0         5           munmap
      0.00    0.000000           0         9           brk
      0.00    0.000000           0      7654           rt_sigaction
      0.00    0.000000           0         2           rt_sigreturn
      0.00    0.000000           0        11         1 ioctl
      0.00    0.000000           0         9         9 access
      0.00    0.000000           0         1           pipe
      0.00    0.000000           0     22890           select
      0.00    0.000000           0         3           dup2
      0.00    0.000000           0     15260           alarm
      0.00    0.000000           0         1           getpid
      0.00    0.000000           0         2           clone
      0.00    0.000000           0         3           execve
      0.00    0.000000           0         1         1 msgget
      0.00    0.000000           0         4           fcntl
      0.00    0.000000           0     53412           gettimeofday
      0.00    0.000000           0         1           getuid
      0.00    0.000000           0         1           getgid
      0.00    0.000000           0         3           geteuid
      0.00    0.000000           0         1           getegid
      0.00    0.000000           0         1           getppid
      0.00    0.000000           0         3           arch_prctl
      0.00    0.000000           0        17           time
      0.00    0.000000           0         1           fadvise64
      0.00    0.000000           0        24        12 openat
      0.00    0.000000           0         1         1 splice
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.721400                137586        35 total
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    strace -c -f ./aa.sh
    ./aa.sh の内容 ==>  cat in.data | cat > /dev/null
    ____________________________________________
    strace: Process 4013 attached
    strace: Process 4014 attached
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.687791      343896         2           wait4
      0.00    0.000000           0     22896           read
      0.00    0.000000           0     22889           write
      0.00    0.000000           0        25         1 close
      0.00    0.000000           0         9         6 stat
      0.00    0.000000           0        12           fstat
      0.00    0.000000           0        19           mmap
      0.00    0.000000           0        12           mprotect
      0.00    0.000000           0         5           munmap
      0.00    0.000000           0         9           brk
      0.00    0.000000           0         7           rt_sigaction
      0.00    0.000000           0         2           rt_sigreturn
      0.00    0.000000           0         9         9 access
      0.00    0.000000           0         1           pipe
      0.00    0.000000           0         3           dup2
      0.00    0.000000           0         1           getpid
      0.00    0.000000           0         2           clone
      0.00    0.000000           0         3           execve
      0.00    0.000000           0         4           fcntl
      0.00    0.000000           0         1           getuid
      0.00    0.000000           0         1           getgid
      0.00    0.000000           0         2           geteuid
      0.00    0.000000           0         1           getegid
      0.00    0.000000           0         1           getppid
      0.00    0.000000           0         3           arch_prctl
      0.00    0.000000           0         2           fadvise64
      0.00    0.000000           0        11           openat
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.687791                 45932        16 total
    ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    strace -c -f ./bb.sh
    ./bb.sh の内容 ==>  cat in.data | cat >> /dev/null
    ____________________________________________
    strace: Process 4021 attached
    strace: Process 4022 attached
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.656595      328298         2           wait4
      0.00    0.000000           0     22896           read
      0.00    0.000000           0     22889           write
      0.00    0.000000           0        25         1 close
      0.00    0.000000           0         9         6 stat
      0.00    0.000000           0        12           fstat
      0.00    0.000000           0        19           mmap
      0.00    0.000000           0        12           mprotect
      0.00    0.000000           0         5           munmap
      0.00    0.000000           0         9           brk
      0.00    0.000000           0         7           rt_sigaction
      0.00    0.000000           0         2           rt_sigreturn
      0.00    0.000000           0         9         9 access
      0.00    0.000000           0         1           pipe
      0.00    0.000000           0         3           dup2
      0.00    0.000000           0         1           getpid
      0.00    0.000000           0         2           clone
      0.00    0.000000           0         3           execve
      0.00    0.000000           0         4           fcntl
      0.00    0.000000           0         1           getuid
      0.00    0.000000           0         1           getgid
      0.00    0.000000           0         2           geteuid
      0.00    0.000000           0         1           getegid
      0.00    0.000000           0         1           getppid
      0.00    0.000000           0         3           arch_prctl
      0.00    0.000000           0         2           fadvise64
      0.00    0.000000           0        11           openat
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.656595                 45932        16 total
    
[/code]


CC BY-SA 4.0
2020-06-25T04:00:20.807
67979
2020-06-26T06:40:56.990
2020-06-26T06:40:56.990
35558
35558
67962
answer


">" と ">>" でシステムコールに違いがあるのは不可解です。  
"cat hoge | pv > /dev/null" は、シェルが /dev/null を open する時に  
O_APPEND を付けるかどうかの違いしかなく、pv の処理には影響しないはずです。  
実際手元の CentOS6.9 で試してみた限りでは、その違いしか見られませんでした。


CC BY-SA 4.0
2020-06-25T11:46:27.173
67990
2020-06-25T11:46:27.173
40823
67962
answer


pv プロセスの stdin と stdout に対して、`read(2)` も `write(2)` も呼び出されていません。

[code]

    $ lsb_release -ir
    Distributor ID: Ubuntu
    Release:    20.04
    $ uname -srm
    Linux 5.4.0-37-generic x86_64
    $ pv --version
    pv 1.6.6 - Copyright 2015 Andrew Wood <andrew.wood@ivarch.com>
    
    $ cat /dev/urandom | pv -rf -t -i 2 >/dev/null 2>output & strace -p $! -e read,write
                   :
    write(2, "0:00:02 [31.7MiB/s]", 19)     = 19
    write(2, "\r", 1)                       = 1
    write(2, "0:00:04 [33.0MiB/s]", 19)     = 19
    write(2, "\r", 1)                       = 1
                   :
    
[/code]

`read(2)` や `write(2)` に変わる何か(system call)が使われているだろうと推測して、以下を実行してみた所、

[code]

    $ cat /dev/urandom | pv -rf -t -i 2 >/dev/null 2>output & strace -p $! | grep -E '\([01],'
                   :
    select(1, [0], [], NULL, {tv_sec=0, tv_usec=90000}) = 1 (in [0], left {tv_sec=0, tv_usec=86340})
    splice(0, NULL, 1, NULL, 131072, SPLICE_F_MORE) = 131072
                   :
    
[/code]

`splice(2)` が使われている事が判りました。

**man splice(2)**

> splice() moves data between two file descriptors **without copying** between
> kernel address space and user address space.

pv には `splice(2)` を利用しないオプションスイッチがあります。

**man pv(1)**

> -C, --no-splice  
>  Never use splice(2), even if it would normally be possible. **The splice(2)
> system call is a more efficient way of transferring data from or to a pipe
> than regular read(2) and write(2)** , but means that the transfer buffer may
> not be used. This prevents -A and -T from working, so if you want to use -A
> or -T then you will need to use -C, at the cost of a small loss in transfer
> efficiency. (This option has no effect on systems where splice(2) is
> unavailable).
[code]

    $ cat /dev/urandom | pv -C -rf -t -i 2 >/dev/null 2>output & strace -p $! -e read,write
                   :
    read(0, ...
    write(1, ...
    read(0, ...
    write(1, ...
                   :
    
[/code]


CC BY-SA 4.0
2020-06-26T14:54:02.927
68038
2020-06-26T15:05:48.627
2020-06-26T15:05:48.627
67962
answer