Ir para o conteúdo
ou

# Performance goes up like a rocket with BC

11 de Junho de 2011, 0:00 | Ninguém está seguindo este artigo ainda. 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 |
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
``` Seq1-A 4m55.433s Seq1-B 4m45.620s Seq1-C 0m3.571s Seq1-D 0m3.241s

### 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
``` Seq2-A 0m3.124s Seq2-B 0m2.953s Seq2-C 0m0.073s Seq2-D 0m0.070s

### 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! :-)

Tags deste artigo: bash bc performance
Fonte: Aurélio A. Heckert

### 0sem comentários ainda

Enviar um comentário

Os campos são obrigatórios.

Se você é um usuário registrado, pode se identificar e ser reconhecido automaticamente.