# New Ticket Created by  Nicholas Clark 
# Please include the string:  [perl #16114]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=16114 >


Appended patch makes the assembler faster. The speedup was 1.8% on on machine
I tested on, 1.3% on another. (Cumulative time to loop round all the .pasm
files created by the test suite and assemble them)
I feel there' still a way to go with speedups.

Before the patch Devel::DProf thought that this is where assemble.pl spends
its time:

%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 33.0   146.5 293.80      1   146.51 293.80  Assembler::to_bytecode
 17.6   78.30 77.599  43052   0.0018 0.0018  Assembler::_annotate_contents
 15.0   66.92 114.67      1   66.926 114.67  Assembler::_generate_bytecode
 11.1   49.41 47.747  88152   0.0006 0.0005  Parrot::Types::pack_op
 6.54   29.02 29.029   2050   0.0142 0.0142  Macro::_expand_macro
 3.65   16.17 97.771      8   2.0223 12.221  Assembler::BEGIN
 3.40   15.07 15.070      1   15.070 15.070  Assembler::_adjust_labels
 3.05   13.50 42.538      1   13.509 42.538  Macro::preprocess
 2.17   9.612  9.589   2050   0.0047 0.0047  Assembler::_string_constant
 1.44   6.390  6.390      1   6.3900 6.3900  Macro::new
 1.21   5.370  5.370      1   5.3700 5.3700  Assembler::_collect_labels
 0.39   1.747  1.709   2050   0.0009 0.0008  Assembler::_numeric_constant
 0.24   1.069  1.637      6   0.1782 0.2728  FindBin::BEGIN
 0.18   0.800  0.800      1   0.8000 0.8000  Assembler::_init
 0.15   0.650  0.919     15   0.0433 0.0613  Exporter::import

With the patch:

%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 35.2   132.3 270.97      1   132.32 270.97  Assembler::to_bytecode
 17.3   65.28 109.01      1   65.280 109.01  Assembler::_generate_bytecode
 12.5   47.01 46.206  43052   0.0011 0.0011  Assembler::_annotate_contents
 12.0   45.31 43.731  79952   0.0006 0.0005  Parrot::Types::pack_op
 5.23   19.63 19.637   2050   0.0096 0.0096  Macro::_expand_macro
 4.04   15.17 64.715      9   1.6861 7.1905  Assembler::BEGIN
 3.87   14.51 14.510      1   14.510 14.510  Assembler::_adjust_labels
 2.77   10.38 10.367   2050   0.0051 0.0051  Assembler::_string_constant
 2.44   9.167 28.804      1   9.1669 28.803  Macro::preprocess
 1.68   6.310  6.590      2   3.1550 3.2948  Macro::BEGIN
 1.03   3.870  3.870      1   3.8700 3.8700  Assembler::_collect_labels
 0.28   1.039  1.267      6   0.1732 0.2111  FindBin::BEGIN
 0.21   0.770  0.770      1   0.7700 0.7700  Assembler::constant_table
 0.21   0.770  0.770      1   0.7700 0.7700  Assembler::_init
 0.20   0.750  1.069     17   0.0441 0.0629  Exporter::import

Look. I made Assembler::_generate_bytecode faster! :-)

Unfortunately Devel::SmallProf currently doesn't work with 5.8.0

The patch is entirely about changing how the regexps are generated - it
makes all the constant regexps built up by interpolating other regexps
flagged as /o, and it stops the constituent regexps being constantly
re-assigned to my variables inside subroutines.

This patch doesn't include the near infinite speedup for 5.005_03, which is
currently suffering from Warnock's Dilemma

Nicholas Clark
-- 
Even better than the real thing:        http://nms-cgi.sourceforge.net/

--- assemble.pl.orig    Mon Aug  5 20:07:04 2002
+++ assemble.pl Sat Aug 10 18:53:14 2002
@@ -93,8 +93,40 @@ This should eliminate the intermediary .
 # XXX have been added, and features -will- need to be added.
 #
 
