May 2006
In the previous texts of this series, building four key software components was done to see if it would yield any results. These were:
The kernel was covered again in the second part of the series. In this last installment, some small tests and the results.
The Perl and GCC test were relatively simple. A small program was devised for each that does the following:
reads in a loop count calls a recursive division function that divides two random integers until the loop equals zero
rdiv.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void rdiv (int count, int top, int bottom)
{
int result = 0;
if (count > 0) {
result = (top/bottom);
count = (count - 1); // we do this bc --foo is not to be trusted
rdiv(count, rand(), rand());
}
}
int main(int argc, char *argv[])
{
int count;
count = atoi(argv[1]);
rdiv(count, rand(), rand());
return 0;
}
rdiv.pl
#!/usr/bin/env perl
sub divide {
my ($cnt, $divisor, $dividend) = @_;
my $garbage = 0; # placeholder for the division result
if ($cnt > 0) {
--$cnt;
$garbage = ($divisor / $dividend);
} else {
return;
}
divide($cnt, $divisor, $dividend);
}
# Main
my $initial_count = $ARGV[0];
my $MAX_INT = 32784;
divide($initial_count, int(rand($MAX_INT)), int(rand($MAX_INT)));
gcd.sh
ARGS=2
E_BADARGS=65
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` first-number second-number"
exit $E_BADARGS
fi
gcd ()
{
dividend=$1
divisor=$2
remainder=1
until [ "$remainder" -eq 0 ]
do
let "remainder = $dividend % $divisor"
dividend=$divisor
done
}
gcd $1 $2
echo; echo "GCD of $1 and $2 = $dividend"; echo
exit 0
The bash test uses a script borrowed from the advanced bash guide which finds the greatest common denominator of two numbers. By feeding the GCD script unusual and large numbers a measurement could be obtained. Each test ran thirty times, however, only three output examples for each are:
Regular GCC real 0m0.062s user 0m0.040s sys 0m0.020s real 0m0.062s user 0m0.028s sys 0m0.032s real 0m0.065s user 0m0.044s sys 0m0.020s Optimized GCC real 0m0.057s user 0m0.028s sys 0m0.028s real 0m0.064s user 0m0.044s sys 0m0.020s real 0m0.062s user 0m0.044s sys 0m0.016s Regular bash real 0m0.019s user 0m0.016s sys 0m0.004s real 0m0.019s user 0m0.016s sys 0m0.004s real 0m0.019s user 0m0.012s sys 0m0.004s Optimized bash real 0m0.019s user 0m0.020s sys 0m0.000s real 0m0.019s user 0m0.020s sys 0m0.000s real 0m0.019s user 0m0.016s sys 0m0.004s Regular Perl real 0m1.360s user 0m1.100s sys 0m0.248s real 0m1.357s user 0m1.112s sys 0m0.224s real 0m1.355s user 0m1.068s sys 0m0.272s Optimized Perl real 0m1.176s user 0m0.960s sys 0m0.200s real 0m1.178s user 0m0.964s sys 0m0.204s real 0m1.172s user 0m0.952s sys 0m0.204s
The kernel itself did not seem to be a lot faster. Outside of full blown profiling or code injection, there was no simple way to test it. On the positive side the kernel compiled and packaged a lot faster using the optimized GCC compiler.
First, the bash shell had no marginal difference, the results were nearly identical regardless of the combinations of numbers (or the test for that matter).
The next more interesting item is the Perl results, which shows a definite speed improvement with larger requirements. A larger virtual memory space makes sense when considering that optimization generally does tricks like loop unwinding that naturally need more code space.
The most surprising is GCC. While it does not show with a small program, when compiling a kernel with the optimized compiler, the compile finished in nearly 1/2 the time.
While some components such as shells may not directly benefit from optimization, even this experiment which is small in relation to what could be tested, shows that larger software systems such as a kernel or OS build can benefit from just small optimization strategies.