adjust TEST's valgrind invocation to also work with linux's perf stat
authorJim Cromie <jim.cromie@gmail.com>
Sat, 10 Sep 2011 03:18:45 +0000 (20:18 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 10 Sep 2011 03:18:45 +0000 (20:18 -0700)
Move --log-fd=3 option from unconditional invocation into VG_OPTS
default value.  A future version of perf will understand --log-fd=3,
but other tools probably will not, with this we can accommodate them,
and the current version of perf.

Makefile.SH:

Set VALGRIND var conditionally, to allow cmdline override (this is
probably non-portable, will need review at least).

perl.valgrind.config target's test of $(VALGRIND) is simplified to use
$(VG_TEST), which defaults to its legacy value: ./perl -e 1
2>/dev/null.  Setting it to '--help' is needed for perf, and would
also work to verify that valgrind is runnable, but current test is
slightly more comprehensive for valgrind, so Ive left that for user to
change in the environment.

t/TEST:

1. --log-fd=3 is in default, but can be overridden by setting VG_OPTS
2. several variable renames to clarify purpose
3. $toolnm to rename output file with flexible suffix,
    ie: valgrind, cachegrind, perf-stat
4. add perf to cachegrind as a special case, avoid culling of valgrind
   output files by their content

With above, and following env, make test.valgrind works:

  # --log-fd isnt mainline yet.
  VALGRIND=/home/jimc/projects/lx/linux-2.6/tools/perf/perf
  VG_TEST=--help
  VG_OPTS='stat --log-fd=3 -- '

$> make test.valgrind;
PERL_VALGRIND=1 VALGRIND='/home/jimc/projects/lx/linux-2.6/tools/perf/perf'  ./runtests choose
t/base/cond....................................................ok
t/base/if......................................................ok
t/base/lex.....................................................ok
...

[jimc@groucho perl]$ cat t/base/*.perf-stat

 Performance counter stats for './perl base/cond.t':

          5.882071 task-clock                #    0.850 CPUs utilized
                 1 context-switches          #    0.000 M/sec
                 1 CPU-migrations            #    0.000 M/sec
               483 page-faults               #    0.082 M/sec
         4,688,843 cycles                    #    0.797 GHz
   <not supported> stalled-cycles-frontend
   <not supported> stalled-cycles-backend
         3,368,118 instructions              #    0.72  insns per cycle
           718,821 branches                  #  122.205 M/sec
            48,053 branch-misses             #    6.68% of all branches

       0.006920536 seconds time elapsed

This patch will allow you to use released version of perf,
just drop the --log-fd from VG_OPTS.  The tests will fail,
because perf will write to STDOUT, and foul the harness.

The following runs cachegrind, creates t/*/*.cachegrind files.
It is much slower than using perf-stat.

$> export VG_OPTS='--tool=cachegrind --log-fd=3 -- '
$> make test.valgrind

==25822== Cachegrind, a cache and branch-prediction profiler
==25822== Copyright (C) 2002-2009, and GNU GPL'd, by Nicholas Nethercote et al.
==25822== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==25822== Command: ./perl base/cond.t
==25822==
==25822==
==25822== I   refs:      1,680,072
==25822== I1  misses:        8,129
==25822== L2i misses:        3,675
==25822== I1  miss rate:      0.48%
==25822== L2i miss rate:      0.21%
==25822==
==25822== D   refs:        604,393  (400,033 rd   + 204,360 wr)
==25822== D1  misses:       12,599  (  8,838 rd   +   3,761 wr)
==25822== L2d misses:        6,261  (  2,966 rd   +   3,295 wr)
==25822== D1  miss rate:       2.0% (    2.2%     +     1.8%  )
==25822== L2d miss rate:       1.0% (    0.7%     +     1.6%  )
==25822==
==25822== L2 refs:          20,728  ( 16,967 rd   +   3,761 wr)
==25822== L2 misses:         9,936  (  6,641 rd   +   3,295 wr)
==25822== L2 miss rate:        0.4% (    0.3%     +     1.6%  )

NB: The following almost works; t runs the 1st test 5 times, and
produces 1 statistics file, but it fails, because TEST sees multiple
leaders, (FAILED--seen duplicate leader) and exits immediately,
because it happens in t/base.  A work-around is easy enough, but adds
yet another knob. TBD.

$> VALGRIND=perf VG_OPTS='stat -r5 --log-fd=3 --' make test.valgrind

 Performance counter stats for './perl base/cond.t' (5 runs):

          5.568965 task-clock                #    0.833 CPUs utilized            ( +-  1.82% )
                 0 context-switches          #    0.000 M/sec                    ( +- 61.24% )
                 0 CPU-migrations            #    0.000 M/sec                    ( +-100.00% )
               478 page-faults               #    0.086 M/sec                    ( +-  0.37% )
         4,441,737 cycles                    #    0.798 GHz                      ( +-  1.84% )
   <not supported> stalled-cycles-frontend
   <not supported> stalled-cycles-backend
         3,183,574 instructions              #    0.72  insns per cycle          ( +-  2.30% )
           669,241 branches                  #  120.173 M/sec                    ( +-  2.87% )
            41,826 branch-misses             #    6.25% of all branches          ( +-  3.78% )

       0.006688160 seconds time elapsed                                          ( +-  1.49% )

This patch is really a proof-of-concept; perf tool has far more
capabilities than t/TEST can exploit well, but this is a start,
and makes perf foo experimentation easier.

Makefile.SH
t/TEST

index 18ef6aa..7c8b545 100755 (executable)
@@ -333,7 +333,8 @@ $make_set_make
 
 # If you're going to use valgrind and it can't be invoked as plain valgrind
 # then you'll need to change this, or override it on the make command line.
-VALGRIND=valgrind
+VALGRIND ?= valgrind
+VG_TEST  ?= ./perl -e 1 2>/dev/null
 
 DTRACE = $dtrace
 DTRACE_H = $dtrace_h
@@ -887,7 +888,7 @@ perl.valgrind.config: config.sh
        @grep "^usemymalloc="    config.sh
        @grep "^usemymalloc='n'" config.sh >/dev/null || exit 1
        @echo "And of course you have to have valgrind..."
-       $(VALGRIND) ./perl -e 1 2>/dev/null || exit 1
+       $(VALGRIND) $(VG_TEST) || exit 1
 
 # Third Degree Perl (Tru64 only)
 
diff --git a/t/TEST b/t/TEST
index a691a37..0a354ba 100755 (executable)
--- a/t/TEST
+++ b/t/TEST
@@ -291,12 +291,13 @@ sub _cmd {
 
         if ($ENV{PERL_VALGRIND}) {
             my $perl_supp = $options->{return_dir} ? "$options->{return_dir}/perl.supp" : "perl.supp";
-            my $valgrind = $ENV{VALGRIND} // 'valgrind';
+            my $valgrind_exe = $ENV{VALGRIND} // 'valgrind';
             my $vg_opts = $ENV{VG_OPTS}
-              //  "--suppressions=$perl_supp --leak-check=yes "
-                . "--leak-resolution=high --show-reachable=yes "
+              // '--log-fd=3 '
+                 . "--suppressions=$perl_supp --leak-check=yes "
+                 . "--leak-resolution=high --show-reachable=yes "
                   . "--num-callers=50 --track-origins=yes";
-            $perl = "$valgrind --log-fd=3 $vg_opts $perl";
+            $perl = "$valgrind_exe $vg_opts $perl";
             $redir = "3>$Valgrind_Log";
             if ($options->{run_dir}) {
                 $Valgrind_Log = "$options->{run_dir}/$Valgrind_Log";
@@ -306,7 +307,6 @@ sub _cmd {
         my $args = "$options->{testswitch} $options->{switch} $options->{utf8}";
         $cmd = $perl . _quote_args($args) . " $test $redir";
     }
-
     return $cmd;
 }
 
@@ -516,7 +516,7 @@ EOT
     }
     # + 3 : we want three dots between the test name and the "ok"
     my $dotdotdot = $maxlen + 3 ;
-    my $valgrind = 0;
+    my $grind_ct = 0;          # count of non-empty valgrind reports
     my $total_files = @tests;
     my $good_files = 0;
     my $tested_files  = 0;
@@ -658,7 +658,9 @@ EOT
        }
 
        if ($ENV{PERL_VALGRIND}) {
-           my @valgrind;
+           my $toolnm = $ENV{VALGRIND};
+           $toolnm =~ s|.*/||;  # keep basename
+           my @valgrind;       # gets content of file
            if (-e $Valgrind_Log) {
                if (open(V, $Valgrind_Log)) {
                    @valgrind = <V>;
@@ -667,11 +669,17 @@ EOT
                    warn "$0: Failed to open '$Valgrind_Log': $!\n";
                }
            }
-           if ($ENV{VG_OPTS} =~ /cachegrind/) {
-               if (rename $Valgrind_Log, "$test.valgrind") {
-                   $valgrind = $valgrind + 1;
+           if ($ENV{VG_OPTS} =~ /(cachegrind)/ or $toolnm =~ /(perf)/) {
+               $toolnm = $1;
+               if ($toolnm eq 'perf') {
+                   # append perfs subcommand, not just stat
+                   my ($sub) = split /\s/, $ENV{VG_OPTS};
+                   $toolnm .= "-$sub";
+               }
+               if (rename $Valgrind_Log, "$test.$toolnm") {
+                   $grind_ct++;
                } else {
-                   warn "$0: Failed to create '$test.valgrind': $!\n";
+                   warn "$0: Failed to create '$test.$toolnm': $!\n";
                }
            }
            elsif (@valgrind) {
@@ -692,7 +700,7 @@ EOT
                }
                if ($errors or $leaks) {
                    if (rename $Valgrind_Log, "$test.valgrind") {
-                       $valgrind = $valgrind + 1;
+                       $grind_ct = $grind_ct + 1;
                    } else {
                        warn "$0: Failed to create '$test.valgrind': $!\n";
                    }
@@ -832,8 +840,8 @@ SHRDLU_5
        }
     }
     if ($ENV{PERL_VALGRIND}) {
-       my $s = $valgrind == 1 ? '' : 's';
-       print "$valgrind valgrind report$s created.\n", ;
+       my $s = $grind_ct == 1 ? '' : 's';
+       print "$grind_ct valgrind report$s created.\n", ;
     }
 }
 exit ($::bad_files != 0);