#! /usr/bin/env perl
use File::Find;
%states = ();
# Find all the source and header files and parse the states.
find sub
{
if ($File::Find::name =~ /\.[ich]$/)
{
%local_states = ();
$line_no = 1;
$previous_line_no = 1;
$filename = $File::Find::name;
#printf("opening $_\n");
open (F, "$_") or die "unable to open $_";
while (<F>)
{
chomp;
if (/STATE_DECL\((.+)\)/)
{
if (!/^#\s*define/)
{
if ($local_states{$1} eq "declared")
{
printf("$filename:$previous_line_no:$line_no\n");
printf("ERROR: no FUNC_ENTER/EXIT for declared state '$1'\n");
}
# if ($local_states{$1} eq "entered")
# {
# # This actually could be a nested state declaration of the same name.
# printf("$filename:$line_no\n");
# printf("ERROR: no FUNC_EXIT for state '$1'\n");
# }
#printf("state declared: $1\n");
if (/\s+\\\s*/)
{
# Assume that if the declared state is in a macro then it will be correctly entered and exited.
# Otherwise it is too hard to parse the file.
$local_states{$1} = "exited";
}
else
{
$local_states{$1} = "declared";
}
$previous_line_no = $line_no;
}
}
if (/FUNC_ENTER.*\((.+)\)/)
{
if ( (!/^#\s*define/) && (!/\s+\\\s*/) )
{
if ($local_states{$1} eq "declared")
{
#printf("state entered: '$1'\n");
$local_states{$1} = "entered";
}
else
{
if (!defined($local_states{$1}))
{
printf("$filename:$line_no\n");
printf("ERROR: FUNC_ENTER for undefined state '$1'\n");
}
if ($local_states{$1} eq "entered")
{
printf("$filename:$line_no\n");
printf("ERROR: FUNC_ENTER repeated for state '$1'\n");
}
# if ($local_states{$1} eq "exited")
# {
# printf("$filename:$line_no\n");
# printf("Warning: FUNC_ENTER after FUNC_EXIT for state '$1'\n");
# }
}
}
}
if (/FUNC_EXIT.*\((.+)\)/)
{
if ( (!/^#\s*define/) && (!/\s+\\\s*/) )
{
if (($local_states{$1} eq "entered") || ($local_states{$1} eq "exited"))
{
#printf("state exited: $1\n");
$local_states{$1} = "exited";
}
else
{
if (!defined($local_states{$1}))
{
printf("$filename:$line_no\n");
printf("ERROR: FUNC_EXIT for undefined state '$1'\n");
}
if ($local_states{$1} eq "declared")
{
printf("$filename:$line_no\n");
printf("ERROR: FUNC_EXIT without FUNC_ENTER for state '$1'\n");
}
}
}
}
$line_no = $line_no + 1;
}
close F;
foreach (keys(%local_states))
{
if ($local_states{$_} eq "declared")
{
printf("$filename:\n");
printf("ERROR: no FUNC_ENTER/EXIT for declared state $_\n");
}
else
{
if ($local_states{$_} eq "entered")
{
printf("$filename:\n");
printf("ERROR: FUNC_ENTER without FUNC_EXIT for state $_\n");
}
else
{
if (!($_ eq ""))
{
$states{$_} = "NULL";
}
}
}
}
}
}, "src";
@states = sort keys(%states);
# Remove the MPID_STATE_ prefix
foreach (@states)
{
if ( !($_ eq "") )
{
/(MPID_STATE_)(.+)/;
$display_names{"$1$2"} = "$2";
}
}
# Find all the describe_states.txt files and parse them
find sub
{
if ($_ eq "describe_states.txt")
{
open F, $_;
$line_no = 1;
while (<F>)
{
chomp;
# Check for a line with a display name and a color
/\s*(\S+)(\s+)(\S+)(\s+)(\d+)(\s+)(\d+)(\s+)(\d+).*/;
if (defined($1) && defined($2) && defined($3) && defined($4) && defined($5) && defined($6) && defined($7) && defined($8) && defined($9))
{
if (!defined($states{$1}))
{
printf("Warning1: described state '$1' not used, consider removing it from $File::Find::name:$line_no\n");
}
$display_names{$1} = "$3";
$states{$1} = "\"$5 $7 $9\"";
}
else
{
# Check for a line with just a color
/\s*(\S+)(\s+)(\d+)(\s+)(\d+)(\s+)(\d+).*/;
if (defined($1) && defined($2) && defined($3) && defined($4) && defined($5) && defined($6) && defined($7))
{
if (!defined($states{$1}))
{
printf("Warning2: described state '$1' not used, consider removing it from $File::Find::name:$line_no\n");
}
$states{$1} = "\"$3 $5 $7\"";
}
else
{
# Check for a line with just a display name
/\s*(\S+)(\s+)(\S+).*/;
if (defined($1) && defined($2) && defined($3))
{
if (!defined($states{$1}))
{
printf("Warning3: described state '$1' not used, consider removing it from $File::Find::name:$line_no\n");
}
$display_names{$1} = "$3";
}
}
}
$line_no = $line_no + 1;
}
close F;
}
}, "src";
# FIXME: It would be better to assemble this from just the relevant
# modules, rather than all files. A directory-based approach, such as
# that from extractstrings, could be used.
#
open HFILE, ">src/include/mpiallstates.h"
or die "Unable to open src/include/mpiallstates.h";
print HFILE "/* -*- Mode: C; c-basic-offset:4 ; -*- */\n";
print HFILE "/*\n";
print HFILE " * (C) 2001 by Argonne National Laboratory.\n";
print HFILE " * See COPYRIGHT in top-level directory.\n";
print HFILE " */\n";
print HFILE "\n";
print HFILE "/* automatically generated by maint/genstates */\n";
print HFILE "\n";
print HFILE "#ifndef MPIALLSTATES_H_INCLUDED\n";
print HFILE "#define MPIALLSTATES_H_INCLUDED\n";
print HFILE "\n";
print HFILE "/* Insert all the states to be logged here */\n";
print HFILE "\n";
print HFILE "enum MPID_TIMER_STATE\n";
print HFILE "{\n";
foreach (@states)
{
if ( !($_ eq "") )
{
print HFILE "$_,\n";
}
}
print HFILE "MPID_NUM_TIMER_STATES\n";
print HFILE "};\n";
print HFILE "\n";
print HFILE "#endif\n";
close HFILE;
# FIXME: This is RLOG specific and should be placed in the appropriate
# RLOG directory, not common.
# FIXME: It would also make more sense for the RLOG_Describe_state routine
# to perform the random color assignement when provided with an empty
# or null color string, rather than including all of this code in what is
# otherwise an RLOG-specific file.
open F, ">src/util/logging/common/describe_states.c"
or die "Unable to open src/util/logging/common/describe_states.c";
print F "/* -*- Mode: C; c-basic-offset:4 ; -*- */\n";
print F "/*\n";
print F " * (C) 2001 by Argonne National Laboratory.\n";
print F " * See COPYRIGHT in top-level directory.\n";
print F " */\n";
print F "\n";
print F "/* automatically generated by maint/genstates */\n";
print F "\n";
print F "#include \"mpiimpl.h\"\n";
print F "\n";
print F "/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build\n";
print F " the MPI routines */\n";
print F "#ifndef MPICH_MPI_FROM_PMPI\n";
print F "\n";
print F "#ifdef HAVE_TIMING\n";
print F "\n";
print F "#if (USE_LOGGING == MPID_LOGGING_RLOG)\n";
print F "\n";
print F "int MPIR_Describe_timer_states()\n";
print F "{\n";
print F "\n";
foreach (@states)
{
if ( !($_ eq "") )
{
print F " RLOG_DescribeState(g_pRLOG, $_, \"$display_names{$_}\", $states{$_});\n";
}
}
print F " return 0;\n";
print F "}\n";
print F "\n";
print F "#endif /* USE_LOGGING == MPID_LOGGING_RLOG */\n";
print F "#endif /* HAVE_TIMING */\n";
print F "#endif /* MPICH_MPI_FROM_PMPI */\n";