Adding error handling
This commit is contained in:
parent
c2e591fac9
commit
06edcf338f
@ -172,7 +172,7 @@ MACRO ( CONFIGURE_SYSTEM )
|
||||
ENDMACRO ()
|
||||
|
||||
|
||||
# Macro to configure AtomicModel-specific options
|
||||
# Macro to configure LBPM specific options
|
||||
MACRO ( CONFIGURE_LBPM )
|
||||
# Set the maximum number of processors for the tests
|
||||
IF ( NOT TEST_MAX_PROCS )
|
||||
|
@ -491,8 +491,6 @@ MACRO( ADD_DISTCLEAN )
|
||||
*.vcxproj*
|
||||
ipch
|
||||
x64
|
||||
atomic.lib
|
||||
atomic.pdb
|
||||
)
|
||||
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/distclean.bat "del /s /q /f " )
|
||||
FOREACH (fileToDelete ${DISTCLEANED})
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <exception> // std::exception
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
@ -20,9 +20,7 @@ inline void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy, do
|
||||
//...... READ IN THE SPHERES...................................
|
||||
cout << "Reading the packing file..." << endl;
|
||||
FILE *fid = fopen("pack.out","rb");
|
||||
if ( fid==NULL) {
|
||||
throw logic_error("Error opening pack.out");
|
||||
}
|
||||
INSIST(fid==NULL,"Error opening pack.out");
|
||||
//.........Trash the header lines..........
|
||||
char * line = new char[100];
|
||||
fgets(line, 100, fid);
|
||||
@ -42,9 +40,7 @@ inline void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy, do
|
||||
count++;
|
||||
}
|
||||
cout << "Number of spheres extracted is: " << count/4 << endl;
|
||||
if ( count != nspheres ) {
|
||||
throw logic_error("Specified number of spheres is probably incorrect!");
|
||||
}
|
||||
INSIST( count != nspheres, "Specified number of spheres is probably incorrect!" );
|
||||
// .............................................................
|
||||
}
|
||||
|
||||
|
345
common/UnitTest.cpp
Executable file
345
common/UnitTest.cpp
Executable file
@ -0,0 +1,345 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "common/UnitTest.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
// Windows
|
||||
// Sleep is defined in milliseconds
|
||||
#else
|
||||
// Linux
|
||||
// usleep is defined in microseconds, create a Sleep command
|
||||
#define Sleep(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Empty Constructor *
|
||||
********************************************************************/
|
||||
UnitTest::UnitTest() {
|
||||
#ifdef USE_MPI
|
||||
comm = MPI_COMM_WORLD;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Print a global report *
|
||||
* Note: only rank 0 will print, all messages will be aggregated *
|
||||
********************************************************************/
|
||||
void UnitTest::report(const int level0) {
|
||||
int size = getSize();
|
||||
int rank = getRank();
|
||||
// Broadcast the print level from rank 0
|
||||
int level = level0;
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 )
|
||||
MPI_Bcast( &level, 1, MPI_INT, 0, comm );
|
||||
#endif
|
||||
if ( level<0 || level > 2 )
|
||||
ERROR("Invalid print level");
|
||||
// Perform a global all gather to get the number of failures per processor
|
||||
std::vector<int> N_pass(size,0);
|
||||
std::vector<int> N_fail(size,0);
|
||||
std::vector<int> N_expected_fail(size,0);
|
||||
int local_pass_size = (int) pass_messages.size();
|
||||
int local_fail_size = (int) fail_messages.size();
|
||||
int local_expected_fail_size = (int) expected_fail_messages.size();
|
||||
if ( getSize() > 1 ) {
|
||||
#ifdef USE_MPI
|
||||
MPI_Allgather( &local_pass_size, 1, MPI_INT, &N_pass[0], 1, MPI_INT, comm);
|
||||
MPI_Allgather( &local_fail_size, 1, MPI_INT, &N_fail[0], 1, MPI_INT, comm);
|
||||
MPI_Allgather( &local_expected_fail_size, 1, MPI_INT, &N_expected_fail[0], 1, MPI_INT, comm);
|
||||
#endif
|
||||
} else {
|
||||
N_pass[0] = local_pass_size;
|
||||
N_fail[0] = local_fail_size;
|
||||
N_expected_fail[0] = local_expected_fail_size;
|
||||
}
|
||||
int N_pass_tot = 0;
|
||||
int N_expected_fail_tot = 0;
|
||||
for (int i=0; i<size; i++) {
|
||||
N_pass_tot += N_pass[i];
|
||||
N_expected_fail_tot += N_expected_fail[i];
|
||||
}
|
||||
// Send all messages to rank 0 (if needed)
|
||||
std::vector< std::vector<std::string> > pass_messages_rank(size);
|
||||
std::vector< std::vector<std::string> > fail_messages_rank(size);
|
||||
std::vector< std::vector<std::string> > expected_fail_rank(size);
|
||||
// Get the pass messages
|
||||
if ( ( level==1 && N_pass_tot<=20 ) || level==2 ) {
|
||||
if ( rank==0 ) {
|
||||
// Rank 0 should receive all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
if ( i==0 )
|
||||
pass_messages_rank[i] = pass_messages;
|
||||
else if ( N_pass[i]>0 )
|
||||
pass_messages_rank[i] = unpack_message_stream(i,1);
|
||||
}
|
||||
} else if ( pass_messages.size() ) {
|
||||
// All other ranks send their message (use non-blocking communication)
|
||||
pack_message_stream(pass_messages,0,1);
|
||||
}
|
||||
}
|
||||
// Get the fail messages
|
||||
if ( level==1 || level==2 ) {
|
||||
if ( rank==0 ) {
|
||||
// Rank 0 should receive all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
if ( i==0 )
|
||||
fail_messages_rank[i] = fail_messages;
|
||||
else if ( N_fail[i]>0 )
|
||||
fail_messages_rank[i] = unpack_message_stream(i,2);
|
||||
}
|
||||
} else if ( !fail_messages.empty() ){
|
||||
// All other ranks send their message (use non-blocking communication)
|
||||
pack_message_stream(fail_messages,0,2);
|
||||
}
|
||||
}
|
||||
// Get the expected_fail messages
|
||||
if ( ( level==1 && N_expected_fail_tot<=50 ) || level==2 ) {
|
||||
if ( rank==0 ) {
|
||||
// Rank 0 should receive all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
if ( i==0 )
|
||||
expected_fail_rank[i] = expected_fail_messages;
|
||||
else if ( N_expected_fail[i]>0 )
|
||||
expected_fail_rank[i] = unpack_message_stream(i,3);
|
||||
}
|
||||
} else if ( !expected_fail_messages.empty() ){
|
||||
// All other ranks send their message (use non-blocking communication)
|
||||
pack_message_stream(expected_fail_messages,0,3);
|
||||
}
|
||||
}
|
||||
// Print the results of all messages (only rank 0 will print)
|
||||
if ( rank==0 ) {
|
||||
std::cout << std::endl;
|
||||
// Print the passed tests
|
||||
std::cout << "Tests passed" << std::endl;
|
||||
if ( level==0 || ( level==1 && N_pass_tot>20 ) ) {
|
||||
// We want to print a summary
|
||||
if ( size>8 ) {
|
||||
// Print 1 summary for all processors
|
||||
std::cout << " " << N_pass_tot << " tests passed (use report level 2 for more detail)" << std::endl;
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for (int i=0; i<size; i++)
|
||||
std::cout << " " << N_pass[i] << " tests passed (proc " << i << ") (use report level 2 for more detail)" << std::endl;
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
ASSERT( (int)pass_messages_rank[i].size() == N_pass[i] );
|
||||
if ( N_pass[i] > 0 ) {
|
||||
std::cout << " Proccessor " << i << ":" << std::endl;
|
||||
for (unsigned int j=0; j<pass_messages_rank[i].size(); j++)
|
||||
std::cout << " " << pass_messages_rank[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
// Print the tests that failed
|
||||
std::cout << "Tests failed" << std::endl;
|
||||
if ( level==0 ) {
|
||||
// We want to print a summary
|
||||
if ( size>8 ) {
|
||||
// Print 1 summary for all processors
|
||||
std::cout << " " << N_pass_tot << " tests failed (use report level 2 for more detail)" << std::endl;
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for (int i=0; i<size; i++)
|
||||
std::cout << " " << N_fail[i] << " tests failed (proc " << i << ") (use report level 1 or 2 for more detail)" << std::endl;
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
ASSERT( (int)fail_messages_rank[i].size() == N_fail[i] );
|
||||
if ( N_fail[i] > 0 ) {
|
||||
std::cout << " Processor " << i << ":" << std::endl;
|
||||
for (unsigned int j=0; j<fail_messages_rank[i].size(); j++)
|
||||
std::cout << " " << fail_messages_rank[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
// Print the tests that expected failed
|
||||
std::cout << "Tests expected failed" << std::endl;
|
||||
if ( level==0 || ( level==1 && N_expected_fail_tot>50 ) ) {
|
||||
// We want to print a summary
|
||||
if ( size>8 ) {
|
||||
// Print 1 summary for all processors
|
||||
std::cout << " " << N_expected_fail_tot << " tests expected failed (use report level 2 for more detail)" << std::endl;
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for (int i=0; i<size; i++)
|
||||
std::cout << " " << N_expected_fail[i] << " tests expected failed (proc " << i << ") (use report level 1 or 2 for more detail)" << std::endl;
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for (int i=0; i<size; i++) {
|
||||
ASSERT( (int)expected_fail_rank[i].size() == N_expected_fail[i] );
|
||||
if ( N_expected_fail[i] > 0 ) {
|
||||
std::cout << " Processor " << i << ":" << std::endl;
|
||||
for (unsigned int j=0; j<expected_fail_rank[i].size(); j++)
|
||||
std::cout << " " << expected_fail_rank[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
// Add a barrier to synchronize all processors (rank 0 is much slower)
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 )
|
||||
MPI_Barrier(comm);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Pack and send the given messages *
|
||||
********************************************************************/
|
||||
void UnitTest::pack_message_stream(const std::vector<std::string>& messages, const int rank, const int tag)
|
||||
{
|
||||
#ifdef USE_MPI
|
||||
// Get the size of the messages
|
||||
int N_messages = (int) messages.size();
|
||||
int *msg_size = new int[N_messages];
|
||||
int msg_size_tot = 0;
|
||||
for (int i=0; i<N_messages; i++) {
|
||||
msg_size[i] = (int) messages[i].size();
|
||||
msg_size_tot += msg_size[i];
|
||||
}
|
||||
// Allocate space for the message stream
|
||||
int size_data = (N_messages+1)*sizeof(int)+msg_size_tot;
|
||||
char *data = new char[size_data];
|
||||
// Pack the message stream
|
||||
int *tmp = (int*) data;
|
||||
tmp[0] = N_messages;
|
||||
for (int i=0; i<N_messages; i++)
|
||||
tmp[i+1] = msg_size[i];
|
||||
int k = (N_messages+1)*sizeof(int);
|
||||
for (int i=0; i<N_messages; i++) {
|
||||
messages[i].copy(&data[k],msg_size[i]);
|
||||
k += msg_size[i];
|
||||
}
|
||||
// Send the message stream (using a non-blocking send)
|
||||
MPI_Request request;
|
||||
MPI_Isend( data, size_data, MPI_CHAR, rank, tag, comm, &request );
|
||||
// Wait for the communication to send and free the temporary memory
|
||||
MPI_Status status;
|
||||
MPI_Wait( &request, &status );
|
||||
delete [] data;
|
||||
delete [] msg_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* receive and unpack a message stream *
|
||||
********************************************************************/
|
||||
std::vector<std::string> UnitTest::unpack_message_stream(const int rank, const int tag)
|
||||
{
|
||||
#ifdef USE_MPI
|
||||
// Probe the message to get the message size
|
||||
MPI_Status status;
|
||||
MPI_Probe(rank,tag,comm,&status);
|
||||
int size_data=-1;
|
||||
MPI_Get_count(&status,MPI_BYTE,&size_data);
|
||||
ASSERT(size_data>=0);
|
||||
// Allocate memory to receive the data
|
||||
char *data = new char[size_data];
|
||||
// receive the data (using a non-blocking receive)
|
||||
MPI_Request request;
|
||||
MPI_Irecv( data, size_data, MPI_CHAR, rank, tag, comm, &request );
|
||||
// Wait for the communication to be received
|
||||
MPI_Wait( &request, &status );
|
||||
// Unpack the message stream
|
||||
int *tmp = (int*) data;
|
||||
int N_messages = tmp[0];
|
||||
int *msg_size = &tmp[1];
|
||||
std::vector<std::string> messages(N_messages);
|
||||
int k = (N_messages+1)*sizeof(int);
|
||||
for (int i=0; i<N_messages; i++) {
|
||||
messages[i] = std::string(&data[k],msg_size[i]);
|
||||
k += msg_size[i];
|
||||
}
|
||||
// Delete the temporary memory
|
||||
delete [] data;
|
||||
return messages;
|
||||
#else
|
||||
return std::vector<std::string>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Other functions *
|
||||
********************************************************************/
|
||||
int UnitTest::getRank()
|
||||
{
|
||||
int rank = 0;
|
||||
#ifdef USE_MPI
|
||||
int flag=0;
|
||||
MPI_Initialized(&flag);
|
||||
if ( flag )
|
||||
MPI_Comm_rank( comm, &rank );
|
||||
#endif
|
||||
return rank;
|
||||
}
|
||||
int UnitTest::getSize()
|
||||
{
|
||||
int size = 1;
|
||||
#ifdef USE_MPI
|
||||
int flag=0;
|
||||
MPI_Initialized(&flag);
|
||||
if ( flag )
|
||||
MPI_Comm_size( comm, &size );
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
size_t UnitTest::NumPassGlobal()
|
||||
{
|
||||
size_t num = pass_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
int send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
size_t UnitTest::NumFailGlobal()
|
||||
{
|
||||
size_t num = fail_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
int send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
size_t UnitTest::NumExpectedFailGlobal()
|
||||
{
|
||||
size_t num = expected_fail_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
int send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
|
||||
|
105
common/UnitTest.h
Executable file
105
common/UnitTest.h
Executable file
@ -0,0 +1,105 @@
|
||||
#ifndef included_UnitTest
|
||||
#define included_UnitTest
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#ifdef USE_MPI
|
||||
#include "mpi.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Class UnitTest is simple utility for running unit tests.
|
||||
* It provides basic routines for tracing success or failure of tests,
|
||||
* and reporting the results.
|
||||
* \par Code Sample:
|
||||
* \code
|
||||
try {
|
||||
std::cout << "Testing tstOne" << std::endl;
|
||||
tstOne(&ut);
|
||||
ut.passes("Test XXX passed");
|
||||
} catch( ... ) {
|
||||
ut.failure("An unknown exception was thrown");
|
||||
}
|
||||
ut.report();
|
||||
return ut.NumFail();
|
||||
* \endcode
|
||||
|
||||
*/
|
||||
class UnitTest {
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
UnitTest();
|
||||
|
||||
//! Indicate a passed test
|
||||
virtual void passes (const std::string &in) { pass_messages.push_back(in); }
|
||||
|
||||
//! Indicate a failed test
|
||||
virtual void failure (const std::string &in) { fail_messages.push_back(in); }
|
||||
|
||||
//! Indicate an expected failed test
|
||||
virtual void expected_failure (const std::string &in) { expected_fail_messages.push_back(in); }
|
||||
|
||||
//! Return the number of passed tests locally
|
||||
virtual size_t NumPassLocal () { return pass_messages.size(); }
|
||||
|
||||
//! Return the number of failed tests locally
|
||||
virtual size_t NumFailLocal () { return fail_messages.size(); }
|
||||
|
||||
//! Return the number of expected failed tests locally
|
||||
virtual size_t NumExpectedFailLocal () { return expected_fail_messages.size(); }
|
||||
|
||||
//! Return the number of passed tests locally
|
||||
virtual size_t NumPassGlobal ();
|
||||
|
||||
//! Return the number of failed tests locally
|
||||
virtual size_t NumFailGlobal ();
|
||||
|
||||
//! Return the number of expected failed tests locally
|
||||
virtual size_t NumExpectedFailGlobal ();
|
||||
|
||||
//! Return the rank of the current processor
|
||||
int getRank ();
|
||||
|
||||
//! Return the number of processors
|
||||
int getSize ();
|
||||
|
||||
/*!
|
||||
* Print a report of the passed and failed tests.
|
||||
* Note: This is a blocking call that all processors must execute together.
|
||||
* Note: Only rank 0 will print the messages (this is necessary as other ranks may not be able to print correctly).
|
||||
* @param level Optional integer specifying the level of reporting (default: 1)
|
||||
* 0: Report the number of tests passed, failed, and expected failures.
|
||||
* 1: Report the number of passed tests (if <=20) or the number passed otherwise,
|
||||
* report all failures,
|
||||
* report the number of expected failed tests (if <=50) or the number passed otherwise.
|
||||
* 2: Report all passed, failed, and expected failed tests.
|
||||
*/
|
||||
virtual void report(const int level=1);
|
||||
|
||||
protected:
|
||||
std::vector<std::string> pass_messages;
|
||||
std::vector<std::string> fail_messages;
|
||||
std::vector<std::string> expected_fail_messages;
|
||||
#ifdef USE_MPI
|
||||
MPI_Comm comm;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Make the copy constructor private
|
||||
UnitTest(const UnitTest& p) {}
|
||||
|
||||
// Function to pack the messages into a single data stream and send to the given processor
|
||||
// Note: This function does not return until the message stream has been sent
|
||||
void pack_message_stream(const std::vector<std::string>& messages, const int rank, const int tag);
|
||||
|
||||
// Function to unpack the messages from a single data stream
|
||||
// Note: This function does not return until the message stream has been received
|
||||
std::vector<std::string> unpack_message_stream(const int rank, const int tag);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
384
common/Utilities.cpp
Normal file
384
common/Utilities.cpp
Normal file
@ -0,0 +1,384 @@
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef USE_MPI
|
||||
#include "mpi.h"
|
||||
#endif
|
||||
|
||||
// Detect the OS and include system dependent headers
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER)
|
||||
// Note: windows has not been testeds
|
||||
#define USE_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <psapi.h>
|
||||
#include <DbgHelp.h>
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
//#pragma comment(lib, psapi.lib) //added
|
||||
//#pragma comment(linker, /DEFAULTLIB:psapi.lib)
|
||||
#elif defined(__APPLE__)
|
||||
#define USE_MAC
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#elif defined(__linux) || defined(__unix) || defined(__posix)
|
||||
#define USE_LINUX
|
||||
#include <sys/time.h>
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define USE_ABI
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to terminate the program *
|
||||
****************************************************************************/
|
||||
static bool abort_printMemory = true;
|
||||
static bool abort_printStack = true;
|
||||
static bool abort_throwException = false;
|
||||
static int force_exit = 0;
|
||||
void Utilities::setAbortBehavior( bool printMemory, bool printStack, bool throwException )
|
||||
{
|
||||
abort_printMemory = printMemory;
|
||||
abort_printStack = printStack;
|
||||
abort_throwException = throwException;
|
||||
}
|
||||
void Utilities::abort(const std::string &message, const std::string &filename, const int line)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Program abort called in file `" << filename << "' at line " << line << std::endl;
|
||||
// Add the memory usage and call stack to the error message
|
||||
if ( abort_printMemory ) {
|
||||
size_t N_bytes = Utilities::getMemoryUsage();
|
||||
msg << "Bytes used = " << N_bytes << std::endl;
|
||||
}
|
||||
if ( abort_printStack ) {
|
||||
std::vector<std::string> stack = Utilities::getCallStack();
|
||||
msg << std::endl;
|
||||
msg << "Stack Trace:\n";
|
||||
for (size_t i=0; i<stack.size(); i++)
|
||||
msg << " " << stack[i] << std::endl;
|
||||
}
|
||||
msg << std::endl << message << std::endl;
|
||||
// Print the message and abort
|
||||
if ( force_exit>1 ) {
|
||||
exit(-1);
|
||||
} else if ( !abort_throwException ) {
|
||||
// Use MPI_abort (will terminate all processes)
|
||||
force_exit = 2;
|
||||
std::cerr << msg.str();
|
||||
#if defined(USE_MPI) || defined(HAVE_MPI)
|
||||
int initialized=0, finalized=0;
|
||||
MPI_Initialized(&initialized);
|
||||
MPI_Finalized(&finalized);
|
||||
if ( initialized!=0 && finalized==0 )
|
||||
MPI_Abort(MPI_COMM_WORLD,-1);
|
||||
#endif
|
||||
exit(-1);
|
||||
} else if ( force_exit>0 ) {
|
||||
exit(-1);
|
||||
} else {
|
||||
// Throw and standard exception (allows the use of try, catch)
|
||||
throw std::logic_error(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to handle MPI errors *
|
||||
****************************************************************************/
|
||||
/*#if defined(USE_MPI) || defined(HAVE_MPI)
|
||||
MPI_Errhandler mpierr;
|
||||
void MPI_error_handler_fun( MPI_Comm *comm, int *err, ... )
|
||||
{
|
||||
if ( *err==MPI_ERR_COMM && *comm==MPI_COMM_WORLD ) {
|
||||
// Special error handling for an invalid MPI_COMM_WORLD
|
||||
std::cerr << "Error invalid MPI_COMM_WORLD";
|
||||
exit(-1);
|
||||
}
|
||||
int msg_len=0;
|
||||
char message[1000];
|
||||
MPI_Error_string( *err, message, &msg_len );
|
||||
if ( msg_len <= 0 )
|
||||
abort("Unkown error in MPI");
|
||||
abort( "Error calling MPI routine:\n" + std::string(message) );
|
||||
}
|
||||
#endif*/
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to handle unhandled exceptions *
|
||||
****************************************************************************/
|
||||
void term_func_abort(int err)
|
||||
{
|
||||
printf("Exiting due to abort (%i)\n",err);
|
||||
std::vector<std::string> stack = Utilities::getCallStack();
|
||||
std::string message = "Stack Trace:\n";
|
||||
for (size_t i=0; i<stack.size(); i++)
|
||||
message += " " + stack[i] += "\n";
|
||||
message += "\nExiting\n";
|
||||
// Print the message and abort
|
||||
std::cerr << message;
|
||||
#ifdef USE_MPI
|
||||
if ( !abort_throwException )
|
||||
MPI_Abort(MPI_COMM_WORLD,-1);
|
||||
#endif
|
||||
exit(-1);
|
||||
}
|
||||
static int tried_throw = 0;
|
||||
void term_func()
|
||||
{
|
||||
// Try to re-throw the last error to get the last message
|
||||
std::string last_message;
|
||||
#ifdef USE_LINUX
|
||||
try {
|
||||
if ( tried_throw==0 ) {
|
||||
tried_throw = 1;
|
||||
throw;
|
||||
}
|
||||
// No active exception
|
||||
} catch (const std::exception &err) {
|
||||
// Caught a std::runtime_error
|
||||
last_message = err.what();
|
||||
} catch (...) {
|
||||
// Caught an unknown exception
|
||||
last_message = "unknown exception occurred.";
|
||||
}
|
||||
#endif
|
||||
std::stringstream msg;
|
||||
msg << "Unhandled exception:" << std::endl;
|
||||
msg << " " << last_message << std::endl;
|
||||
Utilities::abort( msg.str(), __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Functions to set the error handler *
|
||||
****************************************************************************/
|
||||
static void setTerminateErrorHandler()
|
||||
{
|
||||
std::set_terminate( term_func );
|
||||
signal(SIGSEGV,&term_func_abort);
|
||||
signal(SIGABRT,&term_func_abort);
|
||||
}
|
||||
void Utilities::setErrorHandlers()
|
||||
{
|
||||
//d_use_MPI_Abort = use_MPI_Abort;
|
||||
//setMPIErrorHandler( SAMRAI::tbox::SAMRAI_MPI::getSAMRAIWorld() );
|
||||
setTerminateErrorHandler();
|
||||
}
|
||||
/*void Utilities::setMPIErrorHandler( const SAMRAI::tbox::SAMRAI_MPI& mpi )
|
||||
{
|
||||
#if defined(USE_MPI) || defined(HAVE_MPI)
|
||||
if ( mpierr.get()==NULL ) {
|
||||
mpierr = boost::shared_ptr<MPI_Errhandler>( new MPI_Errhandler );
|
||||
MPI_Comm_create_errhandler( MPI_error_handler_fun, mpierr.get() );
|
||||
}
|
||||
MPI_Comm_set_errhandler( mpi.getCommunicator(), *mpierr );
|
||||
MPI_Comm_set_errhandler( MPI_COMM_WORLD, *mpierr );
|
||||
#endif
|
||||
}
|
||||
void Utilities::clearMPIErrorHandler( )
|
||||
{
|
||||
#if defined(USE_MPI) || defined(HAVE_MPI)
|
||||
if ( mpierr.get()!=NULL )
|
||||
MPI_Errhandler_free( mpierr.get() ); // Delete the error handler
|
||||
mpierr.reset();
|
||||
MPI_Comm_set_errhandler( MPI_COMM_SELF, MPI_ERRORS_ARE_FATAL );
|
||||
MPI_Comm_set_errhandler( MPI_COMM_WORLD, MPI_ERRORS_ARE_FATAL );
|
||||
#endif
|
||||
}*/
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to get the memory usage *
|
||||
* Note: this function should be thread-safe *
|
||||
****************************************************************************/
|
||||
#if defined(USE_MAC)
|
||||
// Get the page size on mac
|
||||
static size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||
#endif
|
||||
static size_t N_bytes_initialization = Utilities::getMemoryUsage();
|
||||
size_t Utilities::getMemoryUsage()
|
||||
{
|
||||
size_t N_bytes = 0;
|
||||
#if defined(USE_LINUX)
|
||||
struct mallinfo meminfo = mallinfo();
|
||||
size_t size_hblkhd = static_cast<size_t>( meminfo.hblkhd );
|
||||
size_t size_uordblks = static_cast<size_t>( meminfo.uordblks );
|
||||
N_bytes = static_cast<size_t>( size_hblkhd + size_uordblks );
|
||||
#elif defined(USE_MAC)
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
||||
if (KERN_SUCCESS != task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO, (task_info_t)&t_info,
|
||||
&t_info_count)) {
|
||||
return 0;
|
||||
}
|
||||
N_bytes = t_info.virtual_size;
|
||||
#elif defined(USE_WINDOWS)
|
||||
PROCESS_MEMORY_COUNTERS memCounter;
|
||||
GetProcessMemoryInfo( GetCurrentProcess(), &memCounter, sizeof(memCounter) );
|
||||
N_bytes = memCounter.WorkingSetSize;
|
||||
#endif
|
||||
return N_bytes;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to get the current call stack *
|
||||
****************************************************************************/
|
||||
std::vector<std::string> Utilities::getCallStack()
|
||||
{
|
||||
std::vector<std::string> stack_list;
|
||||
#if defined(USE_ABI)
|
||||
void *trace[100];
|
||||
memset(trace,0,100*sizeof(void*));
|
||||
Dl_info dlinfo;
|
||||
int status;
|
||||
const char *symname;
|
||||
char *demangled=NULL;
|
||||
int trace_size = backtrace(trace,100);
|
||||
for (int i=0; i<trace_size; ++i) {
|
||||
if(!dladdr(trace[i], &dlinfo))
|
||||
continue;
|
||||
symname = dlinfo.dli_sname;
|
||||
demangled = abi::__cxa_demangle(symname, NULL, 0, &status);
|
||||
if(status == 0 && demangled)
|
||||
symname = demangled;
|
||||
std::string object = std::string(dlinfo.dli_fname);
|
||||
std::string function = "";
|
||||
if ( symname!=NULL )
|
||||
function = std::string(symname);
|
||||
if ( i!=0 ) { // Skip the current function
|
||||
std::string stack_item = object + ": " + function;
|
||||
//stack_item = "object: " + object;
|
||||
//stack_item += "function: " + function;
|
||||
stack_list.push_back(stack_item);
|
||||
}
|
||||
if ( demangled!=NULL ) {
|
||||
free(demangled);
|
||||
demangled=NULL;
|
||||
}
|
||||
}
|
||||
#elif defined(USE_WINDOWS)
|
||||
::CONTEXT lContext;
|
||||
::ZeroMemory( &lContext, sizeof( ::CONTEXT ) );
|
||||
::RtlCaptureContext( &lContext );
|
||||
::STACKFRAME64 lFrameStack;
|
||||
::ZeroMemory( &lFrameStack, sizeof( ::STACKFRAME64 ) );
|
||||
lFrameStack.AddrPC.Offset = lContext.Rip;
|
||||
lFrameStack.AddrFrame.Offset = lContext.Rbp;
|
||||
lFrameStack.AddrStack.Offset = lContext.Rsp;
|
||||
lFrameStack.AddrPC.Mode = lFrameStack.AddrFrame.Mode = lFrameStack.AddrStack.Mode = AddrModeFlat;
|
||||
#ifdef _M_IX86
|
||||
DWORD MachineType = IMAGE_FILE_MACHINE_I386;
|
||||
#endif
|
||||
#ifdef _M_X64
|
||||
DWORD MachineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
#endif
|
||||
#ifdef _M_IA64
|
||||
DWORD MachineType = IMAGE_FILE_MACHINE_IA64;
|
||||
#endif
|
||||
while ( 1 ) {
|
||||
int rtn = ::StackWalk64( MachineType, ::GetCurrentProcess(), ::GetCurrentThread(),
|
||||
&lFrameStack, MachineType == IMAGE_FILE_MACHINE_I386 ? 0 : &lContext,
|
||||
NULL, &::SymFunctionTableAccess64, &::SymGetModuleBase64, NULL );
|
||||
if( !rtn )
|
||||
break;
|
||||
if( lFrameStack.AddrPC.Offset == 0 )
|
||||
break;
|
||||
::MEMORY_BASIC_INFORMATION lInfoMemory;
|
||||
::VirtualQuery( ( ::PVOID )lFrameStack.AddrPC.Offset, &lInfoMemory, sizeof( lInfoMemory ) );
|
||||
if ( lInfoMemory.Type==MEM_PRIVATE )
|
||||
continue;
|
||||
::DWORD64 lBaseAllocation = reinterpret_cast< ::DWORD64 >( lInfoMemory.AllocationBase );
|
||||
::TCHAR lNameModule[ 1024 ];
|
||||
::HMODULE hBaseAllocation = reinterpret_cast< ::HMODULE >( lBaseAllocation );
|
||||
::GetModuleFileName( hBaseAllocation, lNameModule, 1024 );
|
||||
PIMAGE_DOS_HEADER lHeaderDOS = reinterpret_cast<PIMAGE_DOS_HEADER>( lBaseAllocation );
|
||||
if ( lHeaderDOS==NULL )
|
||||
continue;
|
||||
PIMAGE_NT_HEADERS lHeaderNT = reinterpret_cast<PIMAGE_NT_HEADERS>( lBaseAllocation + lHeaderDOS->e_lfanew );
|
||||
PIMAGE_SECTION_HEADER lHeaderSection = IMAGE_FIRST_SECTION( lHeaderNT );
|
||||
::DWORD64 lRVA = lFrameStack.AddrPC.Offset - lBaseAllocation;
|
||||
::DWORD64 lNumberSection = ::DWORD64();
|
||||
::DWORD64 lOffsetSection = ::DWORD64();
|
||||
for( int lCnt = ::DWORD64(); lCnt < lHeaderNT->FileHeader.NumberOfSections; lCnt++, lHeaderSection++ ) {
|
||||
::DWORD64 lSectionBase = lHeaderSection->VirtualAddress;
|
||||
::DWORD64 lSectionEnd = lSectionBase + max( lHeaderSection->SizeOfRawData, lHeaderSection->Misc.VirtualSize );
|
||||
if( ( lRVA >= lSectionBase ) && ( lRVA <= lSectionEnd ) ) {
|
||||
lNumberSection = lCnt + 1;
|
||||
lOffsetSection = lRVA - lSectionBase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::stringstream stream;
|
||||
stream << lNameModule << " : 000" << lNumberSection << " : " << reinterpret_cast<void*>(lOffsetSection);
|
||||
stack_list.push_back(stream.str());
|
||||
}
|
||||
#else
|
||||
#warning Stack trace is not supported on this compiler/OS
|
||||
#endif
|
||||
return stack_list;
|
||||
}
|
||||
|
||||
|
||||
// Functions to get the time and timer resolution
|
||||
#if defined(USE_WINDOWS)
|
||||
double Utilities::time()
|
||||
{
|
||||
LARGE_INTEGER end, f;
|
||||
QueryPerformanceFrequency(&f);
|
||||
QueryPerformanceCounter(&end);
|
||||
double time = ((double)end.QuadPart)/((double)f.QuadPart);
|
||||
return time;
|
||||
}
|
||||
double Utilities::tick()
|
||||
{
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency(&f);
|
||||
double resolution = ((double)1.0)/((double)f.QuadPart);
|
||||
return resolution;
|
||||
}
|
||||
#elif defined(USE_LINUX) || defined(USE_MAC)
|
||||
double Utilities::time()
|
||||
{
|
||||
timeval current_time;
|
||||
gettimeofday(¤t_time,NULL);
|
||||
double time = ((double)current_time.tv_sec)+1e-6*((double)current_time.tv_usec);
|
||||
return time;
|
||||
}
|
||||
double Utilities::tick()
|
||||
{
|
||||
timeval start, end;
|
||||
gettimeofday(&start,NULL);
|
||||
gettimeofday(&end,NULL);
|
||||
while ( end.tv_sec==start.tv_sec && end.tv_usec==start.tv_usec )
|
||||
gettimeofday(&end,NULL);
|
||||
double resolution = ((double)(end.tv_sec-start.tv_sec))+1e-6*((double)(end.tv_usec-start.tv_usec));
|
||||
return resolution;
|
||||
}
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
70
common/Utilities.h
Normal file
70
common/Utilities.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef included_Utilities
|
||||
#define included_Utilities
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Utilities is a Singleton class containing basic routines for error
|
||||
* reporting, file manipulations, etc. Included are a set of \ref Macros "macros" that are commonly used.
|
||||
*/
|
||||
namespace Utilities
|
||||
{
|
||||
|
||||
/*!
|
||||
* Aborts the run after printing an error message with file and
|
||||
* linenumber information.
|
||||
*/
|
||||
void abort(const std::string &message, const std::string &filename, const int line);
|
||||
|
||||
|
||||
/*!
|
||||
* Set the behavior of abort
|
||||
* @param printMemory Print the current memory usage (default is true)
|
||||
* @param printStack Print the current call stack (default is true)
|
||||
* @param throwException Throw an exception instead of MPI_Abort (default is false)
|
||||
*/
|
||||
void setAbortBehavior( bool printMemory, bool printStack, bool throwException );
|
||||
|
||||
//! Function to set the error handlers
|
||||
void setErrorHandlers();
|
||||
|
||||
/*!
|
||||
* Function to get the memory availible.
|
||||
* This function will return the total memory availible
|
||||
* Note: depending on the implimentation, this number may be rounded to
|
||||
* to a multiple of the page size.
|
||||
* If this function fails, it will return 0.
|
||||
*/
|
||||
size_t getSystemMemory();
|
||||
|
||||
/*!
|
||||
* Function to get the memory usage.
|
||||
* This function will return the total memory used by the application.
|
||||
* Note: depending on the implimentation, this number may be rounded to
|
||||
* to a multiple of the page size.
|
||||
* If this function fails, it will return 0.
|
||||
*/
|
||||
size_t getMemoryUsage();
|
||||
|
||||
//! Function to get the current call stack
|
||||
std::vector<std::string> getCallStack();
|
||||
|
||||
//! Function to get an arbitrary point in time
|
||||
double time();
|
||||
|
||||
//! Function to get the resolution of time
|
||||
double tick();
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
|
||||
#include "common/UtilityMacros.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
124
common/UtilityMacros.h
Normal file
124
common/UtilityMacros.h
Normal file
@ -0,0 +1,124 @@
|
||||
// This file contains useful macros including ERROR, WARNING, INSIST, ASSERT, etc.
|
||||
#ifndef included_UtilityMacros
|
||||
#define included_UtilityMacros
|
||||
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
/*! \defgroup Macros Set of utility macro functions
|
||||
* \details These functions are a list of C++ macros that are used
|
||||
* for common operations, including checking for errors.
|
||||
* \addtogroup Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/*! \def NULL_STATEMENT
|
||||
* \brief A null statement
|
||||
* \details A statement that does nothing, for insure++ make it something
|
||||
* more complex than a simple C null statement to avoid a warning.
|
||||
*/
|
||||
#ifdef __INSURE__
|
||||
#define NULL_STATEMENT do{if(0) int nullstatement=0 }}while(0)
|
||||
#else
|
||||
#define NULL_STATEMENT
|
||||
#endif
|
||||
|
||||
|
||||
/*! \def NULL_USE(variable)
|
||||
* \brief A null use of a variable
|
||||
* \details A null use of a variable, use to avoid GNU compiler warnings about unused variables.
|
||||
* \param variable Variable to pretend to use
|
||||
*/
|
||||
#define NULL_USE(variable) do { \
|
||||
if(0) {char *temp = (char *)&variable; temp++;} \
|
||||
}while(0)
|
||||
|
||||
|
||||
/*! \def ERROR(MSG)
|
||||
* \brief Throw error
|
||||
* \details Throw an error exception from within any C++ source code. The
|
||||
* macro argument may be any standard ostream expression. The file and
|
||||
* line number of the abort are also printed.
|
||||
* \param MSG Error message to print
|
||||
*/
|
||||
#define ERROR(MSG) do { \
|
||||
Utilities::abort(MSG,__FILE__,__LINE__); \
|
||||
}while(0)
|
||||
|
||||
|
||||
/*! \def WARNING(MSG)
|
||||
* \brief Print a warning
|
||||
* \details Print a warning without exit. Print file and line number of the warning.
|
||||
* \param MSG Warning message to print
|
||||
*/
|
||||
#define WARNING(MSG) do { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << MSG << std::ends; \
|
||||
printf("WARNING: %s\n Warning called in %s on line %i\n",tboxos.str().c_str(),__FILE__,__LINE__); \
|
||||
}while(0)
|
||||
|
||||
|
||||
/*! \def ASSERT(EXP)
|
||||
* \brief Assert error
|
||||
* \details Throw an error exception from within any C++ source code if the
|
||||
* given expression is not true. This is a parallel-friendly version
|
||||
* of assert.
|
||||
* The file and line number of the abort are printed along with the stack trace (if availible).
|
||||
* \param EXP Expression to evaluate
|
||||
*/
|
||||
#define ASSERT(EXP) do { \
|
||||
if ( !(EXP) ) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed assertion: " << #EXP << std::ends; \
|
||||
Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
|
||||
/*! \def INSIST(EXP,MSG)
|
||||
* \brief Insist error
|
||||
* \details Throw an error exception from within any C++ source code if the
|
||||
* given expression is not true. This will also print the given message.
|
||||
* This is a parallel-friendly version of assert.
|
||||
* The file and line number of the abort are printed along with the stack trace (if availible).
|
||||
* \param EXP Expression to evaluate
|
||||
* \param MSG Debug message to print
|
||||
*/
|
||||
#define INSIST(EXP,MSG) do { \
|
||||
if ( !(EXP) ) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed insist: " << #EXP << std::endl; \
|
||||
tboxos << "Message: " << MSG << std::ends; \
|
||||
Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Macro for use when assertions are to be included
|
||||
* only when debugging.
|
||||
*/
|
||||
/*! \def CHECK_ASSERT(EXP)
|
||||
* \brief Assert error (debug only)
|
||||
* \details Throw an error exception from within any C++ source code if the
|
||||
* given expression is not true. This only runs if DEBUG_CHECK_ASSERTIONS
|
||||
* is enabled. If enabled, this is the same as a call to ASSERT.
|
||||
* \param EXP Expression to evaluate
|
||||
*/
|
||||
#ifdef DEBUG_CHECK_ASSERTIONS
|
||||
#define CHECK_ASSERT(EXP) ASSERT(EXP)
|
||||
#else
|
||||
#define CHECK_ASSERT(EXP)
|
||||
#endif
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
#endif
|
@ -7,6 +7,7 @@ ADD_LBPM_TEST( pmmc_cylinder )
|
||||
ADD_LBPM_TEST( TestCylinderAreas )
|
||||
ADD_LBPM_TEST( TestSphereCurvature )
|
||||
ADD_LBPM_TEST_1_2_4( testCommunication )
|
||||
ADD_LBPM_TEST_1_2_4( testUtilities )
|
||||
|
||||
# Sample test that will run with 1, 2, and 4 processors, failing with 4 or more procs
|
||||
ADD_LBPM_TEST_1_2_4( hello_world )
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "D3Q19.h"
|
||||
#include "D3Q7.h"
|
||||
#include "Color.h"
|
||||
#include "Communication.h"
|
||||
#include "common/Communication.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -99,6 +100,8 @@ int main(int argc, char **argv)
|
||||
MPI_Init(&argc,&argv);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
|
||||
// Initialize error handlers
|
||||
Utilities::setErrorHandlers();
|
||||
// parallel domain size (# of sub-domains)
|
||||
int nprocx,nprocy,nprocz;
|
||||
int iproc,jproc,kproc;
|
||||
|
119
tests/testUtilities.cpp
Normal file
119
tests/testUtilities.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "common/Utilities.h"
|
||||
#include "common/UnitTest.h"
|
||||
|
||||
#ifdef USE_MPI
|
||||
#include "mpi.h"
|
||||
#endif
|
||||
|
||||
|
||||
// Function to return the call stack
|
||||
std::vector<std::string> get_call_stack()
|
||||
{
|
||||
std::vector<std::string> stack = Utilities::getCallStack();
|
||||
// Trick compiler to skip inline for this function with fake recursion
|
||||
if ( stack.size() > 10000 ) { stack = get_call_stack(); }
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
// The main function
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rank = 0;
|
||||
#ifdef USE_MPI
|
||||
MPI_Init(&argc,&argv);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
|
||||
#endif
|
||||
UnitTest ut;
|
||||
Utilities::setAbortBehavior( true, true, true );
|
||||
|
||||
// Test the memory usage
|
||||
double t0 = Utilities::time();
|
||||
size_t n_bytes1 = Utilities::getMemoryUsage();
|
||||
double time1 = Utilities::time() - t0;
|
||||
double *tmp = new double[0x100000];
|
||||
NULL_USE(tmp);
|
||||
t0 = Utilities::time();
|
||||
size_t n_bytes2 = Utilities::getMemoryUsage();
|
||||
double time2 = Utilities::time() - t0;
|
||||
delete [] tmp;
|
||||
t0 = Utilities::time();
|
||||
size_t n_bytes3 = Utilities::getMemoryUsage();
|
||||
double time3 = Utilities::time() - t0;
|
||||
std::cout << "Number of bytes used for a basic test: " << n_bytes1 << ", " << n_bytes2 << ", " << n_bytes3 << std::endl;
|
||||
std::cout << " Time to query: " << time1*1e6 << " us, " << time2*1e6 << " us, " << time3*1e6 << " us" << std::endl;
|
||||
if ( n_bytes1==0 ) {
|
||||
ut.failure("getMemoryUsage returns 0");
|
||||
} else {
|
||||
ut.passes("getMemoryUsage returns non-zero");
|
||||
if ( n_bytes2>n_bytes1 )
|
||||
ut.passes("getMemoryUsage increases size");
|
||||
else
|
||||
ut.failure("getMemoryUsage increases size");
|
||||
if ( n_bytes1==n_bytes3 )
|
||||
ut.passes("getMemoryUsage decreases size properly");
|
||||
else
|
||||
ut.expected_failure("getMemoryUsage does not decrease size properly");
|
||||
}
|
||||
|
||||
// Test getting the current call stack
|
||||
std::vector<std::string> call_stack = get_call_stack();
|
||||
if ( rank==0 ) {
|
||||
std::cout << "Call stack:" << std::endl;
|
||||
for (size_t i=0; i<call_stack.size(); i++)
|
||||
std::cout << " " << call_stack[i] << std::endl;
|
||||
}
|
||||
if ( !call_stack.empty() ) {
|
||||
ut.passes("non empty call stack");
|
||||
if ( call_stack[0].find("get_call_stack()") != std::string::npos )
|
||||
ut.passes("call stack decoded function symbols");
|
||||
else
|
||||
ut.expected_failure("call stack was unable to decode function symbols");
|
||||
} else {
|
||||
ut.failure("non empty call stack");
|
||||
}
|
||||
|
||||
// Test catching an error
|
||||
try {
|
||||
ERROR("Test");
|
||||
ut.failure("Failed to catch RAY_ERROR");
|
||||
} catch (...) {
|
||||
ut.passes("Caught RAY_ERROR");
|
||||
}
|
||||
try {
|
||||
throw std::logic_error("test");
|
||||
ut.failure("Failed to catch exception");
|
||||
} catch (...) {
|
||||
ut.passes("Caught exception");
|
||||
}
|
||||
|
||||
// Test time/tick
|
||||
double time = Utilities::time();
|
||||
double res = Utilities::tick();
|
||||
if ( time==0 || res==0 )
|
||||
ut.failure("time/tick");
|
||||
else
|
||||
ut.passes("time/tick");
|
||||
|
||||
// Finished
|
||||
ut.report();
|
||||
size_t N_errors = ut.NumFailGlobal();
|
||||
if ( N_errors==0 )
|
||||
printf("All tests passed\n");
|
||||
#ifdef USE_MPI
|
||||
MPI_Finalize();
|
||||
#endif
|
||||
return (int) N_errors;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user