| 1 | #!/usr/bin/env bash
 | 
| 2 | #
 | 
| 3 | # Test how long it takes to read many files
 | 
| 4 | 
 | 
| 5 | big-stream() {
 | 
| 6 |   cat */*.py 
 | 
| 7 |   # Python messes up here!
 | 
| 8 |   #*/*/*.py
 | 
| 9 | }
 | 
| 10 | 
 | 
| 11 | slow-stream() {
 | 
| 12 |   ### for testing signal handling in loop
 | 
| 13 |   local secs=${1:-1}
 | 
| 14 | 
 | 
| 15 |   while read -r line; do
 | 
| 16 |     sleep $secs
 | 
| 17 |     echo $line
 | 
| 18 |   done
 | 
| 19 | }
 | 
| 20 | 
 | 
| 21 | OSH=_bin/cxx-opt/osh
 | 
| 22 | YSH=_bin/cxx-opt/ysh
 | 
| 23 | 
 | 
| 24 | setup() {
 | 
| 25 |   local n=${1:-1}  # how many copies
 | 
| 26 | 
 | 
| 27 |   for i in $(seq $n); do
 | 
| 28 |     big-stream 
 | 
| 29 |   done > $BIG_FILE
 | 
| 30 | 
 | 
| 31 |   wc -l $BIG_FILE
 | 
| 32 | 
 | 
| 33 |   ninja $OSH $YSH
 | 
| 34 | }
 | 
| 35 | 
 | 
| 36 | py3-count() {
 | 
| 37 |   echo '=== python3'
 | 
| 38 | 
 | 
| 39 |   # Buffered I/O is much faster
 | 
| 40 |   python3 -c '
 | 
| 41 | import sys
 | 
| 42 | i = 0
 | 
| 43 | for line in sys.stdin:
 | 
| 44 |   i += 1
 | 
| 45 | print(i)
 | 
| 46 | '
 | 
| 47 | }
 | 
| 48 | 
 | 
| 49 | awk-count() {
 | 
| 50 |   echo '=== awk'
 | 
| 51 |   awk '{ i += 1 } END { print i } '
 | 
| 52 | }
 | 
| 53 | 
 | 
| 54 | exec-ysh-count() {
 | 
| 55 |   local do_trap=${1:-}
 | 
| 56 | 
 | 
| 57 |   echo '=== ysh'
 | 
| 58 | 
 | 
| 59 |   local code='
 | 
| 60 | var i = 0
 | 
| 61 | for _ in <> {
 | 
| 62 |   setvar i += 1
 | 
| 63 | }
 | 
| 64 | echo $i
 | 
| 65 | '
 | 
| 66 | 
 | 
| 67 |   if test -n "$do_trap"; then
 | 
| 68 |     # Register BEFORE creating pipeline
 | 
| 69 |     #trap usr1-handler USR1
 | 
| 70 |     code="
 | 
| 71 | trap 'echo \[pid \$\$\] usr1' USR1
 | 
| 72 | trap 'echo \[pid \$\$\] exit with status \$?' EXIT
 | 
| 73 | echo \"hi from YSH pid \$\$\"
 | 
| 74 | 
 | 
| 75 | $code
 | 
| 76 | "
 | 
| 77 |   fi
 | 
| 78 | 
 | 
| 79 |   # New buffered read!
 | 
| 80 |   exec $YSH -c "$code"
 | 
| 81 | }
 | 
| 82 | 
 | 
| 83 | usr1-handler() {
 | 
| 84 |   echo "pid $$ got usr1"
 | 
| 85 | }
 | 
| 86 | 
 | 
| 87 | exec-sh-count() {
 | 
| 88 |   local sh=$1
 | 
| 89 |   local do_trap=${2:-}
 | 
| 90 | 
 | 
| 91 |   echo "shell pid = $$"
 | 
| 92 | 
 | 
| 93 |   echo === $sh
 | 
| 94 | 
 | 
| 95 |   local code='
 | 
| 96 | i=0
 | 
| 97 | while read -r line; do
 | 
| 98 |   i=$(( i + 1 ))
 | 
| 99 | done
 | 
| 100 | echo $i
 | 
| 101 | '
 | 
| 102 | 
 | 
| 103 |   if test -n "$do_trap"; then
 | 
| 104 |     # Register BEFORE creating pipeline
 | 
| 105 |     #trap usr1-handler USR1
 | 
| 106 |     code="
 | 
| 107 | trap 'echo \[pid \$\$\] usr1' USR1
 | 
| 108 | trap 'echo \[pid \$\$\] exit with status \$?' EXIT
 | 
| 109 | echo \"hi from $sh pid \$\$\"
 | 
| 110 | 
 | 
| 111 | $code
 | 
| 112 | "
 | 
| 113 |   fi
 | 
| 114 |   #echo "$code"
 | 
| 115 | 
 | 
| 116 |   # need exec here for trap-demo
 | 
| 117 |   exec $sh -c "$code"
 | 
| 118 | }
 | 
| 119 | 
 | 
| 120 | readonly BIG_FILE=_tmp/lines.txt
 | 
| 121 | 
 | 
| 122 | compare() {
 | 
| 123 |   echo '=== wc'
 | 
| 124 |   time wc -l < $BIG_FILE  # warmup
 | 
| 125 |   echo
 | 
| 126 | 
 | 
| 127 |   time py3-count < $BIG_FILE
 | 
| 128 |   echo
 | 
| 129 | 
 | 
| 130 |   time awk-count < $BIG_FILE
 | 
| 131 |   echo
 | 
| 132 | 
 | 
| 133 |   time $0 exec-ysh-count < $BIG_FILE
 | 
| 134 |   echo
 | 
| 135 | 
 | 
| 136 |   for sh in dash bash $OSH; do
 | 
| 137 |     # need $0 because it exec
 | 
| 138 |     time $0 exec-sh-count $sh < $BIG_FILE
 | 
| 139 |     echo
 | 
| 140 |   done
 | 
| 141 | }
 | 
| 142 | 
 | 
| 143 | sh-count-slow-trap() {
 | 
| 144 |   local write_delay=${1:-0.20}
 | 
| 145 |   local kill_delay=${2:-0.07}
 | 
| 146 |   local -a argv=( ${@:2} )
 | 
| 147 | 
 | 
| 148 |   local len=${#argv[@]}
 | 
| 149 |   #echo "len=$len"
 | 
| 150 |   if test $len -eq 0; then
 | 
| 151 |     echo 'argv required'
 | 
| 152 |   fi
 | 
| 153 | 
 | 
| 154 |   local sh=$1
 | 
| 155 | 
 | 
| 156 |   #exec-sh-count bash T & < <(seq 100 | slow-stream)
 | 
| 157 | 
 | 
| 158 |   echo "[pid $$] Spawn stream with write delay $write_delay"
 | 
| 159 | 
 | 
| 160 |   seq 10 | slow-stream $write_delay | "${argv[@]}" &
 | 
| 161 |   local pid=$!
 | 
| 162 | 
 | 
| 163 |   echo "pid of background job = $pid"
 | 
| 164 |   echo 'pstree:'
 | 
| 165 |   pstree -p $pid
 | 
| 166 |   echo
 | 
| 167 | 
 | 
| 168 |   echo "[pid $$] Entering kill loop ($kill_delay secs)"
 | 
| 169 | 
 | 
| 170 |   while true; do
 | 
| 171 |     # wait for USR1 to be registered
 | 
| 172 |     sleep $kill_delay
 | 
| 173 | 
 | 
| 174 |     kill -s USR1 $pid
 | 
| 175 |     local status=$?
 | 
| 176 | 
 | 
| 177 |     echo "[pid $$] kill $pid status: $status"
 | 
| 178 |     if test $status -ne 0; then
 | 
| 179 |       break
 | 
| 180 |     fi
 | 
| 181 | 
 | 
| 182 |   done
 | 
| 183 | 
 | 
| 184 |   time wait
 | 
| 185 |   echo "wait status: $?"
 | 
| 186 | }
 | 
| 187 | 
 | 
| 188 | compare-trap() {
 | 
| 189 |   # dash exits at the first try
 | 
| 190 |   #sh-count-slow-trap dash
 | 
| 191 | 
 | 
| 192 |   # Oh interesting, mksh waits until the main loop!  Different behavior
 | 
| 193 |   #sh-count-slow-trap mksh
 | 
| 194 | 
 | 
| 195 |   #sh-count-slow-trap zsh
 | 
| 196 | 
 | 
| 197 |   #sh-count-slow-trap bash
 | 
| 198 | 
 | 
| 199 |   # OSH behaves like bash/zsh, yay
 | 
| 200 |   sh-count-slow-trap '' '' exec-sh-count _bin/cxx-opt/osh T
 | 
| 201 | 
 | 
| 202 |   #sh-count-slow-trap '' '' exec-ysh-count T
 | 
| 203 | 
 | 
| 204 |   return
 | 
| 205 | 
 | 
| 206 |   for sh in $YSH dash bash $OSH; do
 | 
| 207 |     sh-count-with-trap $sh
 | 
| 208 |     echo
 | 
| 209 |     echo
 | 
| 210 |   done
 | 
| 211 | }
 | 
| 212 | 
 | 
| 213 | "$@"
 | 
| 214 | 
 |