I had presumed but i never had thought how much the performance can grow when giving some logic from BASH to BC. Ok... We all know, BASH is some of the slowest languages in the world, but BASH scripts that hard work with math can be as fast as other languages if we let some logic to the BC, an arbitrary precision numeric processing language.
When i started to work with the XPM Image script (my new pet project) i realized that BASH is more slow then i think, but i also realized that i can give to BC much more then only some simple math expressions to compute. In BC i can define variables, set flux control, functions... Well thats a real programming language and i'm underusing it.
In a small test i had the confirmation: BC with inside loops is much faster than BASH loops with BC inside. The question is: "How much?" ... Taking advantage i decide to test how much the verbose hinders the performance. So i did this change on the pixel matrix generator loop:
echo 'A: Loops in bash + With verbose code' time ( helix='|/-\' for y in $( seq 0 $(($h-1)) ); do echo -ne "Line $y ${helix:$(($y%4)):1} \r" >&2 echo -n '"' for x in $( seq 0 $(($w-1)) ); do echo " $bc_pal_func $bc_round_func define f(x,y,w,h) { $func } # calc the position on the pallete for the current pixel: p = round( 255 * f($x,$y,$w,$h) ); num_to_pal(p)" | bc -l done echo -n '"' test $y -lt $(($h-1)) && echo ',' done > /tmp/pix-matrix-1 echo "Done. " >&2 ) echo 'B: Loops in bash + Without verbose code' time ( for y in $( seq 0 $(($h-1)) ); do echo -n '"' for x in $( seq 0 $(($w-1)) ); do echo " $bc_pal_func $bc_round_func define f(x,y,w,h) { $func } # calc the position on the pallete for the current pixel: p = round( 255 * f($x,$y,$w,$h) ); num_to_pal(p)" | bc -l done echo -n '"' test $y -lt $(($h-1)) && echo ',' done > /tmp/pix-matrix-2 ) echo 'C: Loops in bc + With verbose code' time ( export BC_LINE_LENGTH=$(( $w * 2 + 5 )) echo " $bc_pal_func $bc_round_func define f(x,y,w,h) { $func } helix_pos = 0; define void verbose(line) { print \"Line \",y,\" \" if ( helix_pos == 0 ) print \"|\" \ else if ( helix_pos == 1 ) print \"/\" \ else if ( helix_pos == 2 ) print \"-\" \ else { print \"\\\\\\\\\"; helix_pos = -1; } helix_pos += 1; print \" \\n\"; } for ( y=0; y<$h; y++ ) { verbose(y) print \"\\q\" for ( x=0; x<$w; x++ ) { # calc the position on the pallete for the current pixel: p = round( 255 * f(x,y,$w,$h) ); num_to_pal(p) } print \"\\q\" if ( y < $(($h-1)) ) print \",\" print \"\\n\" }" | bc -l | while read line; do test "${line:0:4}" = "Line" \ && echo -en " $line \r" >&2 \ || echo "$line" done > /tmp/pix-matrix-3 echo "Done. " >&2 ) echo 'D: Loops in bc + Without verbose code' time ( export BC_LINE_LENGTH=$(( $w * 2 + 5 )) echo " $bc_pal_func $bc_round_func define f(x,y,w,h) { $func } for ( y=0; y<$h; y++ ) { print \"\\q\" for ( x=0; x<$w; x++ ) { # calc the position on the pallete for the current pixel: p = round( 255 * f(x,y,$w,$h) ); num_to_pal(p) } print \"\\q\" if ( y < $(($h-1)) ) print \",\\n\" }" | bc -l > /tmp/pix-matrix-4 )
As you see, there is 4 matrix generators testing loops inside x outside BC, and with x without verbose code. Each block will be tested with the time
command. Then i run it to generates two images one with 200x200 pixels and other with 20x20 pixels. See the results:
Sequence 1 - run ./image 200 200
A: Loops in bash + With verbose code Done. real 4m55.433s user 4m36.953s sys 0m59.660s B: Loops in bash + Without verbose code real 4m45.620s user 4m38.969s sys 0m57.516s C: Loops in bc + With verbose code Done. real 0m3.571s user 0m3.172s sys 0m0.148s D: Loops in bc + Without verbose code real 0m3.241s user 0m2.896s sys 0m0.212s
Sequence 2 - run ./image 20 20
A: Loops in bash + With verbose code Done. real 0m3.124s user 0m2.822s sys 0m0.626s B: Loops in bash + Without verbose code real 0m2.953s user 0m2.868s sys 0m0.576s C: Loops in bc + With verbose code Done. real 0m0.073s user 0m0.044s sys 0m0.004s D: Loops in bc + Without verbose code real 0m0.070s user 0m0.032s sys 0m0.008s
What that means?
With simple calculus we can see that:
Comparing sequence 1 (image 200 200)
Seq1-A x Seq1-B:
Loops in bash, without verbose code is 3.32% faster then with verbose code
Seq1-C x Seq1-D:
Loops in bc, without verbose code is 9.24% faster then with verbose code
Seq1-A x Seq1-C:
Loops in bc runs 82.73 times faster than in bash
Comparing sequence 2 (image 20 20)
Seq2-A x Seq2-B:
Loops in bash, without verbose code is 5.41% faster then with verbose code
Seq2-C x Seq2-D:
Loops in bc, without verbose code is 4.11% faster then with verbose code
Seq2-A x Seq2-C:
Loops in bc runs 42.79 times faster than in bash
The bigest thing is: I must give all math related logic to BC and something more when it is possible. This praxis is not only times faster it is computationally less expensive, by that the [BASH code time] / [BC code time] grows when we try to generate the bigger image
The verbosity affects the performance, that makes a 200x200 image only 330 milliseconds slow, inside the BC code. The user can't feel that. Nice! :-)
Interested? Visit the XPM Image website.
0sem comentários ainda
Por favor digite as duas palavras abaixo