it-swarm-tr.com

Boru tamponu ne kadar büyük?

Bir makefile "| true" neden "|| true" ile aynı etkiye sahip olduğu konusunda kafam karıştı user cjm yazdı:

Kaçınılması gereken başka bir neden | true komutu komutun tampon arabelleğini doldurmak için yeterli çıktı üretmesi durumunda, true değerinin okunmasını beklemesini engelleyeceğidir.

Boru tamponunun boyutunun ne olduğunu bulmanın bir yolu var mı?

150
Kit Sunde

Bir boru tamponunun kapasitesi sistemlere göre değişir (ve aynı sistemde bile değişebilir). Bir borunun kapasitesini aramak için hızlı, kolay ve çapraz platform yolu olduğundan emin değilim.

Örneğin Mac OS X, varsayılan olarak 16384 bayt kapasite kullanır, ancak boruya büyük yazma yapılırsa 65336 bayt kapasiteye geçebilir veya çok fazla çekirdek belleği zaten varsa tek bir sistem sayfasının kapasitesine geçebilir boru tamponları tarafından kullanılıyor (bkz. xnu/bsd/sys/pipe.h ve xnu/bsd/kern/sys_pipe.c ; bunlar FreeBSD'den geldiği için aynı davranış orada da olabilir).

Bir Linux boru (7) kılavuz sayfası , Linux 2.6.11'den bu yana boru kapasitesinin 65536 bayt ve tek bir sistem sayfası olduğunu söylüyor bundan önce (örn. (32 bit) x86 sistemlerde 4096 bayt). Kod ( include/linux/pipe_fs_i.h ve fs/pipe.c ) 16 sistem sayfası kullanıyor gibi görünüyor (örn. bir sistem sayfası 4 KiB ise 64 KiB), ancak her boru için tampon bir fcntl boru üzerinde (varsayılan değer 1048576 bayt olan ancak /proc/sys/fs/pipe-max-size)).


İşte test etmek için kullandığım küçük bir bash / Perl kombinasyonu sistemimdeki boru kapasitesi:

#!/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"

İşte Mac OS X 10.6.7 sisteminde çeşitli yazma boyutlarıyla çalıştırırken bulduğum şey (16KiB'den büyük yazma değişiklikleri için not edin):

% /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'daki aynı komut dosyası:

/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

Not: PIPE_BUF değeri C başlık dosyalarında (ve pathconf için _PC_PIPE_BUF), boruların kapasitesini değil, atomik olarak yazılabilecek maksimum bayt sayısını belirtir (bkz POSIX write (2) ).

Alıntı yapmak 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

bu Shell-hattı boru tampon boyutunu da gösterebilir:

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

(arabellek dolana kadar tıkanmış boruya 1k parça gönderme) ... bazı test çıktıları:

64K (intel-debian), 32K (aix-ppc), 64K (jslinux bellard.org)      ...Ctrl+C.

printf kullanan en kısa bash-one-liner:

M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
36
Asain Kujovic

Yalnızca Shell komutlarını kullanarak gerçek boru tampon kapasitesini keşfetmek için bazı alternatifler şunlardır:

# 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

Bu Ubuntu 12.04, YMMV'de hızlı ve kirli bir saldırı

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'teki değere ihtiyacınız varsa, burada basit bir yöntem vardır (dd için çağrı yapabilirsiniz):

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 kutumda varsayılan olarak 8 * 512 = 4096 baytlık borular var.

Solaris ve diğer birçok sistem benzer bir ulimit fonksiyonuna sahiptir.

0
Sam Watkins