Updates will be applied April 15th at 12pm EDT (UTC-0400). GitLab could be a little slow between 12 - 12:45pm EDT.

Commit 8cda178f authored by Burlen Loring's avatar Burlen Loring

analysis adaptor finalize api

Add a finalize method, this should be called by the bridge
before the analysis is deleted giving the analysis a chance
to clean up and shut down. The motivation is to ease use of
smart pointers with analyses that need to do MPI calls to
clean up and shut down. Without an explicit finalize step
the analysis potentially end up calling MPI after MPI_Finalize
because the smart pointer goes out of scope after MPI_Finalize
is called causing run to abort/crash.
parent 4d00ff5c
......@@ -120,6 +120,7 @@ int main(int argc, char **argv)
// close the ADIOS stream
dataAdaptor->Close();
analysisAdaptor->Finalize();
// we must force these to be destroyed before mpi finalize
// some of the adaptors make MPI calls in the destructor
......
......@@ -320,6 +320,7 @@ class analysis_adaptor:
elif analysis == 'posthoc':
if check_arg(args,'file','newton') and check_arg(args,'dir','./') \
and check_arg(args,'mode','0') and check_arg(args,'freq','1'):
# TODO -- mesh name API updates
self.AnalysisAdaptor = sensei.VTKPosthocIO.New()
self.AnalysisAdaptor.Initialize(comm, args['dir'],args['file'],\
[], ['ids','fx','fy','fz','f','vx','vy','vz','v','m'], \
......@@ -335,8 +336,7 @@ class analysis_adaptor:
sys.exit(-1)
def finalize(self):
if self.Analysis == 'posthoc':
self.AnalysisAdaptor.Finalize()
self.AnalysisAdaptor.Finalize()
def update(self, i,t,ids,x,y,z,m,vx,vy,vz,fx,fy,fz):
......@@ -349,6 +349,7 @@ class analysis_adaptor:
mb.SetNumberOfBlocks(n_ranks)
mb.SetBlock(rank, node)
# TODO -- mesh name API updates
self.DataAdaptor.SetDataTime(t)
self.DataAdaptor.SetDataTimeStep(i)
self.DataAdaptor.SetDataObject(mb)
......
......@@ -73,8 +73,12 @@ void finalize(size_t k_max, size_t nblocks)
(void)k_max;
(void)nblocks;
timer::MarkStartEvent("oscillators::bridge::finalize");
GlobalAnalysisAdaptor->Finalize();
GlobalAnalysisAdaptor = NULL;
GlobalDataAdaptor = NULL;
timer::MarkEndEvent("oscillators::bridge::finalize");
}
......
......@@ -55,8 +55,10 @@ void bridge_update(int tstep, double time, double *pressure, double* temperature
//-----------------------------------------------------------------------------
void bridge_finalize()
{
BridgeInternals::GlobalAnalysisAdaptor->Finalize();
BridgeInternals::GlobalAnalysisAdaptor = NULL;
BridgeInternals::GlobalDataAdaptor = NULL;
timer::PrintLog(std::cout, BridgeInternals::comm);
}
......@@ -47,10 +47,6 @@ ADIOSAnalysisAdaptor::ADIOSAnalysisAdaptor() : Comm(MPI_COMM_WORLD),
//----------------------------------------------------------------------------
ADIOSAnalysisAdaptor::~ADIOSAnalysisAdaptor()
{
if (this->Schema)
this->FinalizeADIOS();
delete Schema;
}
//----------------------------------------------------------------------------
......@@ -101,12 +97,24 @@ void ADIOSAnalysisAdaptor::InitializeADIOS(vtkDataObject *dobj)
//----------------------------------------------------------------------------
void ADIOSAnalysisAdaptor::FinalizeADIOS()
{
timer::MarkEvent mark("ADIOSAnalysisAdaptor::FinalizeADIOS");
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
adios_finalize(rank);
}
//----------------------------------------------------------------------------
int ADIOSAnalysisAdaptor::Finalize()
{
timer::MarkEvent mark("ADIOSAnalysisAdaptor::Finalize");
if (this->Schema)
this->FinalizeADIOS();
delete Schema;
return 0;
}
//----------------------------------------------------------------------------
void ADIOSAnalysisAdaptor::WriteTimestep(unsigned long timeStep,
double time, vtkDataObject *dobj)
......
......@@ -50,6 +50,8 @@ public:
bool Execute(DataAdaptor* data) override;
int Finalize() override;
protected:
ADIOSAnalysisAdaptor();
~ADIOSAnalysisAdaptor();
......
......@@ -27,6 +27,17 @@ public:
/// iteration.
virtual bool Execute(DataAdaptor* data) = 0;
/// @breif Finalize the analyis routine
///
/// This method is called when the run is finsihed clean up
/// and shut down should occur here rather than in the destructor
/// as MPI may not be available at desctruction time for instance
/// when smart pointers are used MPI is finalized before the
/// pointer goes out of scope and is destroyed.
///
/// @returns zero if successful
virtual int Finalize() = 0;
protected:
AnalysisAdaptor();
~AnalysisAdaptor();
......
......@@ -207,7 +207,6 @@ Autocorrelation::Autocorrelation()
//-----------------------------------------------------------------------------
Autocorrelation::~Autocorrelation()
{
this->PrintResults(this->Internals->KMax);
delete this->Internals;
}
......@@ -397,4 +396,13 @@ void Autocorrelation::PrintResults(size_t k_max)
});
}
//-----------------------------------------------------------------------------
int Autocorrelation::Finalize()
{
this->PrintResults(this->Internals->KMax);
delete this->Internals;
this->Internals = nullptr;
return 0;
}
}
......@@ -35,6 +35,9 @@ public:
std::string& arrayname, size_t k_max);
bool Execute(DataAdaptor* data) override;
int Finalize() override;
protected:
Autocorrelation();
~Autocorrelation();
......
......@@ -25,7 +25,7 @@
namespace sensei
{
static size_t vtkCPAdaptorAPIInitializationCounter = 0;
static int vtkCPAdaptorAPIInitializationCounter = 0;
//-----------------------------------------------------------------------------
senseiNewMacro(CatalystAnalysisAdaptor);
......@@ -33,23 +33,24 @@ senseiNewMacro(CatalystAnalysisAdaptor);
//-----------------------------------------------------------------------------
CatalystAnalysisAdaptor::CatalystAnalysisAdaptor()
{
if (vtkCPAdaptorAPIInitializationCounter == 0)
{
timer::MarkEvent mark("catalyst::initialize");
vtkCPAdaptorAPI::CoProcessorInitialize();
}
vtkCPAdaptorAPIInitializationCounter++;
this->Initialize();
}
//-----------------------------------------------------------------------------
CatalystAnalysisAdaptor::~CatalystAnalysisAdaptor()
{
vtkCPAdaptorAPIInitializationCounter--;
this->Finalize();
}
//-----------------------------------------------------------------------------
void CatalystAnalysisAdaptor::Initialize()
{
if (vtkCPAdaptorAPIInitializationCounter == 0)
{
timer::MarkEvent mark("catalyst::finalize");
vtkCPAdaptorAPI::CoProcessorFinalize();
timer::MarkEvent mark("CatalystAnalysisAdaptor::Initialize");
vtkCPAdaptorAPI::CoProcessorInitialize();
}
vtkCPAdaptorAPIInitializationCounter++;
}
//-----------------------------------------------------------------------------
......@@ -172,6 +173,18 @@ bool CatalystAnalysisAdaptor::FillDataDescriptionWithData(
return true;
}
//-----------------------------------------------------------------------------
int CatalystAnalysisAdaptor::Finalize()
{
vtkCPAdaptorAPIInitializationCounter--;
if (vtkCPAdaptorAPIInitializationCounter == 0)
{
timer::MarkEvent mark("CatalystAnalysisAdaptor::Finalize");
vtkCPAdaptorAPI::CoProcessorFinalize();
}
return 0;
}
//-----------------------------------------------------------------------------
void CatalystAnalysisAdaptor::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -30,10 +30,14 @@ public:
bool Execute(DataAdaptor* data) override;
int Finalize() override;
protected:
CatalystAnalysisAdaptor();
~CatalystAnalysisAdaptor();
void Initialize();
/// @brief Fill \c desc with meta data from \c DataAdaptor.
///
/// Called before the RequestDataDescription step to fill \c desc with
......
......@@ -2,12 +2,6 @@
#include "senseiConfig.h"
#include "Error.h"
#include <vtkObjectFactory.h>
#include <vtkSmartPointer.h>
#include <vtkNew.h>
#include <vtkDataObject.h>
#include "senseiConfig.h"
#include "Autocorrelation.h"
#include "PosthocIO.h"
#include "Histogram.h"
......@@ -26,12 +20,20 @@
#include "LibsimImageProperties.h"
#endif
#include <vtkObjectFactory.h>
#include <vtkSmartPointer.h>
#include <vtkNew.h>
#include <vtkDataObject.h>
#include <vector>
#include <pugixml.hpp>
#include <sstream>
#include <cstdio>
#include <errno.h>
using AnalysisAdaptorPtr = vtkSmartPointer<sensei::AnalysisAdaptor>;
using AnalysisAdaptorVector = std::vector<AnalysisAdaptorPtr>;
namespace sensei
{
......@@ -125,6 +127,7 @@ private:
public:
std::vector<vtkSmartPointer<AnalysisAdaptor>> Analyses;
AnalysisAdaptorVector Analyses;
#ifdef ENABLE_LIBSIM
vtkSmartPointer<LibsimAnalysisAdaptor> LibsimAdaptor;
#endif
......@@ -571,15 +574,29 @@ bool ConfigurableAnalysis::Initialize(MPI_Comm comm, const std::string& filename
//----------------------------------------------------------------------------
bool ConfigurableAnalysis::Execute(DataAdaptor* data)
{
for (std::vector<vtkSmartPointer<AnalysisAdaptor> >::iterator iter
= this->Internals->Analyses.begin();
iter != this->Internals->Analyses.end(); ++iter)
AnalysisAdaptorVector::iterator iter = this->Internals->Analyses.begin();
AnalysisAdaptorVector::iterator end = this->Internals->Analyses.end();
for (; iter != end; ++iter)
{
iter->GetPointer()->Execute(data);
// TODO -- should we be checking the return value here?
// what happens when an analysis errors out? do we keep trying
// to execute it?
(*iter)->Execute(data);
}
return true;
}
//----------------------------------------------------------------------------
int ConfigurableAnalysis::Finalize()
{
AnalysisAdaptorVector::iterator iter = this->Internals->Analyses.begin();
AnalysisAdaptorVector::iterator end = this->Internals->Analyses.end();
for (; iter != end; ++iter)
{
(*iter)->Finalize();
}
return true;
}
//----------------------------------------------------------------------------
void ConfigurableAnalysis::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -23,6 +23,8 @@ public:
bool Execute(DataAdaptor* data) override;
int Finalize() override;
protected:
ConfigurableAnalysis();
~ConfigurableAnalysis();
......
......@@ -183,4 +183,12 @@ int Histogram::GetHistogram(double &min, double &max,
return this->Internals->GetHistogram(this->Communicator, min, max, bins);
}
//-----------------------------------------------------------------------------
int Histogram::Finalize()
{
delete this->Internals;
this->Internals = nullptr;
return 0;
}
}
......@@ -29,6 +29,8 @@ public:
bool Execute(DataAdaptor* data) override;
int Finalize() override;
// return the last computed histogram
int GetHistogram(double &min, double &max,
std::vector<unsigned int> &bins);
......
......@@ -1159,6 +1159,14 @@ bool LibsimAnalysisAdaptor::Execute(DataAdaptor* DataAdaptor)
return internals->Execute(DataAdaptor);
}
//-----------------------------------------------------------------------------
int LibsimAnalysisAdaptor::Finalize()
{
delete this->internals;
this->internals = nullptr;
return 0;
}
//-----------------------------------------------------------------------------
void LibsimAnalysisAdaptor::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -32,6 +32,8 @@ public:
bool Execute(DataAdaptor* data) override;
int Finalize() override;
// Simple method to add some VisIt plots and render. The limit is how complex
// we want to make this.
bool AddRender(int frequency, const std::string &plots,
......
......@@ -185,13 +185,13 @@ bool VTKPosthocIO::Execute(DataAdaptor* data)
}
//-----------------------------------------------------------------------------
bool VTKPosthocIO::Finalize()
int VTKPosthocIO::Finalize()
{
int rank = 0;
MPI_Comm_rank(this->Comm, &rank);
if (rank != 0)
return true;
return 0;
int nRanks = 1;
MPI_Comm_size(this->Comm, &nRanks);
......@@ -208,7 +208,7 @@ bool VTKPosthocIO::Finalize()
if (!pvdFile)
{
SENSEI_ERROR("Failed to open " << pvdFileName << " for writing")
return false;
return -1;
}
pvdFile << "<?xml version=\"1.0\"?>" << endl
......@@ -271,7 +271,7 @@ bool VTKPosthocIO::Finalize()
}
SENSEI_ERROR("Invalid mode \"" << this->Mode << "\"")
return false;
return -1;
}
}
......@@ -32,7 +32,10 @@ public:
bool Execute(DataAdaptor* data) override;
bool Finalize();
// SENSEI API
int Initialize();
bool Execute(DataAdaptor* data) override;
int Finalize() override;
protected:
VTKPosthocIO();
......
......@@ -461,4 +461,10 @@ bool VTKmContourAnalysis::Execute(sensei::DataAdaptor* data)
return true;
}
} // end of namespace sensei
//-----------------------------------------------------------------------------
int VTKmContourAnalysis::Finalize()
{
return 0;
}
}
......@@ -19,9 +19,12 @@ public:
static VTKmContourAnalysis* New();
vtkTypeMacro(VTKmContourAnalysis, AnalysisAdaptor);
void Initialize(MPI_Comm comm, const std::string& arrayname, double value, bool writeOutput);
void Initialize(MPI_Comm comm, const std::string& arrayname,
double value, bool writeOutput);
virtual bool Execute(sensei::DataAdaptor* data) override;
bool Execute(sensei::DataAdaptor* data) override;
int Finalize() override;
protected:
VTKmContourAnalysis();
......
......@@ -125,7 +125,7 @@ def write_data(file_name, method, n_its):
da = None
i += 1
# force free up the adaptor
aw = None
aw.Finalize()
status_message('finished writing %d steps'%(n_its))
# set the return value
return 0
......
......@@ -137,6 +137,8 @@ int main(int argc, char **argv)
int testResult = validateHistogram(min, max, bins);
analysisAdaptor->Finalize();
MPI_Finalize();
return testResult;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment