#! @PERL@
# -*- Mode: perl; -*-
#
# In Progress script to make the default log files more readable.
# This indents the routine enter/exit lines, and applies that indent to
# other lines.  It also simplifies the lines, removing all but the message
# and location (and computing the time within each function)
# 
# Set defaults
my $whichrank = -1;
my $filenameTrim = "default";
my %elideCall = ();
my $infile = "";
my $isThreaded = 1;
my $onlyRoutine = 0;

for (@ARGV) {
    if (/^--?rank=(\d+)/) {
	$whichrank = $1;
    }
    elsif (/^--?srcdir=(.*)/) {
	$filenameTrim = $1;
    }
    elsif (/^--?elide=(.*)/) {
	# This must exactly match the function name recorded
	$elideCall{$1} = 1;
	$elideCall{"MPID_STATE_$1"} = 1;
    }
    elsif (/^-/) {
	print STDERR 
	    "getfuncstack [ -rank=n ] [-srcdir=path] [-elide=name] < logfile\n";
	exit(1);
    }
    else {
	$infile = $_;
	break;
    }
}

@ARGV = ();

# Set initial values
my $linecount = 0;
my $nestlevel = 0;
my $curstate  = "";
my @routineStack = ();
my @routineTime = ();
my $inElide  = 0;

while (<>) {
    my $spaces = "";
    my $tottime = "";
    my $extraMsg = "";
    $linecount++;
    ($world,$rank,$thread,$class,$time,$file,$line,$msg) = split( /\t/, $_ );

#    # Check for validity
#    Removed for now - best to use on separate file output
#    if ((!$isThreaded && $thread != 0) || $class < 0) {
#	# These should really be checks for is-int as well
#	next;
#    }

    # Discard unwanted ranks
    if ($whichrank >= 0 && ($rank != $whichrank || $world > 0) ) { next; }

    # Automatically choose the default filename trim
    if ($filenameTrim eq "default") {
	$filenameTrim = $file;
	$filenameTrim =~ s/(.*\/mpich2[^\/]*\/src\/).*/\1/;
    }
    if ($filenameTrim ne "" && $file =~ /^$filenameTrim/) {
	$file =~ s/^$filenameTrim//;
    }

    # Update nesting level
    if ($msg =~ /^Entering (.*)/) { 
	$curstate = $1; 
	if (defined($elideCall{$curstate})) {
	    $inElide = 1;
        }
	elsif (!$inElide) {
	    $spaces = &indent($nestlevel++) . ">"; 
  	    $routineStack[$#routineStack+1] = $curstate;
  	    $routineTime[$#routineTime+1]   = $time;
	}
    }
    elsif ($msg =~ /^Leaving (.*)/) { 
	$curstate = $1;
	if ($nestlevel > 0) {
	    if (defined($elideCall{$curstate})) {
		$inElide = 0;
	    }
	    elsif (!$inElide) {
		$spaces = &indent(--$nestlevel) . "<"; 
		my $expected = $routineStack[$#routineStack];
		$#routineStack--;
		if ($expected ne $curstate) {
		    print STDERR "Expected state $expected but found $curstate\n";
		}
		# Get the total time in this routine
		$tottime = $time - $routineTime[$#routineTime];
		$#routineTime--;
		# Round totaltime to a few digits
		$tottime = sprintf("%.3g",$tottime);
		$tottime = "($tottime)";
	    }
	}
    }
    else {
	if ($onlyRoutine) {
	    print STDERR "Malformed line $linecount: $_"; 
	    next;
	}
	$spaces = &indent($nestlevel);
	$extraMsg = $msg;
	$extraMsg =~ s/\r?\n//;
    }

    # Strip common text off of state
    $curstate =~ s/^MPID_STATE_//;
    $curstate =~ s/\r?\n//g;
    
    if (! $inElide) {
	my $baseinfo = $spaces;
	if ($extraMsg ne "") {
	    $baseinfo .= $extraMsg;
	}
	else {
	    $baseinfo .= $curstate . "$tottime";
	}
	my $location = "$file\[$line\]";
	my $pad = 40 - length($baseinfo);
	for (my $i=0; $i<$pad; $i++) { $baseinfo .= " "; }
	print "$baseinfo $location\n";
    }
}

sub indent {
    my $num = $_[0];
    my $spaces = "";
    for (my $i=0; $i<=$num; $i++) {
	$spaces .= " ";
    }
    return $spaces;
}

