Skip to content

Commit

Permalink
#900 pmpi- update generators to handle tracing
Browse files Browse the repository at this point in the history
- Splits generators into smaller pieces and prepares
  for future work.

- Wrappers generate collective events.
  • Loading branch information
pnstickne committed Jul 14, 2020
1 parent d0913e5 commit 49bce29
Showing 1 changed file with 158 additions and 26 deletions.
184 changes: 158 additions & 26 deletions src/vt/pmpi/generate_mpi_wrappers.pl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
die "Incorrect usage: missing parameters";
}

# MPI definitions that should always be ignored.
# The most reasonable reason for being in this list is that they do
# not exist on all platforms or are inconsitently implemented as macros, etc.
# - MPI_Aint_(add|diff) - in OpenMPI 1.10 as macros
# - MPI_File_(iwrite|iread)_(all|at_all) - missing in OpenMPI 1.10
my @never_include_patterns = qw(
MPI_Aint_(add|diff)
MPI_File_(iwrite|iread)_(all|at_all)
);

# Extract MPI function definitions.
# It's a very rudimentary extractor that relies on definitions being on one line.
sub extract_defs {
Expand Down Expand Up @@ -51,23 +61,23 @@ sub extract_defs {
});
} @deflines;

@deflines = grep {
my $name = $_->{name};
not grep { $name =~ m/^$_$/; } @never_include_patterns;
} @deflines;

return @deflines;
}

# MPI calls that can be 'safely' used without being guarded
# or are otherwise excluded due to minimal benefit, compatibility issues, etc.
# MPI calls that can be 'safely' used without being guarded.
# - Common idempotent 'get' calls
# - MPI_Aint_(add|diff) - in OpenMPI 1.10 as macros
# - MPI_File_(iwrite|iread)_(all|at_all) - missing in OpenMPI 1.10
my @no_guard_patterns = qw(
MPI_Comm_get_.*
MPI_Comm_rank
MPI_Comm_size
MPI_Get.*(?<!_accumulate)
MPI_Wtime
MPI_Wtick
MPI_Aint_(add|diff)
MPI_File_(iwrite|iread)_(all|at_all)
);

sub should_guard_call {
Expand All @@ -77,14 +87,97 @@ sub should_guard_call {
} @no_guard_patterns;
}

sub declare_event {
my ($name) = @_;
say " static vt::trace::UserEventIDType event_${name} = vt::trace::no_user_event_id;";
}

sub register_event {
my ($name) = @_;
say " event_${name} = theTrace()->registerUserEventColl(\"${name}\");";
}

sub log_event {
my ($name) = @_;
say "#if backend_check_enabled(trace_enabled)";
say " auto scopedEvent = vt::trace::TraceScopedEvent(event_${name});";
say "#endif";
}

# Special actions.
# Form is {
# include => pattern,
# exclude? => pattern,
# declareEvent? => subref,
# registerEvent? => subref,
# beforeCall? => subref
# }
my @call_actions = (
{
include => qr/.*/,
exclude => qr/MPI_Wtime/,
declareEvent => \&declare_event,
registerEvent => \&register_event,
beforeCall => \&log_event
}
);

# Returns the action associated with the name, if any.
# Only the first matching action is returned.
sub get_call_action {
my ($name) = @_;
foreach (@call_actions) {
my $i = $_->{include};
my $x = $_->{exclude} || qr//;
# Matches include and does not match exclude.
if ($name =~ m/^${i}$/ && !($name =~ m/^${x}$/)) {
return $_;
}
}
return undef;
}

sub invoke_action_for_all_defs {
my ($action_name) = @_;

foreach my $def (extract_defs $mpidef_file) {

my $name = $def->{name};

unless ($name) {
next;
}

my $action = get_call_action $name;

unless ($action and $action->{$action_name}) {
next;
}

my $s = $action->{$action_name};
&$s($name);
}
}

open(my $out, '>', $output_file)
or die "Could not open file '$output_file': $!";
select $out;

say <<PROLOGUE;

# TODO:
# - Exclude certain signatures
# - Allow manual overrides

sub emit_prologue {
say <<PROLOGUE;
#include "vt/config.h"
#include "vt/runtime/mpi_access.h"
#if backend_check_enabled(trace_enabled)
#include "vt/trace/trace.h"
#include "vt/trace/trace_user.h" // TraceScopedEvent
#endif
#include <mpi.h>
#define EXTERN extern "C"
Expand All @@ -94,37 +187,76 @@ sub should_guard_call {
#include "vt/pmpi/pmpi_component.h"
void vt::pmpi::PMPIComponent::registerEventHandlers() {
// TODO
}
PROLOGUE
}

# TODO:
# - Exclude certain signatures
# - Allow manual overrides
sub emit_epilogue {
say <<EPILOGUE;
foreach my $def (extract_defs $mpidef_file) {
unless (should_guard_call $def->{name}) {
next;
}
#endif // backend_check_enabled(mpi_access_guards)
EPILOGUE
}

say "AUTOGEN EXTERN $def->{ret} $def->{name}($def->{sigargs}) {";
sub emit_guard {
my ($name) = @_;
say <<MPI_GUARD;
vtAssert(
vt::runtime::ScopedMPIAccess::mpiCallsAllowed(),
"The MPI function '$def->{name}' was called from a VT handler."
"The MPI function '$name' was called from a VT handler."
" MPI functions should not used inside user code invoked from VT handlers."
);
MPI_GUARD
if ($def->{ret} eq "void") {
say " P$def->{name}($def->{callargs});";
}

sub emit_call_original {
my ($name, $callargs, $ret_type) = @_;
if ($ret_type eq "void") {
say " P$name($callargs);";
} else {
say " return P$def->{name}($def->{callargs});";
say " return P$name($callargs);";
}
}

emit_prologue;

# Declarations.
say "#if backend_check_enabled(trace_enabled)";
invoke_action_for_all_defs 'declareEvent';
say "#endif";

# Event registrations.
say "";
say "void vt::pmpi::PMPIComponent::registerEventHandlers() {";
say "#if backend_check_enabled(trace_enabled)";
invoke_action_for_all_defs 'registerEvent';
say "#endif";
say "}";

# PMPI wrappers.

foreach my $def (extract_defs $mpidef_file) {
my $name = $def->{name};
my $should_guard = should_guard_call $name;
my $action = get_call_action $name;

unless ($name or $action) {
next;
}

say "AUTOGEN EXTERN $def->{ret} $def->{name}($def->{sigargs}) {";

if ($should_guard) {
emit_guard $def->{name};
}

if ($action and $action->{beforeCall}) {
my $s = $action->{beforeCall};
&$s($name);
}

emit_call_original $def->{name}, $def->{callargs}, $def->{ret};

say "}";
}

say <<EPILOG;
#endif // backend_check_enabled(mpi_access_guards)
EPILOG
emit_epilogue;

0 comments on commit 49bce29

Please sign in to comment.