Reorganisation of the source tree
[ghc-hetmet.git] / utils / parallel / gran-extr.pl
diff --git a/utils/parallel/gran-extr.pl b/utils/parallel/gran-extr.pl
new file mode 100644 (file)
index 0000000..509da49
--- /dev/null
@@ -0,0 +1,2114 @@
+#!/usr/local/bin/perl
+##############################################################################
+# Last modified: Time-stamp: <Sat Oct 28 1995 23:49:48 Stardate: [-31]6509.75 hwloidl>
+#                                                      (C) Hans Wolfgang Loidl
+#
+# Usage: gran-extr [options] [<sim-file>]
+#
+# Takes a file <sim-file> generated by running the GrAnSim simulator and 
+# produces data files that should be used as input for gnuplot.
+# This script produces figures for:
+#   runtime of tasks
+#   percentage of communication
+#   heap allocation
+#   number of created sparks
+#   cumulative no. of tasks over runtime
+# Furthermore, it computes the correlation between runtime and heap allocation.
+#
+# Options:
+#  -g <file>  ... filename of granularity file to be produced; should end with
+#                .dat; -global and -local will be automatically inserted for 
+#                other versions. 
+#  -c <file> ... filename of communication file to be produced; should end with
+#                .dat; -global and -local will be automatically inserted for 
+#                other versions. 
+#  -s <file> ... filename of sparked-threads file to be produced; should end w/
+#                .dat; -global and -local will be automatically inserted for 
+#                other versions. 
+#  -a <file> ... filename of heap alloc. file to be produced; should end with
+#                .dat;
+#  -f <file> ... filename of communication time file to be produced; 
+#                should end with .dat;
+#  -p <file> ... filename of GNUPLOT file that is prouced and executed.
+#  -G <LIST> ... provide a list of boundaries for the Intervals used in the 
+#                granularity figure; must be a Perl list e.g. (10, 20, 50)
+#                this is interpreted as being open to left and right.
+#  -C <LIST> ... provide a list of boundaries for the Intervals used in the 
+#                communication figure; must be a Perl list e.g. (10, 20, 50)
+#                this is interpreted as being closed to left and right.
+#  -S <LIST> ... provide a list of boundaries for the Intervals used in the 
+#                sparked-threads figure; must be a Perl list e.g. (10, 20, 50)
+#                this is interpreted as being closed to left and right.
+#  -A <LIST> ... provide a list of boundaries for the Intervals used in the 
+#                heap alloc figure; must be a Perl list e.g. (10, 20, 50)
+#                this is interpreted as being closed to left and right.
+#  -F <LIST> ... provide a list of boundaries for the Intervals used in the 
+#                comm. time figure; must be a Perl list e.g. (10, 20, 50)
+#                this is interpreted as being open to left and right.
+#  -l <int>  ... left margin in the produced figures.
+#  -r <int>  ... right margin in the produced figures.
+#  -x <int>  ... enlargement of figure along x-axis.
+#  -y <int>  ... enlargement of figure along y-axis.
+#  -e <int>  ... thickness of impulses in figure.
+#  -i <rat>  ... set the gray level of the impulses to <rat>; <rat> must be
+#                between 0 and 1 with 0 meaning black. 
+#  -k <n>    ... number of klusters (oops, clusters, I mean ;)
+#  -P        ... print percentage of threads rather than absolute number of 
+#                threads on the y axis
+#  -t <file> ... use template <file> for interval settings and file names
+#                Syntax of a line in the template file:
+#                 <flag>: <arg>
+#  -T        ... use smart xtics rather than GNUPLOT default x-axis naming.
+#  -L        ... use logarithmic scale for all figures.
+#  -W        ... print warnings
+#  -m        ... generate monchrome output
+#  -h        ... help; print this text.
+#  -v        ... verbose mode.
+#
+##############################################################################
+
+# ----------------------------------------------------------------------------
+# Command line processing and initialization
+# ----------------------------------------------------------------------------
+
+require "getopts.pl";
+
+&Getopts('hvWTPDmt:L:g:f:c:s:a:p:G:F:C:S:A:l:r:x:y:e:i:k:');  
+
+do process_options();
+
+$OPEN_INT = 1;
+$CLOSED_INT = 0;
+
+if ( $opt_v ) {
+    do print_verbose_message ();
+}
+
+# ----------------------------------------------------------------------------
+# The real thing
+# ----------------------------------------------------------------------------
+
+open(INPUT,"<$input") || die "Couldn't open input file $input";
+
+do skip_header();
+
+$tot_total_rt = 0;
+$tot_rt = 0;
+$tot_bt = 0;
+$tot_ft = 0;
+$tot_it = 0;
+$gum_style_gr = 0;
+
+$line_no = 0;
+while (<INPUT>) {
+    next                     if /^--/;     # Comment lines start with --
+    next                    if /^\s*$/;   # Skip empty lines
+    $line_no++;
+    @fields = split(/[:,]/,$_);
+    $has_end = 0;
+
+    foreach $elem (@fields) {
+      foo : {
+        $pe = $1, $end = $2 , last foo   if $elem =~ /^\s*PE\s+(\d+)\s+\[(\d+)\].*$/;
+        $tn = $1, $has_end = 1  , last foo   if $elem =~ /^\s*END\s+(\w+).*$/;
+       # $tn = $1      , last foo   if $elem =~ /^\s*TN\s+(\w+).*$/;
+       $sn = $1        , last foo   if $elem =~ /^\s*SN\s+(\d+).*$/;
+        $start = $1     , last foo   if $elem =~ /^\s*ST\s+(\d+).*$/;
+        $is_global = $1 , last foo   if $elem =~ /^\s*EXP\s+(T|F).*$/;
+        $bbs = $1       , last foo   if $elem =~ /^\s*BB\s+(\d+).*$/;
+        $ha = $1        , last foo   if $elem =~ /^\s*HA\s+(\d+).*$/;
+        $rt = $1        , last foo   if $elem =~ /^\s*RT\s+(\d+).*$/;
+        $bt = $1, $bc = $2 , last foo if $elem =~ /^\s*BT\s+(\d+)\s+\((\d+)\).*$/;
+        $ft = $1, $fc = $2 , last foo if $elem =~ /^\s*FT\s+(\d+)\s+\((\d+)\).*$/;
+        $lsp = $1        , last foo   if $elem =~ /^\s*LS\s+(\d+).*$/;
+        $gsp = $1        , last foo   if $elem =~ /^\s*GS\s+(\d+).*$/;
+        $my = $1        , last foo   if $elem =~ /^\s*MY\s+(T|F).*$/;
+      }
+    }
+
+    next unless $has_end == 1;
+
+    $total_rt = $end - $start;
+    $ready_time = $total_rt - $rt - $bt - $ft;
+
+    # ------------------------------------------------------------------------
+    # Accumulate runtime, block time, fetch time and ready time over all threads
+    # ------------------------------------------------------------------------
+
+    $tot_total_rt += $total_rt;
+    $tot_rt += $rt;
+    $tot_bt += $bt;
+    $tot_ft += $ft;
+    $tot_it += $ready_time;
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about `load' on the PEs
+    # ------------------------------------------------------------------------
+
+    print "WARNING: ready time of thread is <0: $ready_time\n" if $pedantic && ($ready_time <0);
+    $pe_load[$pe] += $ready_time;
+
+    if ( $opt_D ) {
+       print "Adding $ready_time to the load time of PE no. $pe yielding $pe_load[$pe]\n";
+    }
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about the size of a spark site
+    # ------------------------------------------------------------------------
+
+    $site_size[$sn] += $rt;
+
+    if ( $opt_D ) {
+       print "Adding $rt to the size of site $sn yielding $site_size[$sn]\n";
+    }
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about pure exec time
+    # ------------------------------------------------------------------------
+
+    push(@all_rts,$rt);
+    $sum_rt += $rt;
+    $max_rt = $rt  if $rt > $max_rt;
+
+    $index = do get_index_open_int($rt,@exec_times);
+    $exec_class[$index]++;
+
+    if ( $is_global eq 'T' ) {
+       $exec_global_class[$index]++;
+    } else {
+       $exec_local_class[$index]++;
+    }
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about communication time (absolute time rather than %)
+    # ------------------------------------------------------------------------
+    
+    # Note: Communicatin time is fetch time
+
+    push(@all_fts,$ft);
+    $sum_ft += $ft;
+    $max_ft = $ft  if $ft > $max_ft;
+
+    $index = do get_index_open_int($ft,@fetch_times);
+    $fetch_class[$index]++;
+
+    if ( $is_global eq 'T' ) {
+       $fetch_global_class[$index]++;
+    } else {
+       $fetch_local_class[$index]++;
+    }
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about communication percentage
+    # ------------------------------------------------------------------------
+
+    $comm_perc = ( $total_rt == 0 ? 100 : (100 * $ft)/$total_rt );
+
+    push(@all_comm_percs,$comm_perc); 
+    $sum_comm_perc += $comm_perc;
+    $max_comm_perc = $comm_perc  if $comm_perc > $max_comm_perc;
+
+    $index = do get_index_closed_int( $comm_perc, @comm_percs );
+    if ( $index != -1 ) {
+      $comm_class[$index]++;
+    } else {
+      print "WARNING: value " . $comm_perc . " not in range (t_rt=$total_rt; ft=$ft)\n" if $pedantic;
+      $outside++;
+    }
+
+    if ( $is_global eq 'T' ) {
+      if ( $index != -1 ) {
+       $comm_global_class[$index]++;
+      } else {
+        $outside_global++;
+      }
+    } else {
+      if ( $index != -1 ) {
+       $comm_local_class[$index]++;
+      } else {
+        $outside_local++;
+      }
+    }
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about locally sparked threads
+    # ------------------------------------------------------------------------
+
+    push(@all_local_sparks,$lsp);
+    $sum_local_sp += $lsp;
+    $max_local_sp = $lsp  if $lsp > $max_local_sp;
+
+    $index = do get_index_open_int($lsp,@sparks);
+    $spark_local_class[$index]++;
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about globally sparked threads
+    # ------------------------------------------------------------------------
+
+    push(@all_global_sparks,$gsp);
+    $sum_global_sp += $gsp;
+    $max_global_sp = $gsp  if $gsp > $max_global_sp;
+
+    $index = do get_index_open_int($gsp,@sparks);
+    $spark_global_class[$index]++;
+
+    # ------------------------------------------------------------------------
+    # Add the above two entries to get the total number of sparks
+    # ------------------------------------------------------------------------
+
+    $sp = $lsp + $gsp;
+
+    push(@all_sparks,$sp);
+    $sum_sp += $sp;
+    $max_sp = $sp  if $sp > $max_sp;
+
+    $index = do get_index_open_int($sp,@sparks);
+    $spark_class[$index]++;
+
+    # ------------------------------------------------------------------------
+    # Gather statistics about heap allocations
+    # ------------------------------------------------------------------------
+
+    push(@all_has,$ha);
+    $sum_ha += $ha;
+    $max_ha = $ha  if $ha > $max_ha;
+
+    $index = do get_index_open_int($ha,@has);
+    $ha_class[$index]++;
+
+    # do print_line($start,$end,$is_global,$bbs,$ha,$rt,$bt,$bc,$ft,$fc,$my);
+}
+
+print STDERR "You don't want to engage me for a file with just $line_no lines, do you?(N)\n" , exit (-1)         if $line_no <= 1;
+
+# ----------------------------------------------------------------------------
+
+do write_pie_chart();
+
+# ----------------------------------------------------------------------------
+# Statistics
+# ----------------------------------------------------------------------------
+
+if ( $opt_D ) {
+  print "Lengths:\n" .
+        "   all_rts: $#all_rts;\n" .
+        "   all_comm_percs: $#all_comm_percs;\n" .
+        "   all_sparks: $#all_sparks; \n" . 
+        "   all_local_sparks: $#all_local_sparks; \n" .
+        "   all_global_sparks: $#all_global_sparks; \n" . 
+        "   all_has: $#all_has\n" .
+       "   all_fts: $#all_fts;\n";
+
+
+  print "No of elems in all_rts: $#all_rts with sum $sum_rt\n";
+  print "No of elems in all_comm_percs: $#all_rts with sum $sum_comm_perc\n";
+  print "No of elems in all_has: $#all_has with sum $sum_ha\n";
+  print "No of elems in all_fts: $#all_fts with sum $sum_ft\n";
+
+}
+
+do do_statistics($line_no);
+
+# Just for debugging
+# ..................
+
+if ( $opt_D ) {
+  open(FILE,">LOG") || die "Couldn't open file LOG\n";
+  printf FILE "All total runtimes (\@all_rts:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_rts);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_rt, $std_dev_rt\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All  communication times (\@all_fts:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_fts);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_ft, $std_dev_ft\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All communication percentages (\@all_comm_percs:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_comm_percs);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_comm_perc,$std_dev_comm_perc\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All  sparks  (\@all_sparks:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_sparks);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_spark,$std_dev_spark\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All local sparks  (\@all_local_sparks:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_local_sparks);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_local_spark,$std_dev_local_spark\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All global sparks  (\@all_global_sparks:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_global_sparks);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_global_spark,$std_dev_global_spark\n";
+  printf FILE 70 x "-" . "\n";
+  printf FILE "All local sparks  (\@all_has:)\n";
+  printf FILE "[";
+  printf FILE join(", ",@all_has);
+  printf FILE "]\n";
+  printf FILE "  Mean, std. dev: $mean_ha,$std_dev_ha\n";
+  printf FILE 70 x "-" . "\n";
+
+
+  printf FILE ("CORR of runtime and heap alloc:  %f\n",$c_exec_ha);
+  printf FILE ("CORR of runtime and no. of sparks:  %f\n",$c_exec_sp);
+  printf FILE ("CORR of heap alloc and no. sparks:  %f\n",$c_ha_sp);
+  printf FILE ("CORR of runtime and local sparks:  %f\n",$c_exec_lsp);
+  printf FILE ("CORR of runtime and global sparks:  %f\n",$c_exec_gsp);
+  printf FILE ("CORR of heap alloc and local sparks:  %f\n",$c_ha_lsp);
+  printf FILE ("CORR of heap alloc and global sparks:  %f\n",$c_ha_gsp);
+  printf FILE ("CORR of runtime and communication time:  %f\n",$c_exec_ft);
+  printf FILE ("CORR of heap alloc and communication time:  %f\n",$c_ha_ft);
+  printf FILE ("CORR of local sparks and communication time:  %f\n",$c_lsp_ft);
+  printf FILE ("CORR of global_sparks and communication time:  %f\n",$c_gsp_ft);
+  close FILE;
+}
+
+if ( $opt_P ) {
+  do percentify($line_no,*exec_class);
+  do percentify($line_no,*exec_global_class);
+  do percentify($line_no,*exec_local_class);
+  do percentify($line_no,*comm_class);
+  do percentify($line_no,*comm_global_class);
+  do percentify($line_no,*comm_local_class);
+  do percentify($line_no,*spark_local_class);
+  do percentify($line_no,*spark_global_class);
+  do percentify($line_no,*ha_class);
+  do percentify($line_no,*ft_class);
+}
+
+# Produce cumulative RT graph and other (more or less) nice graphs
+# ................................................................
+
+do sort_and_cum();
+
+# ----------------------------------------------------------------------------
+
+open(IV,">INTERVALS") || die "Couldn't open file INTERVALS\n";
+do write_interval(IV, 'G', &guess_interval(@all_rts));
+do write_interval(IV, 'C', 0, int($mean_comm_perc), 
+                           int($mean_comm_perc+$std_dev_comm_perc), 50);
+do write_interval(IV, 'S', &guess_interval(@all_sparks));
+do write_interval(IV, 'A', &guess_interval(@all_has));
+close(IV);
+
+# ----------------------------------------------------------------------------
+# Print results to STDOUT (mainly for testing)
+# ----------------------------------------------------------------------------
+
+if ( $opt_v ) {
+    do print_general_info();
+}
+
+# ----------------------------------------------------------------------------
+# Write results to data files to be processed by GNUPLOT
+# ----------------------------------------------------------------------------
+
+do write_data($gran_file_name, $OPEN_INT, $logscale{'g'}, $#exec_times+1,
+              @exec_times, @exec_class);
+
+do write_data($gran_global_file_name, $OPEN_INT, $logscale{'g'}, $#exec_times+1,
+              @exec_times, @exec_global_class);
+
+do write_data($gran_local_file_name, $OPEN_INT, $logscale{'g'}, $#exec_times+1,
+              @exec_times, @exec_local_class);
+
+do write_data($comm_file_name, $CLOSED_INT, $logscale{'c'}, $#comm_percs+1,
+              @comm_percs, @comm_class);
+
+do write_data($comm_global_file_name, $CLOSED_INT, $logscale{'c'}, $#comm_percs+1,
+              @comm_percs, @comm_global_class);
+
+do write_data($comm_local_file_name, $CLOSED_INT, $logscale{'c'}, $#comm_percs+1,
+              @comm_percs, @comm_local_class);
+
+do write_data($spark_file_name, $OPEN_INT, $logscale{'s'}, $#sparks+1,
+              @sparks, @spark_class);
+
+do write_data($spark_local_file_name, $OPEN_INT, $logscale{'s'}, $#sparks+1,
+              @sparks, @spark_local_class);
+
+do write_data($spark_global_file_name, $OPEN_INT, $logscale{'s'}, $#sparks+1,
+              @sparks, @spark_global_class);
+
+do write_data($ha_file_name, $OPEN_INT, $logscale{'a'}, $#has+1,
+              @has, @ha_class);
+
+do write_data($ft_file_name, $OPEN_INT, $logscale{'g'}, $#fetch_times+1,
+              @fetch_times, @fetch_class);
+
+
+# ----------------------------------------------------------------------------
+# Run GNUPLOT over the data files and create figures
+# ----------------------------------------------------------------------------
+
+do gnu_plotify($gp_file_name); 
+
+print "Script finished successfully!\n";
+
+exit 0;
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+# ----------------------------------------------------------------------------
+# Basic Operations on the intervals
+# ----------------------------------------------------------------------------
+
+sub get_index_open_int {
+    local ($value,@list) = @_;
+    local ($index,$right);
+
+    # print "get_index: searching for index of" . $value;
+    # print " in " . join(':',@list);
+
+      $index = 0;
+      $right = $list[$index];
+      while ( ($value >= $right) && ($index < $#list) ) {
+       $index++;
+        $right = $list[$index];
+      }
+    
+      return ( ($index == $#list) && ($value > $right) ) ? $index+1 : $index;
+}
+
+# ----------------------------------------------------------------------------
+
+sub get_index_closed_int {
+    local ($value,@list) = @_;
+    local ($index,$right);
+
+      if ( ($value < $list[0]) || ($value > $list[$#list]) ) {
+         return ( -1 );
+      }
+
+      $index = 0;
+      $left = $list[$index];
+      while ( ($left <= $value) && ($index < $#list) ) {
+       $index++;
+        $left = $list[$index];
+      }
+      return ( $index-1 );
+}
+
+# ----------------------------------------------------------------------------
+# Write operations
+# ----------------------------------------------------------------------------
+
+sub write_data {
+    local ($file_name, $open_int, $logaxes, $n, @rest) = @_;
+    local (@times) = splice(@rest,0,$n);
+    local (@class) = @rest;
+
+    open(GRAN,">$file_name") || die "Couldn't open file $file_name for output";
+
+    if ( $open_int == $OPEN_INT ) {
+
+      for ($i=0, 
+           $left = ( index($logaxes,"x") != -1 ? int($times[0]/2) : 0 ), 
+           $right = 0; 
+           $i < $n; 
+           $i++, $left = $right) {
+         $right = $times[$i];
+         print GRAN int(($left+$right)/2) . "  " . 
+                    ($class[$i] eq "" ? "0" : $class[$i]) . "\n"; 
+      }
+      print GRAN $times[$n-1]+(($times[$n-1]-$times[$n-2])/2) . "  " . 
+                 ($class[$n] eq "" ? "0" : $class[$n]) . "\n";
+
+     } else {
+
+      print GRAN ( (index($logaxes,"x") != -1) && ($times[0] == 0 ? int($times[1]/2) : ($times[$1] + $times[0])/2 ) .  "  " . $class[0] . "\n");
+      for ($i=1; $i < $n-2; $i++) {
+         $left = $times[$i];
+         $right = $times[$i+1];
+         print(GRAN ($left+$right)/2 . "  " . 
+                    ($class[$i] eq "" ? "0" : $class[$i]) . "\n"); 
+      }
+      print GRAN ($times[$n-1]+$times[$n-2])/2 . "  " . $class[$n-2]  if $n >= 2;
+    }
+
+    close(GRAN);
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_array {
+    local ($file_name,$n,@list) = @_;
+
+    open(FILE,">$file_name") || die "$file_name: $!";
+    for ($i=0; $i<=$#list; $i++) {
+       print FILE $i . "  " .  ( $list[$i] eq "" ? "0" : $list[$i] ) . "\n";
+    }
+
+    if ( $opt_D ) {
+       print "write_array: (" . join(", ",1 .. $#list) . ")\n for file $file_name returns: \n (0, $#list, &list_max(@list)\n";
+    } 
+
+    return ( (0, $#list, &list_max(@list), 
+              "(" . join(", ",1 .. $#list) . ")\n") );
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_cumulative_data {
+    local ($file_name1,$file_name2,@list) = @_;
+    local (@ns, @elems, @xtics, $i, $j, $n, $elem, $max_clust, $xtics_str,
+           $xstart, $xend, $file_name0);
+    local ($CLUST_SZ) = $no_of_clusters;
+
+    @ns = ();
+    @elems = ();
+    $file_name0 = $file_name1;
+    $file_name0 =~ s/\.dat$//;
+    $file_name0 .= "0.dat";
+    open(CUMM,">$file_name1") || die "Couldn't open file $file_name1 (error $!)\n";
+    open(CUMM0,">$file_name0") || die "Couldn't open file $file_name0 (error $!)\n";
+
+    print CUMM "1  0\n" unless $list[0] <= 1;
+    print CUMM0 "1  0\n" unless $list[0] <= 1;;
+
+    for ($i=0; $i <= $#list; $i++) {
+       $elem = $list[$i];
+        print CUMM ($elem) . "  " . int( (100 * ($i)) / ($#list+1) ) . "\n"  unless $elem == 0;
+        print CUMM0 ($elem) . "  " . $i . "\n" unless $elem == 0;;
+       for ($n=1; $i < $#list && $list[$i+1] == $elem; $i++, $n++) { }
+
+        print CUMM "$elem  " . int( (100 * ($i+1)) / ($#list+1) ) . "\n";
+        print CUMM0 "$elem  " . ($i+1) . "\n";
+       
+
+        if ( $opt_D ) {
+           print "\n--> Insert: n:  $n (elem $elem) in the above lists yields: \n  ";
+        }
+
+        # inlined version of do insert_elem($elem, $n, $#exs, @exs, @ns)
+       for ($j=0; $j<=$#ns && $ns[$j]>$n; $j++) { }
+       if ( $j > $#ns ) {
+           push(@ns,$n);
+           push(@elems,$elem);
+       } else {
+           splice(@ns,$j,0,$n);           # insert $n at pos $j and move the
+           splice(@elems,$j,0,$elem);     # rest of the array to the right
+       }
+
+        if ( $opt_D ) {
+           print "[" . join(", ",@ns) . "]" . "\n and \n" . 
+                 "[" . join(", ",@elems) . "]\n";
+        }
+      
+    }
+
+    close(CUMM);
+    close(CUMM0);
+
+    open(CLUSTERS_ALL,">" . (&dirname($file_name2)) . "CL-" .
+                     &basename($file_name2)) 
+        || die "Couldn't open file CL-$file_name2 (error $!)\n";
+    for ($i=0; $i <= $#ns; $i++) {
+       print CLUSTERS_ALL "$elems[$i]  $ns[$i]\n";
+    }
+    close(CLUSTERS_ALL);
+
+    # Interesting are only the first parts of the list (clusters!)
+    splice(@elems, $CLUST_SZ);
+    splice(@ns, $CLUST_SZ);
+
+    open(CLUSTERS,">$file_name2") || die "Couldn't open file $file_name2 (error $!)\n";
+
+    $xstart = &list_min(@elems);
+    $xend =   &list_max(@elems);
+    $step = ($xend - $xstart) / ( $CLUST_SZ == 1 ? 1 : ($CLUST_SZ-1));
+
+    @xtics = ();
+    for ($i=0, $x=$xstart; $i <= $#ns; $i++, $x+=$step) {
+       print CLUSTERS "$x  $ns[$i]\n";
+       push(@xtics,"\"$elems[$i]\" $x");
+    }
+    close(CLUSTERS);
+
+    $max_clust = $ns[0];
+    $xtics_str = "(" . join(", ",@xtics) . ")\n";
+
+    return ( ($xstart, $xend, $max_clust, $xtics_str) );
+}
+
+# ----------------------------------------------------------------------------
+
+sub get_xtics {
+    local ($open_int, @list) = @_;
+
+    local ($str);
+
+    if ( $open_int == $OPEN_INT ) { 
+      $last = pop(@list);
+      $str = "( \">0\" 0";
+      foreach $x (@list) {
+         $str .= ", \">$x\" $x";
+      }
+      $str .= ", \"Large\" $last)\n";
+    } else { 
+      $left = shift(@list);
+      $right = shift(@list)  if $#list >= 0;
+      $last  = pop(@list)    if $#list >= 0;
+      $str = "( \"$left-$right\" " . $left;
+      $left = $right;
+      foreach $right (@list) {
+         $str .= ", \"$left-$right\" " . ($left+$right)/2;
+         $left = $right;
+      }
+      $str .= ", \"$left-$last\" " . $last .")\n"   unless $last eq "";
+    }
+    return $str;
+}
+
+# ----------------------------------------------------------------------------
+
+sub print_line {
+    local ($start,$end,$is_global,$bbs,$ha,$rt,$bt,$bc,$ft,$fc,$my) = @_;
+
+    printf("START: %u, END: %u  ==> tot_exec: %u\n",
+           $start,$end,$end-$start);
+    printf("  BASIC_BLOCKS: %u, HEAP_ALLOCATIONS: %u \n",$bbs,$ha);
+    printf("  TOT_EXEC: %u = RUN_TIME %u + BLOCK_TIME %u + FETCH_TIME %u\n",
+           $end-$start,$rt,$bt,$ft);
+    printf("  BLOCK_TIME %u / BLOCK_COUNT %u; FETCH_TIME %u / FETCH_COUNT %u\n",
+          $bt,$bc,$ft,$fc);
+    printf("  %s  %s\n",
+           $is_global eq 'T' ? "GLOBAL" : "LOCAL",
+           $my eq 'T' ? "MANDATORY" : "NOT MANDATORY"); 
+}
+           
+# ----------------------------------------------------------------------------
+
+sub gnu_plotify {
+  local ($gp_file_name) = @_;
+
+  local (@open_xrange,@closed_xrang,@spark_xrange,@ha_xrange, @ft_range,
+         $exec_xtics,$comm_perc_xtics,$spark_xtics,$has_xtics,
+        $cumu0_rts_file, $cumu0_has_file, $cumu0_fts_file);
+
+ $cumu0_rts_file = $cumulat_rts_file_name;
+ $cumu0_rts_file =~ s/\.dat$//;
+ $cumu0_rts_file .= "0.dat";
+
+ $cumu0_has_file = $cumulat_has_file_name;
+ $cumu0_has_file =~ s/\.dat$//;
+ $cumu0_has_file .= "0.dat";
+
+ $cumu0_fts_file = $cumulat_fts_file_name;
+ $cumu0_fts_file =~ s/\.dat$//;
+ $cumu0_fts_file .= "0.dat";
+
+ $cumu0_cps_file = $cumulat_cps_file_name;
+ $cumu0_cps_file =~ s/\.dat$//;
+ $cumu0_cps_file .= "0.dat";
+
+  @open_xrange = &range($OPEN_INT,$logscale{'g'},@exec_times);
+  @closed_xrange = &range($CLOSED_INT,$logscale{'c'},@comm_percs);
+  @spark_xrange = &range($OPEN_INT,$logscale{'s'},@sparks);
+  @ha_xrange = &range($OPEN_INT,$logscale{'a'},@has);
+  @ft_xrange = &range($OPEN_INT,$logscale{'f'},@fts);
+
+  $exec_xtics = $opt_T ? &get_xtics($OPEN_INT,@exec_times) : "" ;
+  $comm_perc_xtics = $opt_T ? &get_xtics($CLOSED_INT,@comm_percs) : "";
+  $spark_xtics = $opt_T ? &get_xtics($OPEN_INT,@sparks) : "";
+  $has_xtics = $opt_T ? &get_xtics($OPEN_INT,@has) : "";
+  $fts_xtics = $opt_T ? &get_xtics($OPEN_INT,@fts) : "";
+
+  open(GP_FILE,">$gp_file_name") || 
+      die "Couldn't open gnuplot file $gp_file_name for output\n";
+
+  if ( $opt_m ) {
+      print GP_FILE "set term postscript \"Roman\" 20\n";
+  } else {
+      print GP_FILE "set term postscript color \"Roman\" 20\n";
+  }
+
+  do write_gp_record(GP_FILE,
+                     $gran_file_name, &dat2ps_name($gran_file_name),
+                     "Granularity (pure exec. time)", $ylabel, $logscale{'g'},
+                     @open_xrange,$max_rt_class,$exec_xtics);
+  do write_gp_record(GP_FILE,
+                     $gran_global_file_name, &dat2ps_name($gran_global_file_name),
+                     "Granularity (pure exec. time) of exported threads",
+                     $ylabel, $logscale{'g'},
+                     @open_xrange,$max_rt_global_class,$exec_xtics);
+  do write_gp_record(GP_FILE,
+                     $gran_local_file_name, &dat2ps_name($gran_local_file_name),
+                     "Granularity (pure exec. time) of not exported threads",
+                     $ylabel,$logscale{'g'},
+                     @open_xrange,$max_rt_local_class,$exec_xtics);
+
+  do write_gp_record(GP_FILE,
+                     $comm_file_name, &dat2ps_name($comm_file_name),
+                     "% of communication",$ylabel,$logscale{'c'},
+                     @closed_xrange,$max_comm_perc_class,$comm_perc_xtics);
+  do write_gp_record(GP_FILE,
+                     $comm_global_file_name, &dat2ps_name($comm_global_file_name),
+                     "% of communication of exported threads",$ylabel,$logscale{'c'},
+                     @closed_xrange,$max_comm_perc_global_class,$comm_perc_xtics);
+  do write_gp_record(GP_FILE,
+                     $comm_local_file_name, &dat2ps_name($comm_local_file_name),
+                     "% of communication of not exported threads",$ylabel,$logscale{'c'},
+                     @closed_xrange,$max_comm_perc_local_class,$comm_perc_xtics);
+  do write_gp_record(GP_FILE,
+                     $ft_file_name, &dat2ps_name($ft_file_name),
+                     "Communication time", $ylabel, $logscale{'g'},
+                     @open_xrange,$max_ft_class,$fts_xtics);
+
+
+  do write_gp_record(GP_FILE,
+                     $spark_file_name, &dat2ps_name($spark_file_name),
+                     "No. of sparks created", $ylabel, $logscale{'s'},
+                     @spark_xrange,$max_spark_class,$spark_xtics);
+
+  do write_gp_record(GP_FILE,
+                     $spark_local_file_name, &dat2ps_name($spark_local_file_name),
+                     "No. of sparks created (parLocal)", $ylabel, $logscale{'s'},
+                     @spark_xrange,$max_spark_local_class,$spark_xtics);
+
+  do write_gp_record(GP_FILE,
+                     $spark_global_file_name, &dat2ps_name($spark_global_file_name),
+                     "No. of sparks created (parGlobal)", $ylabel, $logscale{'s'},
+                     @spark_xrange,$max_spark_global_class,$spark_xtics);
+
+  do write_gp_record(GP_FILE,
+                     $ha_file_name, &dat2ps_name($ha_file_name),
+                     "Heap Allocations (words)", $ylabel, $logscale{'a'},
+                     @ha_xrange,$max_ha_class,$has_xtics);
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumulat_rts_file_name, &dat2ps_name($cumulat_rts_file_name),
+                           "Cumulative pure exec. times","% of threads",
+                          $logscale{'Cg'},
+                           $xend_cum_rts, $yend_cum_rts,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumulat_has_file_name, &dat2ps_name($cumulat_has_file_name),
+                           "Cumulative heap allocations","% of threads",
+                          $logscale{'Ca'},
+                           $xend_cum_has, $yend_cum_has,"");
+                           #  $xtics_cluster_has as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumu0_rts_file, &dat2ps_name($cumu0_rts_file),
+                           "Cumulative pure exec. times","Number of threads",
+                          $logscale{'Cg'},
+                           $xend_cum_rts, $yend_cum0_rts,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumu0_has_file, &dat2ps_name($cumu0_has_file),
+                           "Cumulative heap allocations","Number of threads",
+                          $logscale{'Ca'},
+                           $xend_cum_has, $yend_cum0_has,"");
+                           #  $xtics_cluster_has as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumulat_fts_file_name, &dat2ps_name($cumulat_fts_file_name),
+                           "Cumulative communication times","% of threads",
+                          $logscale{'Cg'},
+                           $xend_cum_fts, $yend_cum_fts,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumu0_fts_file, &dat2ps_name($cumu0_fts_file),
+                           "Cumulative communication times","Number of threads",
+                          $logscale{'Cg'},
+                           $xend_cum_fts, $yend_cum0_fts,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumulat_cps_file_name, &dat2ps_name($cumulat_cps_file_name),
+                           "Cumulative communication percentages","% of threads",
+                          "",  # No logscale here !
+                           $xend_cum_cps, $yend_cum_cps,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_lines_record(GP_FILE,
+                           $cumu0_cps_file, &dat2ps_name($cumu0_cps_file),
+                           "Cumulative communication percentages","Number of threads",
+                          "",  # No logscale here !
+                           $xend_cum_cps, $yend_cum0_cps,""); 
+                           # $xtics_cluster_rts as last arg?
+
+  do write_gp_record(GP_FILE,
+                     $clust_rts_file_name, &dat2ps_name($clust_rts_file_name),
+                     "Pure exec. time", "No. of threads", $logscale{'CG'},
+                     $xstart_cluster_rts,$xend_cluster_rts,$max_cluster_rts,$xtics_cluster_rts);
+
+  do write_gp_record(GP_FILE,
+                     $clust_has_file_name, &dat2ps_name($clust_has_file_name),
+                     "Pure exec. time", "No. of threads", $logscale{'CA'},
+                     $xstart_cluster_has,$xend_cluster_has,$max_cluster_has,$xtics_cluster_has);
+
+  do write_gp_record(GP_FILE,
+                     $clust_fts_file_name, &dat2ps_name($clust_fts_file_name),
+                     "Communication time", "No. of threads", $logscale{'CG'},
+                     $xstart_cluster_fts,$xend_cluster_fts,$max_cluster_fts,$xtics_cluster_rts);
+
+
+  do write_gp_simple_record(GP_FILE,
+                     $pe_file_name, &dat2ps_name($pe_file_name),
+                     "Processing Elements (PEs)", "Ready Time (not running)", 
+                     $logscale{'Yp'},$xstart_pe,$xend_pe,$max_pe,$xtics_pe);
+
+  do write_gp_simple_record(GP_FILE,
+                     $sn_file_name, &dat2ps_name($sn_file_name),
+                     "Spark sites", "Pure exec. time", 
+                     $logscale{'Ys'},$xstart_sn,$xend_sn,$max_sn,$xtics_sn);
+
+  close GP_FILE;
+
+  print "Gnu plotting figures ...\n";
+  system "gnuplot $gp_file_name";
+
+  print "Extending thickness of impulses ...\n";
+  do gp_ext($gran_file_name,
+            $gran_global_file_name,
+           $gran_local_file_name,
+           $comm_file_name,
+           $comm_global_file_name,
+           $comm_local_file_name,
+           $spark_file_name,
+           $spark_local_file_name,
+           $spark_global_file_name,
+           $ha_file_name,
+           $ft_file_name,
+           $clust_fts_file_name,
+           $clust_rts_file_name,
+           $clust_has_file_name,
+            $pe_file_name,
+           $sn_file_name
+  );
+
+
+}
+
+# ----------------------------------------------------------------------------
+
+sub gp_ext {
+    local (@file_names) = @_;
+    local ($file_name);
+    local ($ps_file_name);
+    local ($prg);
+
+    #$prg = system "which gp-ext-imp";
+    #print "  Using script $prg for impuls extension\n";
+    $prg = $ENV{GRANDIR} ? $ENV{GRANDIR} . "/bin/gp-ext-imp" 
+                        : $ENV{HOME} . "/bin/gp-ext-imp" ;
+    if ( $opt_v ) {
+       print "    (using script $prg)\n";
+    }
+
+    foreach $file_name (@file_names) {
+       $ps_file_name = &dat2ps_name($file_name);
+        system "$prg -w $ext_size -g $gray " . 
+               $ps_file_name  . " " . 
+               $ps_file_name . "2" ;
+        system "mv " . $ps_file_name . "2 " . $ps_file_name;
+    }
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_gp_record {
+    local ($file,$in_file,$out_file,$xlabel,$ylabel,$logaxes,
+           $xstart,$xend,$ymax,$xtics) = @_;
+
+    if ( $xstart >= $xend ) {
+       print ("WARNING: empty xrange [$xstart:$xend] changed to [$xstart:" . $xstart+1 . "]\n")        if ( $pedantic || $opt_v );
+       $xend = $xstart + 1;    
+    }
+
+    if ( $ymax <=0 ) {
+       $ymax = 2;
+       print "WARNING: empty yrange changed to [0:$ymax]\n"   if ( $pedantic || $opt_v );
+    }
+
+    $str = "set size " . $xsize . "," . $ysize . "\n" .
+           "set xlabel \"" . $xlabel . "\"\n" .
+           "set ylabel \"" . $ylabel . "\"\n" .
+           ($xstart eq "" ? "" 
+                          : "set xrange [" . int($xstart) .":" . int($xend) . "]\n") .
+           ($ymax eq "" ? "" 
+                        : "set yrange [" . (index($logaxes,"y") != -1 ? 1 : 0) . 
+                          ":" . &list_max(2,int($ymax+$ymax/5)) . "]\n") .
+           ($xtics ne "" ? "set xtics $xtics" : "") . 
+          "set tics out\n" .
+           "set border\n" .
+           "set title \"$nPEs PEs\"\n" .
+          "set nokey \n" .
+           "set nozeroaxis\n" .
+          "set format xy \"%g\"\n" .
+           (index($logaxes,"x") != -1 ? 
+               "set logscale x\n" : 
+               "set nologscale x\n") .
+           (index($logaxes,"y") != -1 ? 
+               "set logscale y\n" : 
+               "set nologscale y\n") .
+           "set output \"" . $out_file . "\"\n" .
+          "plot \"" . $in_file . "\" with impulses\n\n";
+    print $file $str;
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_gp_lines_record {
+    local ($file,$in_file,$out_file,$xlabel,$ylabel,$logaxes,
+           $xend,$yend,$xtics) = @_;
+
+    local ($str);
+
+    $str = "set xlabel \"" . $xlabel . "\"\n" .
+           "set ylabel \"" . $ylabel . "\"\n" .
+          "set xrange [" . ( index($logaxes,"x") != -1 ? 1 : 0 ) . ":$xend]\n" .
+          "set yrange [" . ( index($logaxes,"y") != -1 ? 1 : 0 ) . ":$yend]\n" .
+           "set border\n" .
+           "set nokey\n" .
+           ( $xtics ne "" ? "set xtics $xtics" : "" ) .
+           (index($logaxes,"x") != -1 ? 
+               "set logscale x\n" : 
+               "set nologscale x\n") .
+           (index($logaxes,"y") != -1 ? 
+               "set logscale y\n" : 
+               "set nologscale y\n") .
+           "set nozeroaxis\n" .
+          "set format xy \"%g\"\n" .
+           "set output \"" . $out_file . "\"\n" .
+          "plot \"" . $in_file . "\" with lines\n\n";
+    print $file $str;
+}
+
+
+# ----------------------------------------------------------------------------
+
+sub write_gp_simple_record {
+    local ($file,$in_file,$out_file,$xlabel,$ylabel,$logaxes,
+           $xstart,$xend,$ymax,$xtics) = @_;
+
+    $str = "set size " . $xsize . "," . $ysize . "\n" .
+           "set xlabel \"" . $xlabel . "\"\n" .
+           "set ylabel \"" . $ylabel . "\"\n" .
+           ($xstart eq "" ? "" 
+                          : "set xrange [" . int($xstart) .":" . int($xend) . "]\n") .
+           ($ymax eq "" ? "" 
+                        : "set yrange [" . (index($logaxes,"y") != -1 ? 1 : 0) . 
+                          ":" . &list_max(2,int($ymax+$ymax/5)) . "]\n") .
+           ($xtics ne "" ? "set xtics $xtics" : "") . 
+           "set border\n" .
+           "set nokey\n" .
+          "set tics out\n" .
+           "set nozeroaxis\n" .
+          "set format xy \"%g\"\n" .
+           (index($logaxes,"x") != -1 ? 
+               "set logscale x\n" : 
+               "set nologscale x\n") .
+           (index($logaxes,"y") != -1 ? 
+               "set logscale y\n" : 
+               "set nologscale y\n") .
+           "set output \"" . $out_file . "\"\n" .
+          "plot \"" . $in_file . "\" with impulses\n\n";
+    print $file $str;
+}
+
+# ----------------------------------------------------------------------------
+
+sub dat2ps_name {
+    local ($dat_name) = @_;
+
+    $dat_name =~ s/\.dat$/\.ps/;
+    return ($dat_name);
+}
+
+# ----------------------------------------------------------------------------
+
+sub range {
+    local ($open_int, $logaxes, @ints) = @_;
+
+    local ($range, $left_margin, $right_margin);
+
+    $range = $ints[$#ints]-$ints[0];
+    $left_margin = 0; # $range/10;
+    $right_margin = 0; # $range/10;
+
+    if ( $opt_D ) {
+       print "\n==> Range: logaxes are $logaxes i.e. " . 
+          (index($logaxes,"x") != -1 ? "matches x axis\n" 
+                                     : "DOESN'T match x axis\n"); 
+    }
+    if ( index($logaxes,"x") != -1 ) {
+       if ( $open_int == $OPEN_INT ) {
+           return ( ($ints[0]/2-$left_margin, 
+                     $ints[$#ints]+($ints[$#ints]-$ints[$#ints-1])/2+$right_margin) );
+       } else {
+           return ( ( &list_max(1,$ints[0]-$left_margin), 
+                      $ints[$#ints]+($ints[$#ints]-$ints[$#ints-1])/2+$right_margin) );
+       }
+    } else {
+       if ( $open_int == $OPEN_INT ) {
+           return ( ($ints[0]/2-$left_margin, 
+                     $ints[$#ints]+($ints[$#ints]-$ints[$#ints-1])/2+$right_margin) );
+       } else {
+           return ( ($ints[0]-$left_margin, 
+                     $ints[$#ints]+($ints[$#ints]-$ints[$#ints-1])/2+$right_margin) );
+       }
+    }
+}
+
+# ----------------------------------------------------------------------------
+
+sub percentify {
+    local ($sum,*classes) = @_;
+
+    for ($i=0; $i<=$#classes; $i++) {
+       $classes[$i] = (100 * $classes[$i]) / $sum;
+    }
+}
+
+# ----------------------------------------------------------------------------
+# ToDo: get these statistics functions from "stat.pl"
+# ----------------------------------------------------------------------------
+
+sub mean_std_dev {
+    local ($sum,@list) = @_;
+
+    local ($n, $s, $s_);
+
+    #print "\nmean_std_dev: sum is $sum ; list has length $#list";
+
+    $n = $#list+1;
+    $mean_value = $sum/$n;
+
+    $s_ = 0;
+    foreach $x (@list) {
+       $s_ += $x;
+        $s += ($mean_value - $x) ** 2;  
+    }
+    if ( $sum != $s_ ) {
+      print "ERROR in mean_std_dev: provided sum is wrong  " .
+            "(provided: $sum; computed: $s_)\n"; 
+      print " list_sum: " . &list_sum(@list) . "\n";
+      exit (2);
+    }
+
+    return ( ($mean_value, sqrt($s / ($n - 1)) ) );
+}
+
+# ----------------------------------------------------------------------------
+
+sub _mean_std_dev {
+    return ( &mean_std_dev(&list_sum(@_), @_) );
+}
+
+# ----------------------------------------------------------------------------
+# Compute covariance of 2 vectors, having their sums precomputed.
+# Input: $n   ... number of all elements in @list_1 as well as in @list_2
+#                 (i.e. $n = $#list_1+1 = $#list_2+1).
+#        $mean_1 ... mean value of all elements in @list_1
+#        @list_1 ... list of integers; first vector
+#        $mean_2 ... mean value of all elements in @list_2
+#        @list_2 ... list of integers; first vector
+# Output: covariance of @list_1 and @list_2 
+# ----------------------------------------------------------------------------
+
+sub cov {
+    local ($n, $mean_1, @rest) = @_;
+    local (@list_1) = splice(@rest,0,$n);
+    local ($mean_2, @list_2) = @rest;
+
+    local ($i,$s,$s_1,$s_2);
+
+    for ($i=0; $i<$n; $i++) {
+       $s_1 += $list_1[$i];
+       $s_2 += $list_2[$i];
+       $s += ($mean_1 - $list_1[$i]) * ($mean_2 - $list_2[$i]);
+    }
+    if ( $mean_1 != ($s_1/$n) ) {
+      print "ERROR in cov: provided mean value is wrong " . 
+            "(provided: $mean_1; computed: " . ($s_1/$n) . ")\n"; 
+      exit (2);
+    }
+    if ( $mean_2 != ($s_2/$n) ) {
+      print "ERROR in cov: provided mean value is wrong " .
+            "(provided: $mean_2; computed: " . ($s_2/$n) . ")\n"; 
+      exit (2);
+    }
+    return ( $s / ($n - 1) ) ;
+}
+
+# ----------------------------------------------------------------------------
+# Compute correlation of 2 vectors, having their sums precomputed.
+# Input: $n   ... number of all elements in @list_1 as well as in @list_2
+#                 (i.e. $n = $#list_1+1 = $#list_2+1).
+#        $sum_1 ... sum of all elements in @list_1
+#        @list_1 ... list of integers; first vector
+#        $sum_2 ... sum of all elements in @list_2
+#        @list_2 ... list of integers; first vector
+# Output: correlation of @list_1 and @list_2 
+# ----------------------------------------------------------------------------
+
+sub corr {
+    local ($n, $sum_1, @rest) = @_;
+    local (@list_1) = splice(@rest,0,$n);
+    local ($sum_2, @list_2) = @rest;
+       
+    local ($mean_1,$mean_2,$std_dev_1,$std_dev_2);
+
+    if ( $opt_D ) {
+      print "\ncorr: n=$n  sum_1=$sum_1  sum_2=$sum_2\n";
+      print "     list_sum of list_1=" . &list_sum(@list_1) . 
+              "   list_sum of list_2=" . &list_sum(@list_2) . "\n";
+      print "     len of list_1=$#list_1  len of list_2=$#list_2\n";
+    }
+
+    ($mean_1, $std_dev_1) = &mean_std_dev($sum_1,@list_1);
+    ($mean_2, $std_dev_2) = &mean_std_dev($sum_2,@list_2);
+
+    if ( $opt_D ) {
+      print "corr: $mean_1, $std_dev_1; $mean_2, $std_dev_2\n";
+    }
+
+    return ( ($std_dev_1 * $std_dev_2) == 0  ?
+               0 : 
+               &cov($n, $mean_1, @list_1, $mean_2, @list_2) / 
+              ( $std_dev_1 * $std_dev_2 ) );
+}
+
+# ----------------------------------------------------------------------------
+
+sub list_sum {
+    local (@list) = @_;
+
+    local ($sum);
+
+    foreach $x (@list) {
+       $sum += $x;
+    }
+
+    return ($sum);
+}
+
+# ----------------------------------------------------------------------------
+
+sub list_max {
+    local (@list) = @_;
+
+    local ($max) = shift;
+
+    foreach $x (@list) {
+       $max = $x  if $x > $max;
+    }
+
+    return ($max);
+}
+
+# ----------------------------------------------------------------------------
+
+sub list_min {
+    local (@list) = @_;
+
+    local ($min) = shift;
+
+    foreach $x (@list) {
+       $min = $x  if $x < $min;
+    }
+
+    return ($min);
+}
+
+# ----------------------------------------------------------------------------
+
+sub guess_interval {
+    local (@list) = @_ ;
+
+    local ($min,$max,$sum,$mean,$std_dev,@intervals);
+
+    $min = &list_min(@list);
+    $max = &list_max(@list);
+    $sum = &list_sum(@list);
+    ($mean, $std_dev) = &mean_std_dev($sum,@list);
+
+    @intervals = (int($mean-$std_dev),int($mean-$std_dev/2),int($mean),
+                  int($mean+$std_dev/2),int($mean+$std_dev));
+
+    while ($#intervals>=0 && $intervals[0]<0) {
+       shift(@intervals);
+    }
+
+    return (@intervals);
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_interval {
+    local ($file,$flag,@intervals) = @_;
+
+    printf $file "$flag: (" . join(", ",@intervals) . ")\n";
+}
+# ----------------------------------------------------------------------------
+
+sub read_template {
+
+    if ( $opt_v ) {
+       print "Reading settings from template file $templ_file_name ...\n";
+    }
+
+    open(TEMPLATE,$templ_file_name) || die "Couldn't open file $templ_file_name";
+    while (<TEMPLATE>) {
+      next if /^\s*$/ || /^--/;
+      if (/^\s*G[:,;.\s]+([^\n]+)$/) {
+         $list_str = $1;
+          $list_str =~ s/[\(\)\[\]]//g;
+          @exec_times = split(/[,;. ]+/, $list_str);
+      } elsif (/^\s*F[:,;.\s]+([^\n]+)$/) {
+         $list_str = $1;
+          $list_str =~ s/[\(\)\[\]]//g;
+          @fetch_times = split(/[,;. ]+/, $list_str);
+      } elsif (/^\s*A[:,;.\s]+([^\n]+)$/) {
+         $list_str = $1;
+          $list_str =~ s/[\(\)\[\]]//g;
+          @has = split(/[,;. ]+/, $list_str);
+      } elsif (/^\s*C[:,;.\s]+([^\n]+)$/) {
+         $list_str = $1;
+          $list_str =~ s/[\(\)\[\]]//g;
+          @comm_percs = split(/[,;. ]+/, $list_str);
+      } elsif (/^\s*S[:,;.\s]+([^\n]+)$/) {
+         $list_str = $1;
+          $list_str =~ s/[\(\)\[\]]//g;
+          @sparks = split(/[,;. ]+/, $list_str);
+      } elsif (/^\s*g[:,;.\s]+([\S]+)$/) {
+         ($gran_file_name,$gran_global_file_name, $gran_local_file_name) = 
+           &mk_global_local_names($1);
+      } elsif (/^\s*f[:,;.\s]+([\S]+)$/) {
+         ($ft_file_name,$ft_global_file_name, $ft_local_file_name) = 
+           &mk_global_local_names($1);
+      } elsif (/^\s*c[:,;.\s]+([\S]+)$/) {
+         ($comm_file_name, $comm_global_file_name, $comm_local_file_name) = 
+           &mk_global_local_names($1);
+      } elsif (/^\s*s[:,;.\s]+([\S]+)$/) {
+         ($spark_file_name, $spark_global_file_name, $spark_local_file_name) = 
+           &mk_global_local_names($1);
+      } elsif (/^\s*a[:,;.\s]+([\S]+)$/) {
+         ($ha_file_name, $ha_global_file_name, $ha_local_file_name) = 
+           &mk_global_local_names($1);
+      } elsif (/^\s*p[:,;.\s]+([\S]+)$/) {
+         $gp_file_name = $1;
+        $ps_file_name = &dat2ps_name($gp_file_name);
+
+      } elsif (/^\s*Xcorr[:,;.\s]+([\S]+)$/) {
+         $corr_file_name = $1;
+      } elsif (/^\s*Xcumulat-rts[:,;.\s]+([\S]+)$/) {
+         $cumulat_rts_file_name = $1;
+      } elsif (/^\s*Xcumulat-has[:,;.\s]+([\S]+)$/) {
+         $cumulat_has_file_name = $1;
+      } elsif (/^\s*Xcumulat-fts[:,;.\s]+([\S]+)$/) {
+         $cumulat_fts_file_name = $1;
+      } elsif (/^\s*Xcumulat-cps[:,;.\s]+([\S]+)$/) {
+         $cumulat_cps_file_name = $1;
+      } elsif (/^\s*Xclust-rts[:,;.\s]+([\S]+)$/) {
+         $clust_rts_file_name = $1;
+      } elsif (/^\s*Xclust-has[:,;.\s]+([\S]+)$/) {
+         $clust_has_file_name = $1;
+      } elsif (/^\s*Xclust-fts[:,;.\s]+([\S]+)$/) {
+         $clust_fts_file_name = $1;
+      } elsif (/^\s*Xclust-cps[:,;.\s]+([\S]+)$/) {
+         $clust_cps_file_name = $1;
+      } elsif (/^\s*Xpe[:,;.\s]+([\S]+)$/) {
+         $pe_file_name = $1;
+      } elsif (/^\s*Xsn[:,;.\s]+([\S]+)$/) {
+         $sn_file_name = $1;
+
+      } elsif (/^\s*XRTS[:,;.\s]+([\S]+)$/) {
+         $rts_file_name = $1;
+      } elsif (/^\s*XHAS[:,;.\s]+([\S]+)$/) {
+         $has_file_name = $1;
+      } elsif (/^\s*XFTS[:,;.\s]+([\S]+)$/) {
+         $fts_file_name = $1;
+      } elsif (/^\s*XLSPS[:,;.\s]+([\S]+)$/) {
+         $lsps_file_name = $1;
+      } elsif (/^\s*XGSPS[:,;.\s]+([\S]+)$/) {
+         $gsps_file_name = $1;
+      } elsif (/^\s*XCPS[:,;.\s]+([\S]+)$/) {
+         $cps_file_name = $1;
+      } elsif (/^\s*XCCPS[:,;.\s]+([\S]+)$/) {
+         $ccps_file_name = $1;
+
+      } elsif (/^\s*\-[:,;.\s]+([\S]+)$/) {
+         $input = $1;
+      } elsif (/^\s*L[:,;\s]+(.*)$/) {
+        $str = $1;
+        %logscale = ('g',"xy",'a',"xy",'Cg',"xy",'Ca',"xy",'Yp',"y",'Ys',"y") , next  if $str eq ".";
+         $str =~ s/[\(\)\[\]]//g;
+         %logscale = split(/[,;. ]+/, $str);
+      } elsif (/^\s*i[:,;.\s]+([\S]+)$/) {
+        $gray = $1;
+      } elsif (/^\s*k[:,;.\s]+([\S]+)$/) {
+        $no_of_clusters = $1;
+      } elsif (/^\s*e[:,;.\s]+([\S]+)$/) {
+        $ext_size = $1;
+      } elsif (/^\s*v.*$/) {
+        $verbose = 1;
+      } elsif (/^\s*T.*$/) {
+        $opt_T = 1;
+      } elsif (/^\s*m.*$/) {
+        $opt_m = 1;
+     }
+  }
+  close(TEMPLATE);
+}      
+
+# ----------------------------------------------------------------------------
+
+sub mk_global_local_names { 
+    local ($file_name) = @_;
+
+    $file_name .= ".dat" unless $file_name =~ /\.dat$/;
+    $global_file_name = $file_name; 
+    $global_file_name =~ s/\.dat/\-global\.dat/ ;
+    $local_file_name = $file_name; 
+    $local_file_name =~ s/\.dat/\-local\.dat/ ;
+
+    return ( ($file_name, $global_file_name, $local_file_name) );
+}
+
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+
+sub pre_process {
+    local ($lines) = @_;
+
+    local (@all_rts, @all_comm_percs, @all_sparks, @all_local_sparks, 
+           @all_global_sparks, @all_has, @fields,
+           $line_no, $elem, $total_rt, $comm_perc,
+           $pe, $start, $end, $is_global, $bbs, $ha, $rt, $bt, $ft, 
+           $lsp, $gsp, $my);
+
+    if ( $opt_v ) {
+       print "Preprocessing file $input ... \n";
+    }
+
+    open(INPUT,"<$input") || die "Couldn't open input file $input";
+
+    do skip_header();
+
+    $line_no = 0;
+    while (<INPUT>) {
+       $line_no++;
+       last  if $line_no > $lines;
+       
+       @fields = split(/,/,$_);
+       
+       foreach $elem (@fields) {
+           foo : {
+               $pe = $1        , last foo   if $elem =~ /^\s*PE\s+(\d+).*$/;
+               $start = $1     , last foo   if $elem =~ /^\s*ST\s+(\d+).*$/;
+               $end = $1       , last foo   if $elem =~ /^\s*END\s+(\d+).*$/;
+               $is_global = $1 , last foo   if $elem =~ /^\s*GBL\s+(T|F).*$/;
+               $bbs = $1       , last foo   if $elem =~ /^\s*BB\s+(\d+).*$/;
+               $ha = $1        , last foo   if $elem =~ /^\s*HA\s+(\d+).*$/;
+               $rt = $1        , last foo   if $elem =~ /^\s*RT\s+(\d+).*$/;
+               $bt = $1, $bc = $2 , last foo if $elem =~ /^\s*BT\s+(\d+)\s+\((\d+)\).*$/;
+               $ft = $1, $fc = $2 , last foo if $elem =~ /^\s*FT\s+(\d+)\s+\((\d+)\).*$/;
+               $lsp = $1        , last foo   if $elem =~ /^\s*LS\s+(\d+).*$/;
+               $gsp = $1        , last foo   if $elem =~ /^\s*GS\s+(\d+).*$/;
+               $my = $1        , last foo   if $elem =~ /^\s*MY\s+(T|F).*$/;
+           }
+       }
+
+       $total_rt = $end - $start;
+       $comm_perc = ( $total_rt == 0 ? 100 : (100 * $ft)/$total_rt );
+       $sp = $lsp + $gsp;
+       
+       push(@all_rts,$rt);
+       
+       push(@all_comm_percs,$comm_perc); 
+       
+       push(@all_sparks,$sp);
+       push(@all_local_sparks,$lsp);
+       push(@all_global_sparks,$gsp);
+       
+       push(@all_has,$ha);
+    }
+
+    close(INPUT);
+
+    @exec_times = &guess_interval(@all_rts);
+    @sparks     = &guess_interval(@all_sparks);
+    @has        = &guess_interval(@all_has);
+
+    ($m,$std_dev) = &_mean_std_dev(@all_comm_percs);
+    @comm_percs = (0, int($m), int($std_dev), 100)       unless int($m) == 0;
+    @comm_percs = (0, 1, 2, 5, 10, 50, 100)              if     int($m) == 0;
+}
+
+# ----------------------------------------------------------------------------
+
+sub process_options {
+    if ( $opt_h ) {                      
+       open(ME,$0) || die "Can't open myself ($0)";
+       $n = 0;
+       while (<ME>) {
+           last if $_ =~ /^$/;
+           print $_;
+           $n++;
+       }
+       close(ME);
+       
+       # system "cat $0 | awk 'BEGIN { n = 0; } \
+       #                             /^$/ { print n; \
+       #                                    exit; } \
+       #                                  { n++; }'"
+       exit ;
+    }
+
+    if ( $opt_W ) {
+       $pedantic = 1;
+    } else {
+       $pedantic = 0;
+    }
+
+    $input = $#ARGV == -1 ? "-" : $ARGV[0] ;
+    
+    if ( $#ARGV != 0 ) {
+       #print "Usage: gran-extr [options] <sim-file>\n";
+       #print "Use -h option to get details\n";
+       #exit 1;
+       
+    }
+    
+    
+    if ( ! $opt_t ) {
+       do pre_process(20);
+    }
+    
+    if ( $opt_g ) {
+       ($gran_file_name, $gran_global_file_name, $gran_local_file_name) =       
+           do mk_global_local_names($opt_g);
+    } else {
+       $gran_file_name = "gran.dat";
+       $gran_global_file_name = "gran-global.dat";
+       $gran_local_file_name = "gran-local.dat";
+    }
+    
+    if ( $opt_c ) {
+       ($comm_file_name, $comm_global_file_name, $comm_local_file_name) =       
+           do mk_global_local_names($opt_c);
+    } else {
+       $comm_file_name = "comm.dat";
+       $comm_global_file_name = "comm-global.dat";
+       $comm_local_file_name = "comm-local.dat";
+    }
+    
+    if ( $opt_f ) {
+       ($ft_file_name, $ft_global_file_name, $ft_local_file_name) =       
+           do mk_global_local_names($opt_c);
+    } else {
+       $ft_file_name = "ft.dat";
+       $ft_global_file_name = "ft-global.dat";
+       $ft_local_file_name = "ft-local.dat";
+    }
+    
+    if ( $opt_s ) {
+       ($spark_file_name, $spark_global_file_name, $spark_local_file_name) =  
+           do mk_global_local_names($opt_s);
+    } else {
+       $spark_file_name = "spark.dat";
+       $spark_global_file_name = "spark-global.dat";
+       $spark_local_file_name = "spark-local.dat";
+    }
+    
+    if ( $opt_a ) {
+       ($ha_file_name, $ha_global_file_name, $ha_local_file_name) =       
+           do mk_global_local_names($opt_a);
+    } else {
+       $ha_file_name = "ha.dat";
+    }
+    
+    if ( $opt_p ) {
+       $gp_file_name = $opt_p;
+    } else {
+       $gp_file_name = "gran.gp";
+    }
+    
+    $ps_file_name = &dat2ps_name($gp_file_name);
+    
+    $corr_file_name = "CORR";
+    $cumulat_rts_file_name = "cumulative-rts.dat";
+    $cumulat_has_file_name = "cumulative-has.dat";
+    $cumulat_fts_file_name = "cumulative-fts.dat";
+    $cumulat_cps_file_name = "cumulative-cps.dat";
+    $clust_rts_file_name = "clusters-rts.dat";
+    $clust_has_file_name = "clusters-has.dat";
+    $clust_fts_file_name = "clusters-fts.dat";
+    $clust_cps_file_name = "clusters-cps.dat";
+    $pe_file_name = "pe.dat";
+    $sn_file_name = "sn.dat";
+
+    $pie_file_name = "Pie.ps";
+
+    $cps_file_name = "CPS";
+    $fts_file_name = "FTS";
+    $rts_file_name = "RTS";
+    $has_file_name = "HAS";
+    $lsps_file_name = "LSPS";
+    $gsps_file_name = "GSPS";
+    $ccps_file_name = "CCPS";
+
+    if ( $opt_l ) {
+       $left_margin = $opt_l; 
+    } else {
+       $left_margin = 0; 
+    }
+    $left_perc_margin = 0;
+    
+    if ( $opt_r ) {
+       $right_margin = $opt_r; 
+    } else {
+       $right_margin = 0; 
+    }
+    $right_perc_margin = 0;
+    
+    if ( $opt_x ) {
+       $xsize = $opt_x;
+    } else {
+       $xsize = 1;
+    }
+    
+    if ( $opt_y ) {
+       $ysize = $opt_y;
+    } else {
+       $ysize = 1;
+    }
+    
+    if ( $opt_e ) {
+       $ext_size = $opt_e; 
+    } else {
+       $ext_size = 200; 
+    }
+    
+    if ( $opt_i ) {
+       $gray = $opt_i; 
+    } else {
+       $gray = 0; 
+    }
+    
+    if ( $opt_k ) {
+       $no_of_clusters = $opt_k; 
+    } else {
+       $no_of_clusters = 5; 
+    }
+    
+    if ( $opt_L ) {
+        $str = $opt_L;
+        $str =~ s/[\(\)\[\]]//g;
+        %logscale = split(/[,;. ]+/, $str);
+       # $logscale = $opt_L;
+    } else {
+       %logscale = ();        # ('g',"xy",'a',"xy",'Cg',"xy",'Ca',"xy");
+    }
+    
+# $delta = do compute_delta(@exec_times);
+# $no_of_exec_times = $#exec_times;
+    
+    if ( $opt_G ) {
+       $opt_G =~ s/[\(\)\[\]]//g;
+       @exec_times = split(/[,;. ]+/, $opt_G);
+       # @exec_times = split(/[,;. ]+/, ($opt_G =~ s/[\(\)]//g));
+    } else {
+       # @exec_times = (50, 100, 200, 300, 400, 500, 700);
+    }
+    
+    if ( $opt_F ) {
+       $opt_F =~ s/[\(\)\[\]]//g;
+       @fetch_times = split(/[,;. ]+/, $opt_F);
+       # @fetch_times = split(/[,;. ]+/, ($opt_F =~ s/[\(\)]//g));
+    } else {
+       # @fetch_times = (50, 100, 200, 300, 400, 500, 700);
+    }
+    
+    if ( $opt_C ) {
+       $opt_C =~ s/[\(\)\[\]]//g;
+       @comm_percs = split(/[,;. ]+/, $opt_C);
+    } else { 
+       # @comm_percs = (0,10,20,30,50,100);
+    } 
+    
+    if ( $opt_S ) {
+       $opt_S =~ s/[\(\)\[\]]//g;
+       @sparks = split(/[,;. ]+/, $opt_S);
+    } else { 
+       # @sparks = (0,5,10,50);
+    } 
+    
+# $delta_comm = do compute_delta(@comm_percs);
+    
+    if ( $opt_A ) {
+       $opt_A =~ s/[\(\)\[\]]//g;
+       @has = split(/[,;. ]+/, $opt_A);
+    } else {
+       # @has = (10, 100, 200, 300, 500, 1000);
+    }
+    
+    if ( $opt_t ) {
+       $templ_file_name = ( $opt_t eq '.' ? "TEMPL"     #   default file name
+                            : $opt_t eq ',' ? "/users/fp/hwloidl/grasp/GrAn/bin/TEMPL"     #   global master template
+                            : $opt_t eq '/' ? "/users/fp/hwloidl/grasp/GrAn/bin/T0"     #   template, that throws away most of the info
+                             : $opt_t ); 
+       do read_template();
+       # see RTS2gran for use of template-package
+    }
+    
+    $ylabel = $opt_P ? "% of threads" : "No. of threads";
+}  
+
+# ----------------------------------------------------------------------------
+
+sub print_verbose_message { 
+
+    print "-" x 70 . "\n";
+    print "Setup: \n";
+    print "-" x 70 . "\n";
+    print "\nFilenames: \n";
+    print "  Input file: $input\n";
+    print "  Gran files: $gran_file_name $gran_global_file_name $gran_local_file_name\n"; 
+    print "  Comm files: $comm_file_name $comm_global_file_name $comm_local_file_name\n";
+    print "  Sparked threads file: $spark_file_name $spark_local_file_name $spark_global_file_name\n";
+    print "  Heap file: $ha_file_name\n";
+    print "  GNUPLOT file name: $gp_file_name   Correlation file name: $corr_file_name\n";
+    print "  Cumulative RT file name: $cumulat_rts_file_name   \n  Cumulative HA file name: $cumulat_has_file_name\n";
+    print "  Cluster RT file name: $clust_rts_file_name   \n  Cluster HA file name: $clust_has_file_name\n";
+    print "  Cumulative runtimes file name:    $cumulat_rts_file_name\n";
+    print "  Cumulative heap allocations file name   $cumulat_has_file_name\n";
+    print "  Cluster run times file name:    $clust_rts_file_name\n";
+    print "  Cluster heap allocations file name:    $clust_has_file_name\n";
+    print "  PE load file name:    $pe_file_name\n";
+    print "  Site size file name:    $sn_file_name\n";
+    print "\nBoundaries: \n";
+    print "  Gran boundaries: @exec_times\n";
+    print "  Comm boundaries: @comm_percs\n";
+    print "  Sparked threads boundaries: @sparks\n";
+    print "  Heap boundaries: @has\n";
+    print "\nOther pars: \n";
+    print "  Left margin: $left_margin  Right margin: $right_margin\n";
+    print "  GP-extension: $ext_size  GP xsize: $xsize  GP ysize: $ysize\n";
+    print "  Gray scale: $gray  Smart x-tics is " . ($opt_T ? "ON" : "OFF") .
+         "  Percentage y-axis is " . ($opt_P ? "ON" : "OFF") . "\n";
+    print "  Log. scaling assoc list: ";
+    while (($key,$value) = each %logscale) {
+        print "$key: $value, ";
+    }
+    print "\n";
+    print "  Active template file: $templ_file\n"              if $opt_t;  
+    print "-" x 70 . "\n";
+}
+
+# ----------------------------------------------------------------------------
+
+sub sort_and_cum {
+
+@sorted_rts = sort {$a <=> $b} @all_rts;
+
+($xstart_cluster_rts,$xend_cluster_rts,$max_cluster_rts,$xtics_cluster_rts) =
+  &write_cumulative_data($cumulat_rts_file_name,$clust_rts_file_name,@sorted_rts);
+
+$xend_cum_rts = pop(@sorted_rts);
+$yend_cum_rts = 100;
+$yend_cum0_rts = $#sorted_rts+1;         # unpercentified cum graph
+
+open(RTS,">$rts_file_name") || die "$rts_file_name: $!";
+print RTS "Sorted list of all runtimes:\n";
+print RTS join("\n",@sorted_rts);
+close(RTS);
+
+@sorted_has = sort {$a <=> $b} @all_has;
+
+($xstart_cluster_has,$xend_cluster_has,$max_cluster_has,$xtics_cluster_has) =
+  &write_cumulative_data($cumulat_has_file_name,$clust_has_file_name,@sorted_has);
+
+$xend_cum_has = pop(@sorted_has);
+$yend_cum_has = 100;
+$yend_cum0_has = $#sorted_has+1;         # unpercentified cum graph
+
+open(HAS,">$has_file_name") || die "$has_file_name: $!";
+print HAS "Sorted list of all heap allocations:\n";
+print HAS join("\n",@sorted_has);
+close(HAS);
+
+@sorted_lsps = sort {$a <=> $b} @all_local_sparks;
+
+open(LSPS,">$lsps_file_name") || die "$lsps_file_name: $!";
+print LSPS "Sorted list of all local sparks:\n";
+print LSPS join("\n",@sorted_lsps);
+close(LSPS);
+
+@sorted_gsps = sort {$a <=> $b} @all_global_sparks;
+
+open(GSPS,">$gsps_file_name") || die "$gsps_file_name: $!";
+print GSPS "Sorted list of all global sparks:\n";
+print GSPS join("\n",@sorted_gsps);
+close(GSPS);
+
+@sorted_fts = sort {$a <=> $b} @all_fts;
+
+($xstart_cluster_fts,$xend_cluster_fts,$max_cluster_fts,$xtics_cluster_fts) =
+  &write_cumulative_data($cumulat_fts_file_name,$clust_fts_file_name,@sorted_fts);
+
+$xend_cum_fts = pop(@sorted_fts);
+$yend_cum_fts = 100;
+$yend_cum0_fts = $#sorted_fts+1;         # unpercentified cum graph
+
+open(FTS,">$fts_file_name") || die "$FTS_file_name: $!";
+print FTS "Sorted list of all communication times:\n";
+print FTS join("\n",@sorted_fts);
+close(FTS);
+
+@sorted_comm_percs = sort {$a <=> $b} @all_comm_percs;
+
+($xstart_cluster_cps,$xend_cluster_cps,$max_cluster_cps,$xtics_cluster_cps) =
+  &write_cumulative_data($cumulat_cps_file_name,$clust_cps_file_name,@sorted_comm_percs);
+
+$xend_cum_cps = 100;  # pop(@sorted_comm_percs);
+$yend_cum_cps = 100;
+$yend_cum0_cps = $#sorted_comm_percs+1;         # unpercentified cum graph
+
+open(CCPS,">$ccps_file_name") || die "$ccps_file_name: $!";
+print CCPS "Sorted list of all communication percentages:\n";
+print CCPS join("\n",@sorted_comm_percs);
+close(CCPS);
+
+($xstart_pe,$xend_pe,$max_pe,$xtics_pe) =
+    &write_array($pe_file_name,$#pe_load,@pe_load);
+
+($xstart_sn,$xend_sn,$max_sn,$xtics_sn) =
+    &write_array($sn_file_name,$#site_size,@site_size);
+
+if ( $opt_D ) {
+  print "After write_array: xstart, xend, max _sn: $xstart_sn,$xend_sn,$max_sn,$xtics_sn\n";
+} 
+}
+
+# ----------------------------------------------------------------------------
+# Compute statistical values (like mean, std_dev and especially corr coeff).
+# Write the important info to a file.
+# ----------------------------------------------------------------------------
+
+sub do_statistics {
+    local ($n) = @_;
+
+    if ( $n <= 1 ) {
+       print "Sorry, no statistics for just $n threads\n";
+        return -1;
+    }
+
+# Compute mean values and std deviations
+# ......................................
+    
+    ($mean_rt,$std_dev_rt) = &mean_std_dev($sum_rt,@all_rts);
+    ($mean_comm_perc,$std_dev_comm_perc) = &mean_std_dev($sum_comm_perc,@all_comm_percs);
+    ($mean_spark,$std_dev_spark) = &mean_std_dev($sum_sp,@all_sparks);
+    ($mean_local_spark,$std_dev_local_spark) = &mean_std_dev($sum_local_sp,@all_local_sparks);
+    ($mean_global_spark,$std_dev_global_spark) = &mean_std_dev($sum_global_sp,@all_global_sparks);
+    ($mean_ha,$std_dev_ha) = &mean_std_dev($sum_ha,@all_has);
+    ($mean_ft,$std_dev_ft) = &mean_std_dev($sum_ft,@all_fts);
+    
+# Compute correlation coefficients
+# ................................
+    
+    $c_exec_ha = &corr($#all_rts+1,$sum_rt,@all_rts,$sum_ha,@all_has);
+    $c_exec_sp = &corr($#all_rts+1,$sum_rt,@all_rts,$sum_sp,@all_sparks);
+    $c_exec_lsp = &corr($#all_rts+1,$sum_rt,@all_rts,$sum_local_sp,@all_local_sparks);
+    $c_exec_gsp = &corr($#all_rts+1,$sum_rt,@all_rts,$sum_global_sp,@all_global_sparks);
+    $c_ha_sp   = &corr($#all_has+1,$sum_ha,@all_has,$sum_sp,@all_sparks);
+    $c_ha_lsp   = &corr($#all_has+1,$sum_ha,@all_has,$sum_local_sp,@all_local_sparks);
+    $c_ha_gsp   = &corr($#all_has+1,$sum_ha,@all_has,$sum_global_sp,@all_global_sparks);
+    $c_exec_ft = &corr($#all_rts+1,$sum_rt,@all_rts,$sum_ft,@all_fts);
+    $c_ha_ft = &corr($#all_has+1,$sum_ha,@all_has,$sum_ft,@all_fts);
+    $c_lsp_ft = &corr($#all_local_sparks+1,$sum_local_sp,@all_local_sparks,$sum_ft,@all_fts);
+    $c_gsp_ft = &corr($#all_global_sparks+1,$sum_global_sp,@all_global_sparks,$sum_ft,@all_fts);
+    
+# Write corr coeffs into a file
+# .............................
+    
+    open(CORR,">$corr_file_name") || die "Couldn't open file $corr_file_name\n";
+    #printf CORR ("%f\n%f\n%f\n%f\n%f",$c_exec_ha,$c_exec_lsp,$c_exec_gsp,$c_ha_lsp,$c_ha_gsp)   ;
+    printf CORR ("CORR of runtime and heap alloc:  %f\n",$c_exec_ha);
+    printf CORR ("CORR of runtime and no. of sparks:  %f\n",$c_exec_sp);
+    printf CORR ("CORR of heap alloc and no. sparks:  %f\n",$c_ha_sp);
+    printf CORR ("CORR of runtime and no. of local sparks:  %f\n",$c_exec_lsp);
+    printf CORR ("CORR of runtime and no. of global sparks:  %f\n",$c_exec_gsp);
+    printf CORR ("CORR of heap alloc and no. local sparks:  %f\n",$c_ha_lsp);
+    printf CORR ("CORR of heap alloc and no. global sparks:  %f\n",$c_ha_gsp);
+    printf CORR ("CORR of runtime and communication time:  %f\n",$c_exec_ft);
+    printf CORR ("CORR of heap alloc and communication time:  %f\n",$c_ha_ft);
+    printf CORR ("CORR of no. of local sparks and communication time:  %f\n",$c_lsp_ft);
+    printf CORR ("CORR of no. of global sparks and communication time:  %f\n",$c_gsp_ft);
+    close(CORR);
+
+# These are needed later in the GNUPLOT files
+# ...........................................
+
+    $max_rt_class = &list_max(@exec_class);
+    $max_rt_global_class = &list_max(@exec_global_class);
+    $max_rt_local_class = &list_max(@exec_local_class);
+    $max_comm_perc_class = &list_max(@comm_class);
+    $max_comm_perc_global_class = &list_max(@comm_global_class);
+    $max_comm_perc_local_class = &list_max(@comm_local_class);
+    $max_spark_class = &list_max(@spark_class);
+    $max_spark_local_class = &list_max(@spark_local_class);
+    $max_spark_global_class = &list_max(@spark_global_class);
+    $max_ha_class = &list_max(@ha_class);
+    $max_ft_class = &list_max(@fetch_class);
+
+}
+
+# ----------------------------------------------------------------------------
+# This is written to STDOUT at the end of the file processing (before 
+# gnuplotting and such) if the verbose option is given.
+# ----------------------------------------------------------------------------
+
+sub print_general_info {
+
+    printf("\nTotal number of lines: %d\n", $line_no);
+    
+    print "\nDistribution of execution times: \n";
+    print " Intervals: " . join('|',@exec_times) . "\n";
+    print " Total: " . join('|',@exec_class) . "\n";
+    print " Global: " . join('|',@exec_global_class) . "\n";
+    print " Local: " . join('|',@exec_local_class) . "\n";
+    
+    $total=0; foreach $i (@exec_class) { $total += $i ; }
+    $global=0; foreach $i (@exec_global_class) { $global += $i ; }
+    $local=0; foreach $i (@exec_local_class) { $local += $i ; }
+    
+    print " Sum of classes (should be " . $line_no . "): " . $total .
+       "   (global/local)=(" . $global . "/" . $local . ")\n";
+    print " Mean value: $mean_rt   Std dev: $std_dev_rt\n";
+    
+    print "\nPercentage of communication: \n";
+    print " Intervals: " . join('|',@comm_percs) . "\n";
+    print " Total: " . join('|',@comm_class) . "\n";
+    print " Global: " . join('|',@comm_global_class) . "\n";
+    print " Local: " . join('|',@comm_local_class) . "\n";
+    print " Values outside closed int: Total: " . $outside .
+       " Global: " . $outside_global . " Local: " . $outside_local . "\n";
+    
+    $total=0; foreach $i (@comm_class) { $total += $i ; }
+    $global=0; foreach $i (@comm_global_class) { $global += $i ; }
+    $local=0; foreach $i (@comm_local_class) { $local += $i ; }
+    
+    print " Sum of classes (should be " . $line_no . "): " . $total .
+       "   (global/local)=(" . $global . "/" . $local . ")\n";
+    print " Mean value: $mean_comm_perc   Std dev: $std_dev_comm_perc\n";
+    
+    print "\nSparked threads: \n";
+    print " Intervals:   " . join('|',@sparks) . "\n";
+    print " Total allocs: " . join('|',@spark_class) . "\n";
+    
+    $total=0; foreach $i (@spark_class) { $total += $i ; }
+
+    print " Sum of classes (should be " . $line_no . "): " . $total . "\n";
+    print " Mean value: $mean_spark   Std dev: $std_dev_spark\n";
+    
+    print "\nHeap Allcoations: \n";
+    print " Intervals:   " . join('|',@has) . "\n";
+    print " Total allocs: " . join('|',@ha_class) . "\n";
+    
+    $total=0; foreach $i (@ha_class) { $total += $i ; }
+    
+    print " Sum of classes (should be " . $line_no . "): " . $total . "\n";
+    print " Mean value: $mean_ha   Std dev: $std_dev_ha\n";
+    print "\n";
+    print "CORRELATION between runtimes and heap allocations: $c_exec_ha \n";
+    print "CORRELATION between runtime and no. of sparks:  $c_exec_sp \n";
+    print "CORRELATION between heap alloc and no. sparks:  $c_ha_sp \n";
+    print "CORRELATION between runtimes and locally sparked threads: $c_exec_lsp \n";
+    print "CORRELATION between runtimes and globally sparked threads: $c_exec_gsp \n";
+    print "CORRELATION between heap allocations and locally sparked threads: $c_ha_lsp \n";
+    print "CORRELATION between heap allocations and globally sparked threads: $c_ha_gsp \n";
+    print "CORRELATION between runtime and communication time:  $c_exec_ft\n";
+    print "CORRELATION between heap alloc and communication time:  $c_ha_ft\n";
+    print "CORRELATION between no. of local sparks and communication time:  $c_lsp_ft\n";
+    print "CORRELATION between no. of global sparks and communication time:  $c_gsp_ft\n";
+    print "\n";
+    
+}
+
+# ----------------------------------------------------------------------------
+# Old (obsolete) stuff
+# ----------------------------------------------------------------------------
+#
+#for ($index=0; 
+#     $index <= &list_max($#spark_local_class,$#spark_local_class); 
+#     $index++) {
+#    $spark_class[$index] = $spark_local_class[$index] + $spark_global_class[$index];
+#}
+#
+#for ($index=0, $sum_sp=0; 
+#     $index <= &list_max($#all_local_sparks,$#all_global_sparks); 
+#     $index++) {
+#    $all_sparks[$index] = $all_local_sparks[$index] + $all_global_sparks[$index];
+#    $sum_sp += $all_sparks[$index];
+#}
+#
+# ----------------------------------------------------------------------------
+#
+#sub compute_delta {
+#    local (@times) = @_;
+#
+#    return ($times[$#times] -  $times[$#times-1]);
+#}
+#
+# ----------------------------------------------------------------------------
+
+sub insert_elem {
+    local ($elem,$val,$n,*list1,*list2) = @_;
+    local (@small_part, $i, $len);
+
+    if ( $opt_D ) {
+       print "Inserting val $val (with elem $elem) in the following list: \n" .
+               @list . "\n yields the lists: \n  ";
+    }
+
+    for ($i=0; $i<=$#list2 && $list2[$i]>$val; $i++) { }
+    $len = $#list2 - $i + 1;
+    if ( $len == 0 ) {
+       push(@list1,$elem);
+       push(@list2,$val);
+    } else {
+       splice(@list1,$i,0,$elem);
+       splice(@list2,$i,0,$val);
+    }
+
+    if ( $opt_D ) {
+       print @list1 . "\n and \n" . @list2;
+    }
+
+}
+
+# ----------------------------------------------------------------------------
+
+sub skip_header {
+    local ($in_header);
+
+    $in_header = 9;
+    while (<INPUT>) {
+       if ( $in_header = 9 ) {
+           if (/^=/) {
+               $gum_style_gr = 1;
+               $in_header = 0;
+               $prg = "????";          # 
+               $pars = "-b??????";             # 
+               $nPEs =  1; # 
+               $lat =  1;
+               return ($prg, $pars, $nPEs, $lat);
+           } else {
+               $gum_style_gr = 0;
+               $in_header = 1;
+           }
+           
+       }
+       $prg = $1, $pars = $2  if /^Granularity Simulation for\s+(\w+)\s+(.*)$/;
+       $nPEs = $1             if /^PEs\s+(\d+)/;
+       $lat = $1, $fetch = $2 if /^Latency\s+(\d+)[^F]+Fetch\s+(\d+)/;
+
+       last             if /^\+\+\+\+\+/;
+    }
+}
+
+# ----------------------------------------------------------------------------
+
+sub write_pie_chart {
+    local ($rt_perc, $bt_perc, $ft_perc, $it_perc);
+    local ($title, $title_sz, $label_sz, $x_center, $y_center, $radius); 
+
+    $PieChart = "/users/fp/hwloidl/grasp/GrAn/bin/PieChart.ps";
+
+    $title = "Original Glaswegian Communication Pie (tm)";
+    $title_sz = 24;
+    $label_sz = 12;
+    $x_center = 300; 
+    $y_center = 400;
+    $radius = 100;
+
+    open(PIE,">$pie_file_name") || die "$pie_file_name: $!";
+    
+    print PIE "%!PS-Adobe-2.0\n";
+    print PIE "%%Title: Pie Chart\n";
+    print PIE "%%Creator: gran-extr\n";
+    print PIE "%%CreationDate: Ides of March 44 B.C.\n";
+    print PIE "%%EndComments\n";
+    print PIE "\n";
+    print PIE "% Def of PieChart is taken from:\n";
+    print PIE "% ($PieChart) run\n";
+    print PIE "\n";
+
+    open(PIE_CHART,"<$PieChart") || die "$PieChart: $!";
+    while (<PIE_CHART>){
+       print PIE $_;
+    }
+    close (PIE_CHART);
+    print PIE "\n";
+
+    $rt_perc = $tot_rt / $tot_total_rt;
+    $bt_perc = $tot_bt / $tot_total_rt;
+    $ft_perc = $tot_ft / $tot_total_rt;
+    $it_perc = $tot_it / $tot_total_rt;
+
+    print PIE "($title) $title_sz $label_sz  % Title, title size and label size\n" .
+             "[                     % PS Array of (descrition, percentage [0, .., 1])\n" .
+             "[(Run Time) $rt_perc]\n" .
+             "[(Block Time) $bt_perc]\n" .
+             "[(Fetch Time) $ft_perc]\n" .
+             "[(Ready Time) $it_perc]\n" .
+             "] $x_center $y_center $radius DrawPieChart\n";
+    print PIE "showpage\n";
+
+    close(PIE);
+}
+
+# ----------------------------------------------------------------------------
+
+sub basename {
+    local ($in_str) = @_;
+    local ($str,$i) ;
+
+    $i = rindex($in_str,"/");
+    if ($i == -1) {
+       $str = $in_str;
+    } else {
+       $str = substr($in_str,$i+1) ;
+    }
+
+    return $str;
+}
+
+# ----------------------------------------------------------------------------
+
+sub dirname {
+    local ($in_str) = @_;
+    local ($str,$i) ;
+
+    $i = rindex($in_str,"/");
+    if ($i == -1) {
+       $str = "";
+    } else {
+       $str = substr($in_str,0,$i+1) ;
+    }
+
+    return $str;
+}
+
+# ----------------------------------------------------------------------------
+