in reply to BitStream revisited

I would suggest that you let Perl and stdio take care of buffering reads. It is already well-tested and fast. You should consider using vec to manipulate the bitstrings especially if you are reading large amounts.

The BitStream module would need to figure out how many bytes to read with read(). If the number of bits read is not a integral number of bytes, then it needs to save the leftover bits. The leftover bits would be used for the next read.

Replies are listed 'Best First'.
Re: Re: BitStream revisited
by tachyon (Chancellor) on Dec 31, 2003 at 02:46 UTC

    Please read Re: Performance Question and the associated thread. Optimizing (minimizing) the number of disk accesses via read is paramount to speed. There are simple reasons for this ie nanosecond vs milisecond retreival times for memory cf disk and it is trivial to test and prove.

    cheers

    tachyon

      read already uses buffered input, and each call to it does not make a system call.
      #!/usr/bin/perl while (read(STDIN,$buf,$ENV{BLOCKSIZE})) { ; }
      produces:
      $ BLOCKSIZE=1 strace -e read -c perl /tmp/t6 <zelda4rom.zip 
      Called read 26968 times.
      % time     seconds  usecs/call     calls    errors syscall
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.002888         160        18           read
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.002888                    18           total
      
      $ BLOCKSIZE=1024 strace -e read -c perl /tmp/t6 <zelda4rom.zip 
      Called read 27 times.
      % time     seconds  usecs/call     calls    errors syscall
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.000370          19        19           read
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.000370                    19           total
      
      $ BLOCKSIZE=4096 strace -e read -c perl /tmp/t6 <zelda4rom.zip 
      Called read 7 times.
      % time     seconds  usecs/call     calls    errors syscall
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.000315          17        19           read
      ------ ----------- ----------- --------- --------- ----------------
      100.00    0.000315                    19           total
      
      
      

        As noted -> at the end of the day you want throughput. Lots of small reads are much slower than several larger ones. You can see the progression - bigger read, faster throughput, but only up to a certain point.

        [root@devel3 root]# cat reader.pl #!/usr/bin/perl open $fh, '/root/big.file' or die $!; 1 while read( $fh, $buf, $ENV{BLOCK_SIZE} ); close $fh; [root@devel3 root]# ll big.file -rw-r--r-- 1 root root 100000000 Dec 31 04:31 big.file [root@devel3 root]# BLOCK_SIZE=8 strace -e read -c perl /root/reader.p +l % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.166282 7 24426 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.166282 24426 total [root@devel3 root]# BLOCK_SIZE=64 strace -e read -c perl /root/reader. +pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.182985 7 24426 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.182985 24426 total [root@devel3 root]# BLOCK_SIZE=1024 strace -e read -c perl /root/reade +r.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.170449 7 24427 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.170449 24427 total [root@devel3 root]# BLOCK_SIZE=2048 strace -e read -c perl /root/reade +r.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.169480 7 24427 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.169480 24427 total [root@devel3 root]# BLOCK_SIZE=4096 strace -e read -c perl /root/reade +r.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.171735 7 24427 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.171735 24427 total [root@devel3 root]# BLOCK_SIZE=8192 strace -e read -c perl /root/reade +r.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.106189 9 12220 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.106189 12220 total [root@devel3 root]# BLOCK_SIZE=16384 strace -e read -c perl /root/read +er.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.094355 15 6116 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.094355 6116 total [root@devel3 root]# BLOCK_SIZE=32768 strace -e read -c perl /root/read +er.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.081012 26 3064 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.081012 3064 total [root@devel3 root]# BLOCK_SIZE=65536 strace -e read -c perl /root/read +er.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.078593 51 1538 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.078593 1538 total [root@devel3 root]# BLOCK_SIZE=131072 strace -e read -c perl /root/rea +der.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.099163 128 775 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.099163 775 total [root@devel3 root]# BLOCK_SIZE=262144 strace -e read -c perl /root/rea +der.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.141184 358 394 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.141184 394 total [root@devel3 root]# BLOCK_SIZE=524288 strace -e read -c perl /root/rea +der.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.175145 863 203 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.175145 203 total [root@devel3 root]# BLOCK_SIZE=1048576 strace -e read -c perl /root/re +ader.pl % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.175813 1628 108 read ------ ----------- ----------- --------- --------- ---------------- 100.00 0.175813 108 total [root@devel3 root]#

        On this system RAID 5 SCSI you can see that the system buffer size is 4192 bytes. Over this figure you get bigger reads and as you can see the throughput increases. Somewhat suprisingly (given past testing) the optimal point on the system I used is 65K block size and you can see performance drop off after this point. As previously noted in an earlier post you need to test the exact code/OS/system combo to find the sweet spot that optimizes throughput.

        cheers

        tachyon