Expanded --sort option to take threshold args with the event names.  Lets you
do things like "show functions covering 99% of all D2mr events *and* 99% of all
D2mw events" - before you could only choose the threshold for one.

Useful for me, but probably no-one else.  Still mentioned it in the docs,
though.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@269 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/cachegrind/cg_annotate.in b/cachegrind/cg_annotate.in
index eb7e5dd..30cc049 100644
--- a/cachegrind/cg_annotate.in
+++ b/cachegrind/cg_annotate.in
@@ -112,15 +112,18 @@
 my @sort_events;
 
 # Map from @sort_events indices to @events indices, eg. (3,2).  Same idea as
-# for @show_order
+# for @show_order.
 my @sort_order;
 
-# Threshold;  whatever event is the primary sort, we print out functions
-# representing more than this proportion of 'event' events.
-my $threshold = 99;
+# Thresholds, one for each sort event (or default to 1 if no sort events
+# specified).  We print out functions and do auto-annotations until we've
+# handled this proportion of all the events thresholded.
+my @thresholds;
+
+my $default_threshold = 99;
 
 # If on, automatically annotates all files that are involved in getting over
-# the threshold count of the primary sort event.
+# all the threshold counts.
 my $auto_annotate = 0;
 
 # Number of lines to show around each annotated line.
@@ -145,7 +148,7 @@
     --show=A,B,C          only show figures for events A,B,C [all]
     --sort=A,B,C          sort columns by events A,B,C [event column order]
     --threshold=<0--100>  percentage of counts (of primary sort event) we
-                          are interested in [$threshold%]
+                          are interested in [$default_threshold%]
     --auto=yes|no         annotate all source files containing functions
                           that helped reach the event count threshold [no]
     --context=N           print N lines of context before and after
@@ -184,13 +187,22 @@
             # --sort=A,B,C
             } elsif ($arg =~ /^--sort=(.*)$/) {
                 @sort_events = split(/,/, $1);
+                foreach my $i (0 .. scalar @sort_events - 1) {
+                    if ($sort_events[$i] =~#/.*:(\d+)$/) {
+                                            /.*:([\d\.]+)%?$/) {
+                        my $th = $1;
+                        ($th >= 0 && $th <= 100) or die($usage);
+                        $sort_events[$i] =~ s/:.*//;
+                        $thresholds[$i] = $th;
+                    } else {
+                        $thresholds[$i] = 0;
+                    }
+                }
 
             # --threshold=X (tolerates a trailing '%')
             } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) {
-                $threshold = $1;
-                if ($threshold < 0 || $threshold > 100) {
-                    die($usage);
-                }
+                $thresholds[0] = $1;
+                ($1 >= 0 && $1 <= 100) or die($usage);
 
             # --auto=yes|no
             } elsif ($arg =~ /^--auto=(yes|no)$/) {
@@ -242,8 +254,9 @@
 # 1. If $a2->[$i] is undefined, it defaults to 0 which is what we want; we turn
 #    off warnings to allow this.  This makes things about 10% faster than
 #    checking for definedness ourselves.
-# 2. We don't add a ".", even though it's value is 0, because we don't want to
-#    make an $a2->[$i] that is undef become 0 unnecessarily.
+# 2. We don't add an undefined count or a ".", even though it's value is 0,
+#    because we don't want to make an $a2->[$i] that is undef become 0
+#    unnecessarily.
 sub add_array_a_to_b ($$) 
 {
     my ($a1, $a2) = @_;
@@ -251,7 +264,7 @@
     my $n = max(scalar @$a1, scalar @$a2);
     $^W = 0;
     foreach my $i (0 .. $n-1) {
-        $a2->[$i] += $a1->[$i] if ("." ne $a1->[$i]);
+        $a2->[$i] += $a1->[$i] if (defined $a1->[$i] && "." ne $a1->[$i]);
     }
     $^W = 1;
 }
@@ -331,6 +344,15 @@
         push(@sort_order, $events{$sort_event});
     }
 
+    # If no --threshold args give, default to 99% for the primary sort event,
+    # and 0% for the rest.
+    if (not @thresholds) {
+        foreach my $e (@sort_order) {
+            push(@thresholds, 0);
+        }
+        $thresholds[0] = $default_threshold;
+    }
+
     my $curr_file;
     my $curr_fn;
     my $curr_name;
@@ -424,7 +446,7 @@
     print("Events recorded:  @events\n");
     print("Events shown:     @show_events\n");
     print("Event sort order: @sort_events\n");
-    print("Threshold:        $threshold%\n");
+    print("Thresholds:       @thresholds\n");
 
     my @include_dirs2 = @include_dirs;  # copy @include_dirs
     shift(@include_dirs2);       # remove "" entry, which is always the first
@@ -534,7 +556,7 @@
 # Prints summary and function totals (with separate column widths, so that
 # function names aren't pushed over unnecessarily by huge summary figures).
 # Also returns a hash containing all the files that are involved in getting the
-# events count above the threshold (ie. all the interesting ones).
+# events count above the thresholds (ie. all the interesting ones).
 sub print_summary_and_fn_totals ()
 {
     my @fn_fullnames = keys   %fn_totals;
@@ -564,29 +586,43 @@
         mycmp($fn_totals{$a}, $fn_totals{$b})
     } @fn_fullnames;
 
-    # The thresholded event is the one that is the primary sort event.
+
+    # Assertion
+    (scalar @sort_order == scalar @thresholds) or 
+        die("sort_order length != thresholds length:\n",
+            "  @sort_order\n  @thresholds\n");
+
     my $threshold_files       = {};
-    my $threshold_event_index = $sort_order[0];
-    my $threshold_total       = $summary_CC->[$threshold_event_index];
-    my $curr_total            = 0;
+    # @curr_totals has the same shape as @sort_order and @thresholds
+    my @curr_totals = ();
+    foreach my $e (@thresholds) {
+        push(@curr_totals, 0);
+    }
 
     # Print functions, stopping when the threshold has been reached.
     foreach my $fn_name (@fn_fullnames) {
 
-        # Stop when we've reached the threshold
-        last if ($curr_total * 100 / $threshold_total >= $threshold);
+        # Stop when we've reached all the thresholds
+        my $reached_all_thresholds = 1;
+        foreach my $i (scalar @thresholds - 1) {
+            my $prop = $curr_totals[$i] * 100 / $summary_CC->[$sort_order[$i]];
+            $reached_all_thresholds &= ($prop >= $thresholds[$i]);
+        }
+        last if $reached_all_thresholds;
 
         # Print function results
         my $fn_CC = $fn_totals{$fn_name};
         print_CC($fn_CC, $fn_CC_col_widths);
         print(" $fn_name\n");
 
-        # Update the threshold counting
+        # Update the threshold counts
         my $filename = $fn_name;
         $filename =~ s/:.+$//;    # remove function name
         $threshold_files->{$filename} = 1;
-        $curr_total += $fn_CC->[$threshold_event_index] 
-            if (defined $fn_CC->[$threshold_event_index]);
+        foreach my $i (0 .. scalar @sort_order - 1) {
+            $curr_totals[$i] += $fn_CC->[$sort_order[$i]] 
+                if (defined $fn_CC->[$sort_order[$i]]);
+        }
     }
     print("\n");