checkAPIs.pl: speed up check_value_string_arrays and remove_if0_code
authorPeter Wu <peter@lekensteyn.nl>
Sun, 23 Sep 2018 14:41:09 +0000 (16:41 +0200)
committerAnders Broman <a.broman58@gmail.com>
Mon, 24 Sep 2018 04:03:50 +0000 (04:03 +0000)
The initial execution time on packet-ieee80211.c was 940ms. Optimize:
- Assume that "static const value_string ... = { ... };" does not have
  other preceding stuff (including optional whitespace). This speeds up
  check_value_string_arrays and reduces runtime by 440ms to 500ms.
- Rewrite remove_if0_code to avoid invoking a substitution for every
  line. This reduces runtime by 130ms to 370ms.

packet-rrc.c used to take 9.4s. The fixes improved it to 3.0s and 2.8s.

Change-Id: Ifc7efa447d64dccba3e211f0741099451b61b95a
Reviewed-on: https://code.wireshark.org/review/29794
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
tools/checkAPIs.pl

index 384df1a5d4c7b7bf6dd7d284b56ba1eec9019228..5f3864a63880ff1b5d0d2523a7f6e01a2d0e8992 100755 (executable)
@@ -406,7 +406,7 @@ my $StaticRegex             = qr/ static \s+
 my $ConstRegex              = qr/ const  \s+                                                            /xs;
 my $Static_andor_ConstRegex = qr/ (?: $StaticRegex $ConstRegex | $StaticRegex | $ConstRegex)            /xs;
 my $ValueStringVarnameRegex = qr/ (?:value|val64|string|range|bytes)_string                             /xs;
-my $ValueStringRegex        = qr/ ^ \s* $Static_andor_ConstRegex ($ValueStringVarnameRegex) \ + [^;*]+ = [^;]+ [{] .+? [}] \s*? ;  /xms;
+my $ValueStringRegex        = qr/ $Static_andor_ConstRegex ($ValueStringVarnameRegex) \ + [^;*]+ = [^;]+ [{] .+? [}] \s*? ;  /xs;
 my $EnumValRegex            = qr/ $Static_andor_ConstRegex enum_val_t \ + [^;*]+ = [^;]+ [{] .+? [}] \s*? ;  /xs;
 my $NewlineStringRegex      = qr/ ["] [^"]* \\n [^"]* ["] /xs;
 
@@ -950,81 +950,69 @@ sub print_usage
 # args     codeRef, fileName
 # returns: codeRef
 #
-# Essentially: Use s//patsub/meg to pass each line to patsub.
-#              patsub monitors #if/#if 0/etc and determines
-#               if a particular code line should be removed.
-# XXX: This is probably pretty inefficient;
-#      I could imagine using another approach such as converting
-#       the input string to an array of lines and then making
-#       a pass through the array deleting lines as needed.
+# Essentially: split the input into blocks of code or lines of #if/#if 0/etc.
+#               Remove blocks that follow '#if 0' until '#else/#endif' is found.
 
 {  # block begin
-my ($if_lvl, $if0_lvl, $if0); # shared vars
 my $debug = 0;
 
     sub remove_if0_code {
         my ($codeRef, $fileName)  = @_;
 
-        my ($preprocRegEx) = qr {
-                                    (                                    # $1 [complete line)
-                                        ^
-                                        (?:                              # non-capturing
-                                            \s* \# \s*
-                                            (if \s 0| if | else | endif) # $2 (only if #...)
-                                        ) ?
-                                        .*
-                                        $
-                                    )
-                            }xom;
-
-        ($if_lvl, $if0_lvl, $if0) = (0,0,0);
-        $$codeRef =~ s{ $preprocRegEx }{patsub($1,$2,$fileName)}xegm;
-
-        ($debug == 2) && print "==> After Remove if0: code: [$fileName]\n$$codeRef\n===<\n";
-        return $codeRef;
-    }
-
-    sub patsub {
-        my $fileName = @_[2];
-
-        if ($debug == 99) {
-            print "-->$_[0]\n";
-            (defined $_[1]) && print "  >$_[1]<\n";
-        }
-
-        # #if/#if 0/#else/#endif processing
-        if (defined $_[1]) {
-            my ($if) = $_[1];
-            if ($if eq 'if') {
-                $if_lvl += 1;
-            } elsif ($if eq 'if 0') {
-                $if_lvl += 1;
-                if ($if0_lvl == 0) {
-                    $if0_lvl = $if_lvl;
-                    $if0     = 1;  # inside #if 0
+        # Preprocess output (ensure trailing LF and no leading WS before '#')
+        $$codeRef =~ s/^\s*#/#/m;
+        if ($$codeRef !~ /\n$/) { $$codeRef .= "\n"; }
+
+        # Split into blocks of normal code or lines with conditionals.
+        my $ifRegExp = qr/if 0|if|else|endif/;
+        my @blocks = split(/^(#\s*(?:$ifRegExp).*\n)/m, $$codeRef);
+
+        my ($if_lvl, $if0_lvl, $if0) = (0,0,0);
+        my $lines = '';
+        for my $block (@blocks) {
+            my $if;
+            if ($block =~ /^#\s*($ifRegExp)/) {
+                # #if/#if 0/#else/#endif processing
+                $if = $1;
+                if ($debug == 99) {
+                    print(STDERR "if0=$if0 if0_lvl=$if0_lvl lvl=$if_lvl [$if] - $block");
                 }
-            } elsif ($if eq 'else') {
-                if ($if0_lvl == $if_lvl) {
-                    $if0 = 0;
-                }
-            } elsif ($if eq 'endif') {
-                if ($if0_lvl == $if_lvl) {
-                    $if0     = 0;
-                    $if0_lvl = 0;
-                }
-                $if_lvl -= 1;
-                if ($if_lvl < 0) {
-                    die "patsub: #if/#endif mismatch in $fileName"
+                if ($if eq 'if') {
+                    $if_lvl += 1;
+                } elsif ($if eq 'if 0') {
+                    $if_lvl += 1;
+                    if ($if0_lvl == 0) {
+                        $if0_lvl = $if_lvl;
+                        $if0     = 1;  # inside #if 0
+                    }
+                } elsif ($if eq 'else') {
+                    if ($if0_lvl == $if_lvl) {
+                        $if0 = 0;
+                    }
+                } elsif ($if eq 'endif') {
+                    if ($if0_lvl == $if_lvl) {
+                        $if0     = 0;
+                        $if0_lvl = 0;
+                    }
+                    $if_lvl -= 1;
+                    if ($if_lvl < 0) {
+                        die "patsub: #if/#endif mismatch in $fileName"
+                    }
                 }
             }
-            return $_[0];  # don't remove preprocessor lines themselves
-        }
 
-        # not preprocessor line: See if under #if 0: If so, remove
-        if ($if0 == 1) {
-            return '';  # remove
+            if ($debug == 99) {
+                print(STDERR "if0=$if0 if0_lvl=$if0_lvl lvl=$if_lvl\n");
+            }
+            # Keep preprocessor lines and blocks that are not enclosed in #if 0
+            if ($if or $if0 != 1) {
+                $lines .= $block;
+            }
         }
-        return $_[0];
+        $$codeRef = $lines;
+
+        ($debug == 2) && print "==> After Remove if0: code: [$fileName]\n$$codeRef\n===<\n";
+        return $codeRef;
     }
 }  # block end