#!/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;
}

# ----------------------------------------------------------------------------

