Skip to content

Commit

Permalink
Merge pull request #759 from galacticusorg/featStaticEventHooks
Browse files Browse the repository at this point in the history
Add an `eventHookStatic` directive
  • Loading branch information
abensonca authored Dec 20, 2024
2 parents 3c03560 + 5442e39 commit 2581c3f
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 63 deletions.
1 change: 1 addition & 0 deletions perl/Galacticus/Build/SourceTree.pm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use Galacticus::Build::SourceTree::Process::HDF5FCInterop;
use Galacticus::Build::SourceTree::Process::Constructors;
use Galacticus::Build::SourceTree::Process::ConditionalCall;
use Galacticus::Build::SourceTree::Process::EventHooks;
use Galacticus::Build::SourceTree::Process::EventHooksStatic;
use Galacticus::Build::SourceTree::Process::ParameterMigration;
use Galacticus::Build::SourceTree::Process::Dependencies;
use Galacticus::Build::SourceTree::Process::ClassDocumentation;
Expand Down
111 changes: 111 additions & 0 deletions perl/Galacticus/Build/SourceTree/Process/EventHooksStatic.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Contains a Perl module which implements processing of static event directives.

package Galacticus::Build::SourceTree::Process::EventHooksStatic;
use strict;
use warnings;
use utf8;
use Cwd;
use lib $ENV{'GALACTICUS_EXEC_PATH'}."/perl";
use Data::Dumper;
use XML::Simple;
use Storable;
use List::ExtraUtils;
use Galacticus::Build::Directives;

# Insert hooks for our functions.
$Galacticus::Build::SourceTree::Hooks::processHooks{'eventHooksStatic'} = \&Process_EventHooksStatic;

sub Process_EventHooksStatic {
# Get the tree.
my $tree = shift();
# Get an XML parser.
my $xml = new XML::Simple();
# Get code directive locations if we do not have them.
our $directiveLocations = $xml->XMLin($ENV{'BUILDPATH'}."/directiveLocations.xml")
unless ( $directiveLocations );
# Initialize event hook names.
our @eventHookNames;
unless ( @eventHookNames ) {
if ( -e $ENV{'BUILDPATH'}."/eventHooksStatic.blob" ) {
@eventHookNames = @{retrieve($ENV{'BUILDPATH'}."/eventHooksStatic.blob")};
} else {
@eventHookNames = map {$_->{'name'}} map {&Galacticus::Build::Directives::Extract_Directives($_,'eventHookStatic')} &List::ExtraUtils::as_array($directiveLocations->{'eventHookStatic'}->{'file'});
store(\@eventHookNames,$ENV{'BUILDPATH'}."/eventHooksStatic.blob");
}
}
# Walk the tree, looking for hook directives.
my $node = $tree;
my $depth = 0;
my $moduleNode;
my @functions;
while ( $node ) {
# Locate the containing module.
$moduleNode = $node
if ( $node->{'type'} eq "module" );
# Handle eventHookStatic directives by creating code to call any hooked functions.
if ( $node->{'type'} eq "eventHookStatic" && ! $node->{'directive'}->{'processed'} ) {
$node->{'directive'}->{'processed'} = 1;
# Find locations of all matching directives.
my @eventHookedLocations = &List::ExtraUtils::as_array($directiveLocations->{$node->{'directive'}->{'name'}}->{'file'})
if ( exists($directiveLocations->{$node->{'directive'}->{'name'}}) );
# Iterate over event hook locations, finding names of hooked functions and the modules in which they are contained.
my @hookedFunctions;
foreach my $eventHookedLocation ( @eventHookedLocations ) {
my $eventHookedTree = &Galacticus::Build::SourceTree::ParseFile($eventHookedLocation);
my $eventHookedNode = $eventHookedTree;
my $eventHookedDepth = 0;
my $moduleName;
my $functionName;
while ( $eventHookedNode ) {
$moduleName = $eventHookedNode->{'name'}
if ( $eventHookedNode->{'type'} eq "module" );
$functionName = $eventHookedNode->{'directive'}->{'function'}
if ( $eventHookedNode->{'type'} eq $node->{'directive'}->{'name'} );
$eventHookedNode = &Galacticus::Build::SourceTree::Walk_Tree($eventHookedNode,\$eventHookedDepth);
}
die("Galacticus::Build::SourceTree::Process::EventHooksStatic: unable to find module containing hooked function")
unless ( defined($moduleName ) );
die("Galacticus::Build::SourceTree::Process::EventHooksStatic: unable to find name of hooked function" )
unless ( defined($functionName) );
push(@hookedFunctions,{function => $functionName, module => $moduleName});
}
# Insert the code.
my $newNode =
{
type => "code",
content => join("\n",map {"call ".$_->{'function'}."()"} @hookedFunctions)."\n",
firstChild => undef(),
source => "Galacticus::Build::SourceTree::Process::EventHooksStatic::Process_EventHooksStatic()",
line => 1
};
&Galacticus::Build::SourceTree::InsertAfterNode($node,[$newNode]);
my $usesNode =
{
type => "moduleUse",
moduleUse => {},
source => "Galacticus::Build::SourceTree::Process::EventHooksStatic::Process_EventHooksStatic()",
line => 1
};
$usesNode->{'moduleUse'}->{$_->{'module'}} = {intrinsic => 0, only => {$_->{'function'} => 1}}
foreach ( @hookedFunctions );
&Galacticus::Build::SourceTree::Parse::ModuleUses::AddUses($node->{'parent'},$usesNode);
}
# Look for event hooked functions.
if ( (grep {$node->{'type'} eq $_} @eventHookNames) && ! $node->{'directive'}->{'processed'} ) {
$node->{'directive'}->{'processed'} = 1;
push(@functions,$node->{'directive'}->{'function'});
}
$node = &Galacticus::Build::SourceTree::Walk_Tree($node,\$depth);
}
# Set visibilities for hooked functions.
if ( scalar(@functions) > 0 ) {
if ( defined($moduleNode) ) {
&Galacticus::Build::SourceTree::SetVisibility($moduleNode,$_,"public")
foreach ( @functions );
} else {
die("Galacticus::Build::SourceTree::Process::EventHooksStatic::Process_EventHooksStatic(): hooked function is not in a module");
}
}
}

