OILS / demo / sparse-array.sh View on Github | oils.pub

353 lines, 265 significant
1#!/usr/bin/env bash
2#
3# Test sparse array
4#
5# Relevant files:
6#
7# test/ble-idioms.test.sh
8#
9# core/shell.py defines these functions:
10# _a2sp
11# _opsp
12# builtin/func_misc.py is where they are implemented
13#
14# core/value.asdl defines value.{InternalStringArray,BashArray}
15#
16# _gen/core/value.asdl.* - generated from value.asdl
17#
18# _gen/bin/oils_for_unix.mycpp.cc has the translation of
19
20#
21# Usage:
22# demo/sparse-array.sh <function name>
23
24TIMEFORMAT='%U'
25
26set -o nounset
27set -o pipefail
28set -o errexit
29
30my-time() {
31 local tmp=/tmp/sparse-array
32 { time "$@"; } 2> $tmp
33 echo "$(cat $tmp) seconds"
34}
35
36compare-x() {
37 local x=$1
38
39 local osh=_bin/cxx-opt/osh
40 local osh_souffle=_bin/cxx-opt+souffle/osh
41 ninja $osh $osh_souffle
42
43 # Souffle build is sometimes slightly faster
44 #local shells=(bash $osh $osh_souffle)
45
46 local shells=(bash $osh)
47
48 if false; then
49 echo ===
50 echo $osh SparseArray demo
51 echo
52 my-time sparse-$x $osh
53 fi
54
55 for sh in ${shells[@]}; do
56 echo ===
57 echo $sh
58 echo
59 my-time $sh $0 $x
60 done
61}
62
63compare-sum-shift() {
64 compare-x sum-shift
65}
66
67compare-append-sparse() {
68 compare-x append-sparse
69}
70
71compare-append-dense() {
72 compare-x append-dense
73}
74
75#
76# Workloads
77#
78
79sum-shift() {
80 local n=${1:-1000}
81
82 # Populate array 0 .. n-1
83 a=()
84 for (( i = 0; i < n; ++i )); do
85 a+=( $i )
86 #a+=( 1 )
87 done
88 #echo "${a[@]}"
89
90 # Quadratic loop: sum all numbers, shift by 1
91 local sum=0
92 while true; do
93 local len=${#a[@]}
94 if test $len -eq 0; then
95 break
96 fi
97
98 for (( i = 0; i < len; ++i )); do
99 sum=$(( sum + ${a[i]} ))
100 done
101
102 #echo sum=$sum
103
104 # Shift
105 a=( ${a[@]:1} )
106 done
107
108 echo sum=$sum
109}
110
111sparse-sum-shift() {
112 local osh=$1
113
114 $osh <<'EOF'
115shopt --set ysh:upgrade
116
117f() {
118 local n=${1:-1000}
119
120 a=()
121 var sp = _a2sp(a) # empty sparse array
122
123 # Populate BashArray 0 .. n-1
124 for (( i = 0; i < n; ++i )); do
125 to_append=( $i )
126 call _opsp(sp, 'append', to_append)
127 done
128
129 #echo "${a[@]}"
130 echo "length $[_opsp(sp, 'len')]"
131 #echo SUBST @[_opsp(sp, 'subst')]
132 #echo KEYS @[_opsp(sp, 'keys')]
133
134 var sum = 0
135
136 while (true) {
137 var length = _opsp(sp, 'len')
138 if (length === 0) {
139 break
140 }
141
142 #echo ZERO $sum $[_opsp(sp, 'get', 0)]
143 #echo ONE $sum $[_opsp(sp, 'get', 1)]
144 for i in (0 ..< length) {
145 setvar sum += _opsp(sp, 'get', i)
146 }
147
148 #echo sum=$sum
149
150 # Slice to InternalStringArray
151 var a = _opsp(sp, 'slice', 1, length)
152
153 # Convert back - is this slow?
154 setvar sp = _a2sp(a)
155 }
156
157 echo sum=$sum
158}
159
160f
161
162EOF
163}
164
165append-sparse() {
166 local n=${1:-24} # up to 2^n
167 local m=${2:-2000}
168
169 to_append=( $(seq $m) ) # split words
170
171 a=()
172 for (( i = 0; i < n; ++i )) {
173 a[$(( 1 << i ))]=$i
174 a+=( ${to_append[@]} )
175 }
176 #echo ${a[@]}
177 #echo ${!a[@]}
178 echo ${#a[@]}
179}
180
181sparse-append-sparse() {
182 local osh=${1:-_bin/cxx-opt/osh}
183 local n=${2:-24}
184 local m=${3:-2000}
185
186 NUM_ITERS=$n TO_APPEND=$m $osh <<'EOF'
187n=$NUM_ITERS
188m=$TO_APPEND
189to_append=( $(seq $m) ) # split words before ysh:upgrade
190
191
192shopt --set ysh:upgrade
193
194f() {
195 a=()
196 var sp = _a2sp(a)
197
198 for (( i = 0; i < n; ++i )) {
199 call _opsp(sp, 'set', 1 << i, str(i))
200 call _opsp(sp, 'append', to_append)
201
202 #time call _opsp(sp, 'append', to_append)
203 #echo $[_opsp(sp, 'len')]
204 #echo
205 }
206 echo $[_opsp(sp, 'len')]
207 #echo @[_opsp(sp, 'subst')]
208 #echo @[_opsp(sp, 'keys')]
209}
210
211f
212EOF
213}
214
215append-dense() {
216 local n=${1:-24} # up to 2^n
217 local m=${2:-2000}
218
219 to_append=( $(seq $m) ) # split words
220
221 a=()
222 for (( i = 0; i < n; ++i )) {
223 a+=( ${to_append[@]} )
224 }
225 #echo ${a[@]}
226 #echo ${!a[@]}
227 echo ${#a[@]}
228}
229
230sparse-append-dense() {
231 local osh=${1:-_bin/cxx-opt/osh}
232 local n=${2:-24}
233 local m=${3:-2000}
234
235 NUM_ITERS=$n TO_APPEND=$m $osh <<'EOF'
236n=$NUM_ITERS
237m=$TO_APPEND
238to_append=( $(seq $m) ) # split words before ysh:upgrade
239
240shopt --set ysh:upgrade
241
242f() {
243 a=()
244 var sp = _a2sp(a)
245
246 for (( i = 0; i < n; ++i )) {
247 #call _opsp(sp, 'set', 1 << i, str(i))
248 call _opsp(sp, 'append', to_append)
249
250 #time call _opsp(sp, 'append', to_append)
251 #echo $[_opsp(sp, 'len')]
252 #echo
253 }
254 echo $[_opsp(sp, 'len')]
255 #echo @[_opsp(sp, 'subst')]
256 #echo @[_opsp(sp, 'keys')]
257}
258
259f
260EOF
261}
262
263demo() {
264 # Compiles faster
265 #local osh=_bin/cxx-asan/osh
266
267 local osh=_bin/cxx-opt/osh
268
269 ninja $osh
270
271 $osh <<'EOF'
272
273# Create regular bash array
274
275a=( {1..100} )
276a[1000]='sparse'
277echo $[type(a)]
278
279# Time O(n^2) slicing in a loop
280
281time while true; do
282 # Convert it to the Dict[BigInt, str] representation
283 var sp = _a2sp(a)
284 #echo $[type(sp)]
285
286 var len = _opsp(sp, 'len')
287 #echo "sparse length $len"
288
289 setvar a = _opsp(sp, 'slice', 1, 2000)
290 #echo "array length ${#a[@]}"
291 echo "array ${a[@]}"
292
293 if test ${#a[@]} -eq 0; then
294 break
295 fi
296done
297EOF
298
299 return
300
301 # Copied from spec/ble-idioms.test.sh
302 $osh <<'EOF'
303
304a=( foo {25..27} bar )
305
306a[10]='sparse'
307
308var sp = _a2sp(a)
309echo $[type(sp)]
310
311echo len: $[_opsp(sp, 'len')]
312
313#echo $[len(sp)]
314
315shopt -s ysh:upgrade
316
317echo subst: @[_opsp(sp, 'subst')]
318echo keys: @[_opsp(sp, 'keys')]
319
320echo slice: @[_opsp(sp, 'slice', 2, 5)]
321
322call _opsp(sp, 'set', 0, 'set0')
323
324echo get0: $[_opsp(sp, 'get', 0)]
325echo get1: $[_opsp(sp, 'get', 1)]
326
327to_append=(x y)
328call _opsp(sp, 'append', to_append)
329echo subst: @[_opsp(sp, 'subst')]
330echo keys: @[_opsp(sp, 'keys')]
331
332echo ---
333
334# Sparse
335var d = {
336 '1': 'a',
337 '10': 'b',
338 '100': 'c',
339 '1000': 'd',
340 '10000': 'e',
341 '100000': 'f',
342}
343
344var sp2 = _d2sp(d)
345
346echo len: $[_opsp(sp2, 'len')]
347echo subst: @[_opsp(sp2, 'subst')]
348
349EOF
350
351}
352
353"$@"