#! /usr/bin/perl use warnings; use strict; use Time::HiRes qw{ gettimeofday }; { my %remove; sub remove_later { undef $remove{$_[0]} ; $_[0] } sub remove_all { unlink keys %remove } sub create_file { my ($filename, $content) = @_; open my $out, '>', remove_later($filename) or die $!; print {$out} $content; } } sub measure { my ($command, $n, $prepare) = @_; # Switch the following two lines if you don't want to include compilation. my $t0 = gettimeofday(); $prepare->() if $prepare; my @cmd = $command->($n); 0 == system @cmd or die $?; my $t1 = gettimeofday(); return $t1 - $t0 } { my %prepare = (java => \&_prepare_java, c => \&_prepare_c, erlang => \&_prepare_erlang, pascal => \&_prepare_pascal); sub prepare { my ($type, $n) = @_; sub { $prepare{$type}->($n) } if exists $prepare{$type}; } } sub _prepare_java { my ($n) = @_; create_file('Measure.java', << "__JAVA__"); class Measure { public static void main (String... args) { Integer i, s=0; for(i=0; i<=$n; i++){s+=i;} } } __JAVA__ 0 == system 'javac', 'Measure.java' or die $?; remove_later('Measure.class'); } sub _prepare_c { my ($n) = @_; create_file('measure.c', << "__C__"); int main () { int i = 0, s = 0; for(i=0; i<=$n; i++){s+=i;} return 0; } __C__ 0 == system 'gcc', 'measure.c' or die $?; remove_later('a.out'); } sub _prepare_erlang { my ($n) = @_; create_file('measure.erl', << "__ERLANG__"); -module(measure). -export([main/0]). main() -> sum(0,$n,0). sum(From,To,Sum) -> case From > To of false -> sum(From+1,To,Sum+From); true -> Sum end. __ERLANG__ 0 == system 'erlc', 'measure.erl' or die $?; remove_later('measure.beam'); } sub _prepare_pascal { my ($n) = @_; create_file('measure.pas', << "__PASCAL__"); var i,s:Int64; begin s:=0; for i:=1 to $n do s:=s+i; end. __PASCAL__ 0 == system 'fpc measure.pas &>/dev/null' or die $?; remove_later($_) for qw( measure measure.o ); } sub plot { my ($plot_file, @langs) = @_; open my $gp, '>', remove_later('measure.gp') or die $!; print {$gp} join "\n", 'set term png;', 'set output "measure.png";', 'set key left;', 'set logscale x;'; my $column = 2; my $command = qq(plot "$plot_file"); print {$gp} join ', ', map { my $s = qq($command using 1:$column with lines title "$_"); $command= '""'; ++$column; $s } @langs; print {$gp} "\n"; close $gp; system 'cat measure.gp; echo; cat measure.dat'; 0 == system 'gnuplot', 'measure.gp' or die $!; } sub main { my %run = ( perl => sub { $^X, '-e', "for \$i (0..$_[0]) { \$s += \$i }" }, ruby => sub { ruby => '-e', "s=0;0.upto($_[0]){|i|s+=i}" }, java => sub { java => 'Measure' }, c => sub { './a.out' }, erlang => sub { qw( erl -noshell -s measure main -s init stop ) }, pascal => sub { './measure' }, php => sub { php => '-r', '$s=0;for($i=0;$i<='.$_[0].'; $i++){$s+=$i;}' } ); my %time; for my $n (10, 100, 1e3, 1e4, 1e5, 1e6, 2.5e6, 5e6, 7.5e6, 1e7, 2.5e7, 5e7, 7.5e7, 1e8 ) { print STDERR "$n\n"; for my $lang (sort keys %run) { $time{$n}{$lang} = measure($run{$lang}, $n, prepare($lang, $n)); } } create_file(my $plot_file = 'measure.dat', join "\n", map { my $t = $_; join ' ', $t, map $time{$t}{$_}, sort keys %{ $time{$t} } } sort { $a <=> $b } keys %time); plot($plot_file, sort keys %run); remove_all(); } main();