1;
21 changes: 20 additions & 1 deletion scripts/build/useDependencies.pl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
# Extract lists of directives from this file which require special handling.
my $directives;
@{$directives->{$_}} = &Galacticus::Build::Directives::Extract_Directives($sourceFile->{'fullPathFileName'},$_)
foreach ( "functionClass", "inputParameter", "enumeration", "eventHook", "eventHookManager" );
foreach ( "functionClass", "inputParameter", "enumeration", "eventHook", "eventHookStatic", "eventHookManager" );
# Special handling for functionClass directives - add implementation files to the list of files to scan.
if ( scalar(@{$directives->{'functionClass'}}) > 0 ) {
foreach my $functionClass ( @{$directives->{'functionClass'}} ) {
Expand All @@ -203,6 +203,25 @@
($usesPerFile->{'eventHooksManager'}->{'objectFileName'} = $workSubDirectoryName.$sourceFile ->{'fileName'}) =~ s/\.(f|f90|c|cpp)$/.o/i;
$usesPerFile ->{'eventHooksManager'}->{'fileIdentifier'} = $fileIdentifier ;
}
# Accumulate dependencies for static event hook modules.
if ( scalar(@{$directives->{'eventHookStatic'}}) > 0 ) {
foreach my $eventHookStatic ( @{$directives->{'eventHookStatic'}} ) {
foreach my $eventHookedStaticFile ( &List::ExtraUtils::as_array($locations->{$eventHookStatic->{'name'}}->{'file'}) ) {
my $moduleName;
open(my $file,$eventHookedStaticFile) or die "Can't open input file: $eventHookedStaticFile";
while (my $line = <$file>) {
if ( $line =~ m/^\s*module\s+([a-zA-Z0-9_]+)/ ) {
$moduleName = $1;
last;
}
}
close($file);
die("useDependencies.pl: unable to locate containing module for static event '".$eventHookStatic->{'name'}."' in file '".$eventHookedStaticFile."'")
unless ( defined($moduleName) );
push(@{$usesPerFile->{$fileIdentifier}->{'modulesUsed'}},$workDirectoryName.lc($moduleName).".mod");
}
}
}
# Add dependence on input parameters module if necessary.
push(@{$usesPerFile->{$fileIdentifier}->{'modulesUsed'}},$workDirectoryName."input_parameters.mod")
if ( scalar(@{$directives->{'functionClass'}}) > 0 || scalar(@{$directives->{'inputParameter'}}) > 0 );
Expand Down
7 changes: 3 additions & 4 deletions source/events.hooks.F90
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Handles hooking of object function class into events.
use :: Regular_Expressions, only : regEx
use :: Locks , only : ompLock, ompReadWriteLock
private
public :: hook, hookUnspecified, dependencyExact, dependencyRegEx, eventsHooksInitialize, eventsHooksFutureThread, eventsHooksAtLevelToAllLevels
public :: hook , hookUnspecified , dependencyExact , dependencyRegEx, &
& eventsHooksInitialize, eventsHooksFutureThread, eventsHooksAtLevelToAllLevels

!![
<enumeration>
Expand Down Expand Up @@ -675,9 +676,7 @@ function dependencyRegExConstructor(direction,label) result(self)
end function dependencyRegExConstructor

!![
<hdfPreCloseTask>
<unitName>eventsHooksWaitTimes</unitName>
</hdfPreCloseTask>
<outputFileClose function="eventsHooksWaitTimes"/>
!!]

end module Events_Hooks
9 changes: 3 additions & 6 deletions source/instruments.filters.F90
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ module Instruments_Filters
use :: Locks , only : ompReadWriteLock
implicit none
private
public :: Filter_Get_Index , Filter_Response , Filter_Extent , Filter_Vega_Offset , &
& Filter_Name , Filter_Wavelength_Effective, Filters_Output, Filter_Response_Function, &
& Filters_Initialize
public :: Filter_Get_Index, Filter_Response , Filter_Extent , Filter_Vega_Offset , &
& Filter_Name , Filter_Wavelength_Effective, Filters_Initialize, Filter_Response_Function

type filterType
!!{
Expand Down Expand Up @@ -376,9 +375,7 @@ subroutine Filter_Response_Load(filterName)
end subroutine Filter_Response_Load

!![
<hdfPreCloseTask>
<unitName>Filters_Output</unitName>
</hdfPreCloseTask>
<outputFileClose function="Filters_Output"/>
!!]
subroutine Filters_Output()
!!{
Expand Down
8 changes: 4 additions & 4 deletions source/merger_trees.evolve.timesteps.history.F90
Original file line number Diff line number Diff line change
Expand Up @@ -194,23 +194,23 @@ subroutine historyAutoHook(self)
!!{
Create a hook to the HDF5 pre-close event to allow us to finalize and write out our data.
!!}
use :: Events_Hooks, only : hdf5PreCloseEventGlobal
use :: Events_Hooks, only : outputFileCloseEventGlobal
implicit none
class(mergerTreeEvolveTimestepHistory), intent(inout) :: self

call hdf5PreCloseEventGlobal%attach(self,historyWrite,label='mergerTreeEvolveTimestepHistory')
call outputFileCloseEventGlobal%attach(self,historyWrite,label='mergerTreeEvolveTimestepHistory')
return
end subroutine historyAutoHook

subroutine historyDestructor(self)
!!{
Destructor for the {\normalfont \ttfamily history} merger tree evolution timestep class.
!!}
use :: Events_Hooks, only : hdf5PreCloseEventGlobal
use :: Events_Hooks, only : outputFileCloseEventGlobal
implicit none
type(mergerTreeEvolveTimestepHistory), intent(inout) :: self

if (hdf5PreCloseEventGlobal%isAttached(self,historyWrite)) call hdf5PreCloseEventGlobal%detach(self,historyWrite)
if (outputFileCloseEventGlobal%isAttached(self,historyWrite)) call outputFileCloseEventGlobal%detach(self,historyWrite)
!![
<objectDestructor name="self%cosmologyFunctions_" />
<objectDestructor name="self%starFormationRateDisks_" />
Expand Down
32 changes: 5 additions & 27 deletions source/output.HDF5.open.F90
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ subroutine Output_HDF5_Open_File(parameters)
use :: MPI_Utilities , only : mpiSelf
#endif
use :: String_Handling , only : operator(//)
!![
<include directive="outputFileOpenTask" type="moduleUse">
!!]
include 'output.open.modules.inc'
!![
</include>
!!]
implicit none
type (inputParameters), intent(inout) :: parameters
integer(hsize_t ) :: chunkSize
Expand Down Expand Up @@ -180,15 +173,11 @@ subroutine Output_HDF5_Open_File(parameters)
! Set default chunking and compression levels.
call IO_HDF5_Set_Defaults(hdf5ChunkSize,hdf5CompressionLevel)

! Call all routines that requested to output to the file on start up.
! Call all functions that requested to output to the file on start up.
!![
<include directive="outputFileOpenTask" type="functionCall" functionType="void">
<eventHookStatic name="outputFileOpen"/>
!!]
include 'output.open.inc'
!![
</include>
!!]


! Flag that the file is now open.
outputFileIsOpen=.true.
end if
Expand All @@ -203,26 +192,15 @@ subroutine Output_HDF5_Close_File
use :: File_Utilities , only : File_Rename
use :: HDF5_Access , only : hdf5Access
use :: ISO_Varying_String, only : operator(/=)
!![
<include directive="hdfPreCloseTask" type="moduleUse">
!!]
include 'output.HDF5.pre_close_tasks.moduleUse.inc'
!![
</include>
!!]
implicit none

! Perform any final tasks prior to shutdown.
if (outputFileIsOpen) then
!$omp critical (Output_HDF5_Close_File)
if (outputFileIsOpen) then
!![
<include directive="hdfPreCloseTask" type="functionCall" functionType="void">
!!]
include 'output.HDF5.pre_close_tasks.inc'
!![
</include>
<eventHook name="hdf5PreClose"/>
<eventHookStatic name="outputFileClose"/>
<eventHook name="outputFileClose"/>
!!]
! Close the file.
!$ call hdf5Access%set()
Expand Down
10 changes: 4 additions & 6 deletions source/output.build.F90
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Output_Build
use, intrinsic :: ISO_C_Binding, only : c_ptr
implicit none
private
public :: Output_Build_Output, Output_Build_String
public :: Output_Build_String

interface
function GSL_Get_Version() bind(c,name='GSL_Get_Version')
Expand Down Expand Up @@ -110,13 +110,11 @@ function Output_Build_String()
Output_Build_String=Output_Build_String//":CPPCOMPILER_VERSION["//CPPCOMPILER_VERSION//"]"
return
end function Output_Build_String

!![
<outputFileOpenTask>
<unitName>Output_Build_Output</unitName>
</outputFileOpenTask>
<outputFileOpen function="Output_Build_Output"/>
!!]
subroutine Output_Build_Output
subroutine Output_Build_Output()
!!{
Output build information to the main output file.
!!}
Expand Down
10 changes: 3 additions & 7 deletions source/output.version.F90
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Output_Versioning
use, intrinsic :: ISO_C_Binding, only : c_char, c_size_t
implicit none
private
public :: Version_Output, Version_Finalize, Version_String, Version
public :: Version_String, Version

! Include the automatically generated Git revision number.
include 'output.version.revision.inc'
Expand Down Expand Up @@ -82,9 +82,7 @@ function Version_String()
end function Version_String

!![
<outputFileOpenTask>
<unitName>Version_Output</unitName>
</outputFileOpenTask>
<outputFileOpen function="Version_Output"/>
!!]
subroutine Version_Output
!!{
Expand Down Expand Up @@ -182,9 +180,7 @@ subroutine Version_Output
end subroutine Version_Output

!![
<hdfPreCloseTask>
<unitName>Version_Finalize</unitName>
</hdfPreCloseTask>
<outputFileClose function="Version_Finalize"/>
!!]
subroutine Version_Finalize()
!!{
Expand Down
5 changes: 1 addition & 4 deletions source/utility.OpenMP.F90
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,11 @@ module OpenMP_Utilities
Implements useful OpenMP utilities.
!!}
private
public :: OpenMP_Critical_Wait_Times

contains

!![
<hdfPreCloseTask>
<unitName>OpenMP_Critical_Wait_Times</unitName>
</hdfPreCloseTask>
<outputFileClose function="OpenMP_Critical_Wait_Times"/>
!!]
subroutine OpenMP_Critical_Wait_Times()
!!{
Expand Down
6 changes: 2 additions & 4 deletions source/utility.memory_reporting.F90
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module Memory_Reporting
use, intrinsic :: ISO_C_Binding, only : c_size_t , c_int
implicit none
private
public :: reportMemoryUsage, outputMemoryUsageMaximum
public :: reportMemoryUsage

! Code memory size initialization status.
logical :: codeMemoryUsageInitialized =.false.
Expand Down Expand Up @@ -269,9 +269,7 @@ subroutine codeUsageGet()
end subroutine codeUsageGet

!![
<hdfPreCloseTask>
<unitName>outputMemoryUsageMaximum</unitName>
</hdfPreCloseTask>
<outputFileClose function="outputMemoryUsageMaximum"/>
!!]
subroutine outputMemoryUsageMaximum()
!!{
Expand Down

0 comments on commit 2581c3f

Please sign in to comment.