のコメントとして、makefileの「| true」がユーザーcjmが書いた「|| true」と同じ効果がある理由について混乱しています。
避けるべきもう一つの理由| trueは、コマンドがパイプバッファーをいっぱいにするのに十分な出力を生成した場合、trueを待ってブロックすることです。
パイプバッファーのサイズを調べる方法はありますか?
のコメントとして、makefileの「| true」がユーザーcjmが書いた「|| true」と同じ効果がある理由について混乱しています。
避けるべきもう一つの理由| trueは、コマンドがパイプバッファーをいっぱいにするのに十分な出力を生成した場合、trueを待ってブロックすることです。
パイプバッファーのサイズを調べる方法はありますか?
回答:
パイプバッファーの容量はシステムによって異なります(同じシステムでも異なる場合があります)。パイプの容量を単に検索するための、迅速で簡単なクロスプラットフォームの方法があるかどうかはわかりません。
たとえば、Mac OS Xはデフォルトで16384バイトの容量を使用しますが、パイプに大量の書き込みが行われる場合は65336バイトの容量に切り替えることができ、カーネルメモリが多すぎる場合は単一のシステムページの容量に切り替えますパイプバッファによって使用されている(参照xnu/bsd/sys/pipe.h
、そしてxnu/bsd/kern/sys_pipe.c
、これらは、FreeBSDからのものであるので、同じ動作があまりにも、そこに起こり得ます)。
1つのLinux pipe(7) manページには、Linux 2.6.11以降のパイプ容量は65536バイトで、その前の単一のシステムページ(たとえば(32ビット)x86システムでは4096バイト)であると書かれています。コード(include/linux/pipe_fs_i.h
、およびfs/pipe.c
)は16システムページ(つまり、システムページが4 KiBの場合は64 KiB)を使用するようですが、各パイプのバッファーはパイプのfcntlで調整できます(最大容量はデフォルトで1048576です)バイトですが、/proc/sys/fs/pipe-max-size
))で変更できます。
ここでは少しあるbashの / Perlの私のシステム上のパイプ能力をテストするために使用される組み合わせは:
#!/bin/bash
test $# -ge 1 || { echo "usage: $0 write-size [wait-time]"; exit 1; }
test $# -ge 2 || set -- "$@" 1
bytes_written=$(
{
exec 3>&1
{
perl -e '
$size = $ARGV[0];
$block = q(a) x $size;
$num_written = 0;
sub report { print STDERR $num_written * $size, qq(\n); }
report; while (defined syswrite STDOUT, $block) {
$num_written++; report;
}
' "$1" 2>&3
} | (sleep "$2"; exec 0<&-);
} | tail -1
)
printf "write size: %10d; bytes successfully before error: %d\n" \
"$1" "$bytes_written"
Mac OS X 10.6.7システムでさまざまな書き込みサイズで実行したことがわかりました(16KiBを超える書き込みの変更に注意してください)。
% /bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 16384
write size: 2; bytes successfully before error: 16384
write size: 4; bytes successfully before error: 16384
write size: 8; bytes successfully before error: 16384
write size: 16; bytes successfully before error: 16384
write size: 32; bytes successfully before error: 16384
write size: 64; bytes successfully before error: 16384
write size: 128; bytes successfully before error: 16384
write size: 256; bytes successfully before error: 16384
write size: 512; bytes successfully before error: 16384
write size: 1024; bytes successfully before error: 16384
write size: 2048; bytes successfully before error: 16384
write size: 4096; bytes successfully before error: 16384
write size: 8192; bytes successfully before error: 16384
write size: 16384; bytes successfully before error: 16384
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
Linux 3.19の同じスクリプト:
/bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 65536
write size: 2; bytes successfully before error: 65536
write size: 4; bytes successfully before error: 65536
write size: 8; bytes successfully before error: 65536
write size: 16; bytes successfully before error: 65536
write size: 32; bytes successfully before error: 65536
write size: 64; bytes successfully before error: 65536
write size: 128; bytes successfully before error: 65536
write size: 256; bytes successfully before error: 65536
write size: 512; bytes successfully before error: 65536
write size: 1024; bytes successfully before error: 65536
write size: 2048; bytes successfully before error: 65536
write size: 4096; bytes successfully before error: 65536
write size: 8192; bytes successfully before error: 65536
write size: 16384; bytes successfully before error: 65536
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
注:PIPE_BUF
Cヘッダーファイルで定義されている値(およびのpathconf値_PC_PIPE_BUF
)は、パイプの容量ではなく、アトミックに書き込むことができる最大バイト数を指定します(POSIX write(2)を参照)。
からの引用include/linux/pipe_fs_i.h
:
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
fcntl()
Linux について言及してくれてありがとう。組み込みのパイプには十分な大きさのバッファーがないと思ったので、ユーザー空間のバッファープログラムを探していました。CAP_SYS_RESOURCEを持っているか、rootが最大パイプサイズを拡大することを望んでいる場合、それらが実行されることがわかります。私が欲しいものは特定のLinuxコンピューター(私の)でのみ実行されるので、これは問題になりません。
var=…
)です。また、いくつかの(あまり一般的ではない)リダイレクト(および)を使用します。$(…)
{…}
(…)
0<&-
3>&1
exec 0<&-
)で閉じられたためです。最終レポートが収集され(tail -1
)、書き込みサイズとともに印刷されます。
このシェルラインはパイプバッファサイズも表示できます:
M=0; while true; do dd if=/dev/zero bs=1k count=1 2>/dev/null; \
M=$(($M+1)); echo -en "\r$M KB" 1>&2; done | sleep 999
(バッファーがいっぱいになるまでブロックされたパイプに1kチャンクを送信)...一部のテスト出力:
64K (intel-debian), 32K (aix-ppc), 64K (jslinux bellard.org) ...Ctrl+C.
printfを使用した最短bash-one-liner:
M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
(dd if=/dev/zero bs=1 | sleep 999) &
その後、第二を待ってkillall -SIGUSR1 dd
います65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
)、あなたのソリューションと同じですが、1つのバイトの解像度で-
dd
コマンドは16 KiBでブロックします。Fedora 23/25 x86-64では、64 KiBでブロックします。
dd if=/dev/zero bs=1 | sleep 999
は、フォアグラウンドで実行し、1秒間待ってからを押すことができます^C
。LinuxおよびBSD / macOSでワンライナーが必要な場合(を使用するよりも堅牢killall
):dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
シェルコマンドのみを使用して、実際のパイプバッファー容量を調べるための代替手段を次に示します。
# get pipe buffer size using Bash
yes produce_this_string_as_output | tee >(sleep 1) | wc -c
# portable version
( (sleep 1; exec yes produce_this_string_as_output) & echo $! ) |
(pid=$(head -1); sleep 2; kill "$pid"; wc -c </dev/stdin)
# get buffer size of named pipe
sh -c '
rm -f fifo
mkfifo fifo
yes produce_this_string_as_output | tee fifo | wc -c &
exec 3<&- 3<fifo
sleep 1
exec 3<&-
rm -f fifo
'
# Mac OS X
#getconf PIPE_BUF /
#open -e /usr/include/limits.h /usr/include/sys/pipe.h
# PIPE_SIZE
# BIG_PIPE_SIZE
# SMALL_PIPE_SIZE
# PIPE_MINDIRECT
getconf PIPE_BUF /
印刷物5120
と一致するulimit -a | grep pipe
出力をしかし16個のKiBの後に一致していないdd .. | sleep ...
ブロックを。
yes
73728
dd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
これは、Ubuntu 12.04、YMMVでの迅速で汚いハックです。
cat >pipesize.c
#include <unistd.h>
#include <errno.h>
#include </usr/include/linux/fcntl.h>
#include <stdio.h>
void main( int argc, char *argv[] ){
int fd ;
long pipesize ;
if( argc>1 ){
// if command line arg, associate a file descriptor with it
fprintf( stderr, "sizing %s ... ", argv[1] );
fd = open( argv[1], O_RDONLY|O_NONBLOCK );
}else{
// else use STDIN as the file descriptor
fprintf( stderr, "sizing STDIN ... " );
fd = 0 ;
}
fprintf( stderr, "%ld bytes\n", (long)fcntl( fd, F_GETPIPE_SZ ));
if( errno )fprintf( stderr, "Uh oh, errno is %d\n", errno );
if( fd )close( fd );
}
gcc -o pipesize pipesize.c
mkfifo /tmp/foo
./pipesize /tmp/foo
>sizing /tmp/foo ... 65536 bytes
date | ./pipesize
>sizing STDIN ... 65536 bytes
$ ulimit -a | grep pipe
pipe size (512 bytes, -p) 8
したがって、Linuxボックスでは、デフォルトで8 * 512 = 4096バイトのパイプがあります。
Solarisおよび他の多くのシステムには、同様のulimit機能があります。
(512 bytes, -p) 8
、Fedora 23/25および512 bytes, -p) 10
Solaris 10で出力されます。これらの値は、実験的にブロッキングで得られたバッファーサイズと一致しませんdd
。