Perl vs. C (is this typical?)

Ovid on 2003-10-03T05:00:35

I was doing some more work on my neural net module when I decided to try to compare the performance with AI::NeuralNet::BackProp, a pure Perl neural network. I discovered right off the bat that I can't compare them directly because of differences in how one can create a network, but I felt that I managed a close enough comparison that I could get a rough feel for the performance characteristics.

My network has the core written in C. For one set of data, I have 27 pairs of array references, each with four elements. In the C version, I iterate over these 27 pairs a total of thirty thousand times. It takes about 10 seconds. In the pure Perl version, running that data through the network just once takes about 600 seconds. Admittedly, I'm doing a lot of floating point math and storing this data in arrays, so I know that I should get a significant boost, but this seems ridiculous.

I know it's not a fair comparison. The network architectures are slightly different (the one for Perl actually favored it since I had fewer nodes) and the internals are different, but comparing 30,000 iterations in 10 seconds to one iteration in 600 seconds just blows me away. It's been a long time since I've dabbled in C, but I'm astonished to see that much of a speedup. Is this typical?

Disclaimer: my neural network is a heavily modified version of the code found in AI Application Programming by M. Tim Jones. I don't claim to be so smart as to have been able to write one myself. Go out and buy the book. If you're interested in AI and you know C, it's worth the money.


weird

spur on 2003-10-03T07:56:45

Naturally, well written C is unbeatable in number-crunching, but a x1.8 mln times performance gain is weird. My best bet: either there's something wrong in your benchmark, or the pure Perl module is written very badly.

On the other hand...

pjm on 2003-10-03T10:51:28

Colour me naive, (close relative of mauve I guess), but a warped kind of opposite to this happened to me this afternoon. Not in the sense of finding a numberical routine that ran x-million times faster in perl, but in being shocked at how fast perl could rip through some arithmetic.

I'm teaching a course that touches on crypto, and the intro lecture mentions Hill's cipher in 2x2 form. (2x2 matrices with elemnents in Z_26, say 0..25.) I wondered just what proportion of matrices would be invertible mod 26, and threw an ugly script at it...

#!/local/bin/perl58 -w
use strict;
my $ok;
my $total;
foreach my $i (0..25){
        print "Motoring through \$i=$i now\n";
        foreach my $j (0..25){
                foreach my $k (0..25){
                        foreach my $l (0..25){
                                $total++;
                                my $det=$i*$l-$j*$k;
                                if ($det%2 && $det%13){$ok++;}
                        }
                }
        }
}
print "$ok okay out of a total of $total\n";

The "motoring through..." print statement shows my lack of confidence in this finishing in real time, but much to my amazement in about a second we had...

Motoring through $i=0 now
[...]
Motoring through $i=25 now
157248 okay out of a total of 456976

Admittedly this is on a pretty zappy Sun box: it was about 10 times slower on my humble 400MHz imac. But still not too shabby. I 'spose anyone reading this is thinking: "and how did the C version go?". Mumble, mumble... me no do C... how hard can it be given the C-ish nature of the above? OK, at the very real risk of severe embarrassment.

int main(){
int $ok=0;
int $total=0;
int $det=0;
int $i,$j,$k,$l;
for ($i=0;$i26;$i++){
        printf("Motoring through $i=%d now\n",$i);
        for ($j=0;$j26;$j++){
                for ($k=0;$k26;$k++){
                        for ($l=0;$l26;$l++){
                                $total++;
                                $det=$i*$l-$j*$k;
                                if (($det%2) && ($det%13))
                                      $ok++;
                        }
                }
        }
}
printf("%d okay out of a total of %d\n", $ok,$total);
}

157248 okay out of a total of 456976

Yay: it works. And yep, it's *fast*. Pretty much makes the imac look like the Sun running perl and the Sun running C look like greased lightning.

Cheers,
Paul

There's probably something amiss in there somewher

Elian on 2003-10-03T12:08:35

A factor of 100-200 isn't out of line, but the massive difference you're seeing means there's likely a bug in the logic somewhere--either you're doing too much in the perl code or too little in the C code...