+
+BEGIN {
+  package Syntax;
+
+  use strict;
+
+  use vars qw(@ISA @EXPORT_OK $str_re $label_re $reg_re $num_re
+              $bin_re $dec_re $hex_re $flt_re);
+  require Exporter;
+  @ISA = 'Exporter';
+  @EXPORT_OK = qw($str_re $label_re $reg_re $num_re
+                  $bin_re $dec_re $hex_re $flt_re);
+
+  $reg_re = qr([INPS]\d+);
+  $bin_re = qr([-+]?0[bB][01]+);
+  $dec_re = qr([-+]?\d+);
+  $hex_re = qr([-+]?0[xX][0-9a-fA-F]+);
+  $flt_re = qr{[-+]?\d+ (?:(?:\.\d+(?:[eE][-+]?\d+)?)
+                            | (?:[Ee][+-]?\d+))}x;
+  $str_re = qr(\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\" |
+               \'(?:[^\\\']*(?:\\.[^\\\']*)*)\'
+              )x;
+  $label_re = qr([a-zA-Z_][a-zA-Z0-9_]*);
+  $num_re   = qr([-+]?\d+(\.\d+([eE][-+]?\d+)?)?);
+
+  # until this gets broken out into a file Syntax.pm we need to cheat:
+  $INC{"Syntax.pm"} = $0;
+  # Otherwise use Syntax; will attempt to require 'Syntax.pm', which will fail
+}
+
 package Macro;
 
+use Syntax qw($label_re $num_re);
+
 =head2 Macro class
 
 =item new
@@ -156,21 +188,20 @@ sub _expand_macro {
   my ($self,$macro_name,$macro_args) = @_;
   my %args;
   my @temp = @{$self->{macros}{$macro_name}{contents}};
-  my $label_re = qr([a-zA-Z_][a-zA-Z0-9_]*);
 
   @args{@{$self->{macros}{$macro_name}{arguments}}} = @$macro_args;
   $self->{macros}{$macro_name}{gensym}++;
 
   for(@temp) {
     s{\.local\s+\$($label_re):}
-     {local__${macro_name}__${1}__$self->{macros}{$macro_name}{gensym}:}gx;
+     {local__${macro_name}__${1}__$self->{macros}{$macro_name}{gensym}:}gxo;
 
     s{\.\$($label_re)}
-     {local__${macro_name}__${1}__$self->{macros}{$macro_name}{gensym}}gx;
+     {local__${macro_name}__${1}__$self->{macros}{$macro_name}{gensym}}gxo;
     s{\.($label_re)}
-     {exists $self->{constants}{$1} ? $self->{constants}{$1} : ".$1"}gex;
+     {exists $self->{constants}{$1} ? $self->{constants}{$1} : ".$1"}gexo;
     s{\.($label_re)}
-     {exists $args{$1} ? $args{$1} : ".$1"}gex;
+     {exists $args{$1} ? $args{$1} : ".$1"}gexo;
   }
   @temp;
 }
