it-swarm-ko.tech

파이프 버퍼는 얼마나 큽니까?

의견으로 makefile의 "| true"가 "|| true"와 동일한 효과를 갖는 이유에 대해 혼동됩니다. 사용자 cjm 쓴 :

피해야 할 또 다른 이유 | true는 명령이 파이프 버퍼를 채우기에 충분한 출력을 생성하면 true를 읽기 위해 대기하는 것을 차단한다는 것입니다.

파이프 버퍼의 크기를 알아내는 방법이 있습니까?

150
Kit Sunde

파이프 버퍼의 용량은 시스템마다 다르며 심지어 동일한 시스템에서도 달라질 수 있습니다. 파이프의 용량을 조회하는 빠르고 쉽고 크로스 플랫폼 방법이 있는지 잘 모르겠습니다.

예를 들어, Mac OS X은 기본적으로 16384 바이트의 용량을 사용하지만 파이프에 큰 쓰기를 수행하는 경우 65336 바이트 용량으로 전환하거나 너무 많은 커널 메모리가 이미있는 경우 단일 시스템 페이지의 용량으로 전환 할 수 있습니다 파이프 버퍼에서 사용됨 ( xnu/bsd/sys/pipe.hxnu/bsd/kern/sys_pipe.c ; FreeBSD에서 온 것이기 때문에 동일한 동작이 발생할 수도 있습니다. ).

한 Linux pipe (7) 맨 페이지 파이프 용량은 Linux 2.6.11 이후 65536 바이트이고 그 이전의 단일 시스템 페이지 (예 : 4096 바이트 ( 32 비트) x86 시스템). 코드 ( include/linux/pipe_fs_i.hfs/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 -- "[email protected]" 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

참고 : C 헤더 파일에 정의 된 PIPE_BUF 값 (및 _PC_PIPE_BUFpathconf 값은 파이프 용량을 지정하지 않지만 최대 값을 지정합니다. 원자 적으로 쓸 수있는 바이트 수 ( 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.  */
147
Chris Johnsen

이 쉘 라인은 파이프 버퍼 크기도 표시 할 수 있습니다.

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
36
Asain Kujovic

다음은 Shell 명령 만 사용하여 실제 파이프 버퍼 용량을 탐색 할 수있는 몇 가지 대안입니다.

# 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
8
chan

우분투 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
6
Jeff

Python> = 3.3의 값이 필요한 경우 간단한 방법이 있습니다 (dd를 호출 할 수 있다고 가정).

from subprocess import Popen, PIPE, TimeoutExpired
p = Popen(["dd", "if=/dev/zero", "bs=1"], stdin=PIPE, stdout=PIPE)
try: 
    p.wait(timeout=1)
except TimeoutExpired: 
    p.kill()
    print(len(p.stdout.read()))
1
unhammer
$ ulimit -a | grep pipe
pipe size            (512 bytes, -p) 8

따라서 Linux 상자에는 기본적으로 8 * 512 = 4096 바이트 파이프가 있습니다.

Solaris 및 기타 여러 시스템에는 유사한 ulimit 기능이 있습니다.

0
Sam Watkins