#! /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 () { 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 () { 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";