@@ -229,9 +260,6 @@ sub preprocess {
   my $self = shift;
   my $line = 0;
   my $in_macro;
-  my $label_re = qr([a-zA-Z_][a-zA-Z0-9_]*);
-  my $reg_re   = qr([INSP]\d+);
-  my $num_re   = qr([-+]?\d+(\.\d+([eE][-+]?\d+)?)?);
 
   my @todo=@{$self->{cur_contents}};
   while(scalar(@todo)) {
@@ -253,19 +281,19 @@ sub preprocess {
 
     if(/^\.constant \s+
         ($label_re) \s+
-        ([INSP]\d+)/x) { # .constant {name} {register}
+        ([INSP]\d+)/xo) { # .constant {name} {register}
       $self->{constants}{$1} = $2;
     }
     elsif(/^\.constant \s+
         ($label_re) \s+
-        ($num_re)/x) { # .constant {name} {number}
+        ($num_re)/xo) { # .constant {name} {number}
       $self->{constants}{$1} = $2;
     }
     elsif(/^\.constant \s+
           ($label_re)  \s+
           (\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\" |
            \'(?:[^\\\']*(?:\\.[^\\\']*)*)\'
-          )/x) {                               # .constant {name} {string}
+          )/xo) {                               # .constant {name} {string}
       $self->{constants}{$1} = $2;
     }
     elsif(/^\.include \s+
@@ -288,7 +316,7 @@ sub preprocess {
     elsif(/^\.macro    \s+
            ($label_re) \s*
            \(([^)]*)\)
-         /x) {            # .{name} (...
+         /xo) {            # .{name} (...
       if($in_macro) {
         push @{$self->{contents}},$_;
         print STDERR
@@ -323,7 +351,7 @@ sub preprocess {
 #      push @{$self->{contents}},$_;
 #    }
     elsif(/\.($label_re) \s*
-           \(([^)]*)\)/x) {                    # .{name} (...
+           \(([^)]*)\)/xo) {                    # .{name} (...
       if(defined $self->{macros}{$1}) {
         my $macro_name = $1;
         my $arguments = $2;
@@ -340,7 +368,7 @@ sub preprocess {
         print STDERR "Couldn't find macro '.$1' at line $line.\n";
       }
     }
-    elsif(/\.($label_re)/) {                         # .{name}
+    elsif(/\.($label_re)/o) {                         # .{name}
       if(defined $self->{constants}{$1}) {
         push @{$self->{contents}},$_;
         $self->{contents}[-1] =~ s/\.(\w+)/$self->{constants}{$1}/g;
@@ -376,6 +404,8 @@ sub contents {
 
 package Assembler;
 
+use Syntax qw($str_re $label_re $reg_re $bin_re $dec_re $hex_re $flt_re);
+
 use POSIX; # Needed for strtol()
 
 use FindBin;
@@ -429,14 +459,12 @@ arguments have been appropriately analyz
 
 sub _annotate_contents {
   my ($self,$line) = @_;
-  my $str_re = qr(\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\" |
-                  \'(?:[^\\\']*(?:\\.[^\\\']*)*)\'
-                 )x;
 
   $self->{pc}++;
   return if $line=~/^\s*$/ or $line=~/^\s*#/; # Filter out the comments and blank 
lines
-  $line=~s/^((?:[^'"]+|$str_re)*)#.*$/$1/; # Remove trailing comments
-  $line=~s/(^\s+|\s+$)//g;           # Remove leading and trailing whitespace
+  $line=~s/^\s+//;           # Remove leading whitespace
+  $line=~s/^((?:[^'"]+|$str_re)*)#.*$/$1/o; # Remove trailing comments
+  $line=~s/\s+\z//;           # Remove trailing whitespace
   #
   # Accumulate lines that only have labels until an instruction is found.
   # XXX This could fail if a label occurs at the end of a file.
@@ -489,13 +517,11 @@ Local labels aren't given special treatm
 sub _collect_labels {
   my $self = shift;
 
-  my $label_re = qr([a-zA-Z_][a-zA-Z0-9_]*);
-
   #
   # Collect label definition points first
   #
   for(@{$self->{contents}}) {
-    while($_->[0] =~ s/^(\$?$label_re)\s*:\s*,?//) {
+    while($_->[0] =~ s/^(\$?$label_re)\s*:\s*,?//o) {
       my $label = $1;
       if($label=~/^\$/) {
         push @{$self->{local_labels}{$1}},$_->[1]; # Local label
@@ -717,8 +743,7 @@ sub constant_table {
     return ('table' => $const,
             'length' => $constl);
 }
- 
-    
+
 =item output_bytecode
 
 Returns a string with the Packfile. 
@@ -841,16 +866,6 @@ instruction, and generates bytecode. It 
 sub to_bytecode {
   my $self = shift;
 
-  my $reg_re = qr([INPS]\d+);
-  my $bin_re = qr([-+]?0[bB][01]+);
-  my $dec_re = qr([-+]?\d+);
-  my $hex_re = qr([-+]?0[xX][0-9a-fA-F]+);
-  my $flt_re = qr{[-+]?\d+ (?:(?:\.\d+(?:[eE][-+]?\d+)?)
-                               | (?:[Ee][+-]?\d+))}x;
-  my $str_re = qr(\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\" |
-                  \'(?:[^\\\']*(?:\\.[^\\\']*)*)\'
-                 )x;
-  my $label_re = qr([a-zA-Z_][a-zA-Z0-9_]*);
   my $pc = 0;
 
   $self->_collect_labels(); # Collect labels in a separate pass
@@ -869,7 +884,7 @@ sub to_bytecode {
       if($temp=~s/^#.*//) {
         # Skip flying comments.
       }
-      elsif($temp=~s/^($reg_re)//) {
+      elsif($temp=~s/^($reg_re)//o) {
         my $reg_idx = substr($1,1);
         unless($reg_idx >= 0 and $reg_idx <= 31) {
           print STDERR "Caught out-of-bounds register $1 at line $_->[1].\n";
@@ -888,7 +903,7 @@ sub to_bytecode {
       # XXX Nip off the first keyed register and replace the '[k' at the start
       # XXX of the string, so we can nip off another argument.
       #
-      elsif($temp=~s/^\[k;($reg_re)/\[k/) {
+      elsif($temp=~s/^\[k;($reg_re)/\[k/o) {
         my $reg_idx = substr($1,1);
         unless($reg_idx >= 0 and $reg_idx <= 31) {
           print STDERR "Caught out-of-bounds register $1 at line $_->[1].\n";
@@ -918,54 +933,54 @@ sub to_bytecode {
         _to_keyed_integer($_);
         push @{$_->[0]}, ['s',$1];
       }
-      elsif($temp=~s/^($flt_re)//) {
+      elsif($temp=~s/^($flt_re)//o) {
         $suffixes .= "_nc";
         push @{$_->[0]}, $self->_numeric_constant($1);
       }
-      elsif($temp=~s/^\[($str_re)\]//) {
+      elsif($temp=~s/^\[($str_re)\]//o) {
         $suffixes .= "_sc";
         _to_keyed($_);
         push @{$_->[0]}, $self->_string_constant($1);
       }
-      elsif($temp=~s/^\[($bin_re)\]//) { # P3[0b11101]
+      elsif($temp=~s/^\[($bin_re)\]//o) { # P3[0b11101]
         my $val = $1;$val=~s/0b//;
         $suffixes .= "_ic";
         _to_keyed_integer($_);
         push @{$_->[0]}, ['ic',(strtol($val,2))[0]];
       }
-      elsif($temp=~s/^\[($hex_re)\]//) { # P7[0x1234]
+      elsif($temp=~s/^\[($hex_re)\]//o) { # P7[0x1234]
         $suffixes .= "_ic";
         _to_keyed_integer($_);
         push @{$_->[0]}, ['ic',(strtol($1,16))[0]];
       }
-      elsif($temp=~s/^\[($dec_re)\]//) { # P14[3]
+      elsif($temp=~s/^\[($dec_re)\]//o) { # P14[3]
         $suffixes .= "_ic";
         _to_keyed_integer($_);
         push @{$_->[0]}, ['ic',0+$1];
       }
-      elsif($temp=~s/^\[($flt_re)\]//) {
+      elsif($temp=~s/^\[($flt_re)\]//o) {
         $suffixes .= "_nc";
        _to_keyed($_);
         push @{$_->[0]}, $self->_numeric_constant($1);
       }
-      elsif($temp=~s/^($bin_re)//) {     # 0b1101
+      elsif($temp=~s/^($bin_re)//o) {     # 0b1101
         my $val = $1;$val=~s/0b//;
         $suffixes .= "_ic";
         push @{$_->[0]}, ['ic',(strtol($val,2))[0]];
       }
-      elsif($temp=~s/^($hex_re)//) {     # 0x12aF
+      elsif($temp=~s/^($hex_re)//o) {     # 0x12aF
         $suffixes .= "_ic";
         push @{$_->[0]}, ['ic',(strtol($1,16))[0]];
       }
-      elsif($temp=~s/^($dec_re)//) {     # -32
+      elsif($temp=~s/^($dec_re)//o) {     # -32
         $suffixes .= "_ic";
         push @{$_->[0]}, ['ic',0+$1];
       }
-      elsif($temp=~s/^($str_re)//) {     # "Hello World"
+      elsif($temp=~s/^($str_re)//o) {     # "Hello World"
         $suffixes .= "_sc";
         push @{$_->[0]}, $self->_string_constant($1);
       }
-      elsif($temp=~s/^($label_re)//) {
+      elsif($temp=~s/^($label_re)//o) {
         unless(defined $self->{global_labels}{$1}) {
           print STDERR "Couldn't find global label '$1' at line $_->[1].\n";
           last;


Reply via email to