Here are the costs in seconds for running 100 million iterations of each
op. This only really makes sense on *my* machine, but it gives you an
idea of what sort of tradeoffs there are. Given that the difference between
most ops is negligible, I'd suggest that a lot of work is still happening
in the despatch.
The script which generated this is attached.
add_i 4.5
add_n 5
branch_ic 2
dec_i 4.5
dec_i_ic 4.5
dec_n 4.5
dec_n_nc 6
div_i 10.5
div_n 24.5
eq_i_ic 4.5
eq_ic_ic 4.5
eq_n_ic 5.5
eq_nc_ic 6
ge_i_ic 5.5
ge_ic_ic 5
ge_n_ic 6
ge_nc_ic 6
gt_i_ic 5
gt_ic_ic 5
gt_n_ic 5.5
gt_nc_ic 6.5
if_i_ic 5
if_n_ic 6
inc_i 2
inc_i_ic 4.5
inc_n 5
inc_n_nc 5.5
iton_n_i 6.5
le_i_ic 5
le_ic_ic 5
le_n_ic 5.5
le_nc_ic 5.5
length_i_s 6
lt_i_ic 4.5
lt_ic_ic 4.5
lt_n_ic 5
lt_nc_ic 6
mod_i 11
mul_i 5.5
mul_n 6
ne_i_ic 4.5
ne_ic_ic 4.5
ne_n_nc 5.5
ne_nc_ic 5
noop 3.5
ntoi_i_n 11.5
pushpop_i 14
pushpop_n 14
pushpop_p 14
pushpop_s 14
set_i 4.5
set_i_ic 4.5
set_n_nc 5
sub_i 5
sub_n 5
substr_s_s_i 23.5
time_i 49.5
time_n 49.5
--
Simon: `hello kitty' douche. If you are getting some and you know what
hello kitty is... Well, you're an exceptionally lucky man.
-- Megahal, trained on IRC.
#!/usr/bin/perl -w
use strict;
$/="\n-----\n";
my $loops = 100_000_000;
print "Calibrating loop...\n";
my $cal = testit("","");
print "Empty loop took $cal seconds\n";
$| =1;
my %cost;
while (<DATA>) {
chomp;
my @lines = split /\n/,$_;
my $name = shift @lines;
print "Testing op $name...";
my $setup ="";
my $loop = "";
if (($_ = shift @lines) eq "SETUP") {
$setup .= $_."\n" while $_ = shift @lines and $_ ne "LOOP"
} else {
$loop = $_."\n";
}
$loop .= join "\n", @lines;
print $cost{$name} = testit($setup, $loop) - $cal;
print "\n";
};
open COST, ">costmodel.tab" or die $!;
for (sort keys %cost) {
print COST "$_", " " x (40-length($_)), $cost{$_},"\n";
}
sub testit {
my ($setup, $loop) = @_;
open PASM, ">cost.pasm" or die $!;
unlink "cost.pbc";
print PASM <<EOF;
set_i_ic I33, $loops
set_i_ic I32, 0
set_i_ic I1, 0
set_i_ic I2, 1
$setup
time_i I31
REDO: eq_i_ic I32, I33, DONE, NEXT
NEXT: inc_i I32
# This is the main loop
$loop
# That was the main loop
branch_ic REDO
DONE: time_i I34
sub_i I34, I34, I31
print_i I34
EOF
system("perl assemble.pl cost.pasm > cost.pbc");
die "Didn't assemble cleanly" unless -f "cost.pbc";
# Average runs.
my $a = `./test_prog cost.pbc`;
my $b = `./test_prog cost.pbc`;
return ($a+$b)/2;
}
__DATA__
add_i
add_i I1, I2, I2
-----
sub_i
sub_i I1, I2, I2
-----
mul_i
mul_i I1, I2, I2
-----
div_i
div_i I1, I2, I2
-----
mod_i
mod_i I1, I2, I2
-----
set_i
set_i I1, I2
-----
set_i_ic
set_i_ic I1, 1
-----
eq_i_ic
eq_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
eq_ic_ic
eq_ic_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
ne_i_ic
ne_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
ne_ic_ic
ne_i_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
lt_i_ic
lt_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
lt_ic_ic
lt_ic_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
le_i_ic
le_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
le_ic_ic
le_i_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
gt_i_ic
gt_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
gt_ic_ic
gt_ic_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
ge_i_ic
ge_i_ic I1, I2, MYNEXT, MYNEXT
MYNEXT:
-----
ge_ic_ic
ge_i_ic I1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
if_i_ic
if_i_ic I1, MYNEXT, MYNEXT
MYNEXT:
-----
time_i
time_i I1
-----
branch_ic
branch_ic MYNEXT
MYNEXT:
-----
inc_i
inc_i I1
-----
inc_i_ic
inc_i_ic I1, 2
-----
dec_i
dec_i I1
-----
dec_i_ic
dec_i_ic I1, 2
-----
add_n
add_n N1, N2, N2
-----
sub_n
sub_n N1, N2, N2
-----
mul_n
mul_n N1, N2, N2
-----
div_n
div_n N1, N2, N2
-----
set_n_nc
set_n_nc N1, 1
-----
eq_n_ic
eq_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
eq_nc_ic
eq_nc_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
ne_n_nc
ne_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
ne_nc_ic
ne_n_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
lt_n_ic
lt_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
lt_nc_ic
lt_nc_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
le_n_ic
le_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
le_nc_ic
le_n_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
gt_n_ic
gt_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
gt_nc_ic
gt_nc_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
ge_n_ic
ge_n_ic N1, N2, MYNEXT, MYNEXT
MYNEXT:
-----
ge_nc_ic
ge_n_ic N1, 1, MYNEXT, MYNEXT
MYNEXT:
-----
if_n_ic
if_n_ic N1, MYNEXT, MYNEXT
MYNEXT:
-----
time_n
time_n N1
-----
inc_n
inc_n N1
-----
inc_n_nc
inc_n_nc N1, 2.0
-----
dec_n
dec_n N1
-----
dec_n_nc
dec_n_nc N1, 2.0
-----
iton_n_i
iton_n_i N1, I1
-----
ntoi_i_n
ntoi_i_n I1, N1
-----
pushpop_i
push_i
pop_i
-----
pushpop_n
push_n
pop_n
-----
pushpop_s
push_s
pop_s
-----
pushpop_p
push_p
pop_p
-----
length_i_s
SETUP
set_s_sc S1, "Hello world"
LOOP
length_i_s I1, S1
-----
substr_s_s_i
SETUP
set_s_sc S1, "Hello world"
set_i_ic I1, 3
set_i_ic I2, 4
# This saves a runtime allocation
set_s_sc S2, ""
LOOP
substr_s_s_i S2, S1, I1, I2
-----
noop
noop