diff --git a/examples/hello/bpWriter/helloBPWriter_nompi.cpp b/examples/hello/bpWriter/helloBPWriter_nompi.cpp index 7217e12b6ac48e8dafa6062593bb5d4f41c3ca8d..0a08af072a9e949079e48b2172e46c266368a1c1 100644 --- a/examples/hello/bpWriter/helloBPWriter_nompi.cpp +++ b/examples/hello/bpWriter/helloBPWriter_nompi.cpp @@ -29,7 +29,6 @@ int main(int argc, char *argv[]) /*** IO class object: settings and factory of Settings: Variables, * Parameters, Transports, and Execution: Engines */ adios2::IO &bpIO = adios.DeclareIO("BPFile_N2N"); - bpIO.AddTransport("File", {{"Library", "stdio"}}); /** global array: name, { shape (total dimensions) }, { start (local) }, * { count (local) }, all are constant dimensions */ diff --git a/source/adios2/ADIOSTypes.h b/source/adios2/ADIOSTypes.h index 352d62ef2c0ade4981f629e0c65c8252639de082..bb806e56960f57681c2edd4ff500a94fc67103d5 100644 --- a/source/adios2/ADIOSTypes.h +++ b/source/adios2/ADIOSTypes.h @@ -144,7 +144,7 @@ enum class SelectionType // adios defaults #ifdef _WIN32 -const std::string DefaultFileLibrary("stdio"); +const std::string DefaultFileLibrary("fstream"); #else const std::string DefaultFileLibrary("POSIX"); #endif @@ -160,7 +160,7 @@ constexpr size_t DefaultMaxBufferSize(std::numeric_limits<size_t>::max() - 1); /** default buffer growth factor. Needs to be studied * for optimizing applications*/ -constexpr float DefaultBufferGrowthFactor(1.05); +constexpr float DefaultBufferGrowthFactor(1.05f); /** default size for writing/reading files using POSIX/fstream/stdio write * 2Gb - 100Kb (tolerance)*/ diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt index 6c77dc0ce4f39d81faf0f75a551d27f4ce30e264..ce6a31efdf961afe5dce50bbb256c2d5f53ee7de 100644 --- a/source/adios2/CMakeLists.txt +++ b/source/adios2/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(adios2 #helper helper/adiosMath.cpp + helper/adiosMPIFunctions.cpp helper/adiosString.cpp helper/adiosSystem.cpp helper/adiosType.cpp diff --git a/source/adios2/core/ADIOS.h b/source/adios2/core/ADIOS.h index c9e9937076f33f3d15f06c0d4cc02f304f38a2ef..618a33232bf29cc7d931dc36d3b0932166d85818 100644 --- a/source/adios2/core/ADIOS.h +++ b/source/adios2/core/ADIOS.h @@ -33,7 +33,9 @@ class ADIOS public: /** Passed from parallel constructor, MPI_Comm is a pointer itself. */ MPI_Comm m_MPIComm; - std::string m_HostLanguage = "C++"; ///< changed by language bindings + + /** Changed by language bindings */ + std::string m_HostLanguage = "C++"; /** * @brief Constructor for MPI applications WITH a XML config file @@ -66,6 +68,13 @@ public: */ ADIOS(const bool debugMode = false); + /** + * Delete copy constructor explicitly. Objects shouldn't be allowed to be + * redefined. Use smart pointers if this is absolutely necessary. + * @param adios reference to another adios object + */ + ADIOS(const ADIOS &adios) = delete; + ~ADIOS() = default; /** @@ -81,16 +90,18 @@ public: IO &DeclareIO(const std::string ioName); /** - * Retrieve an already defined IO object + * Retrieve an already defined IO object. Make sure IO was previously + * created with DeclareIO. Otherwise, throws an exception in debug mode. + * @return reference to existing IO object inside ADIOS */ IO &GetIO(const std::string name); -protected: // no const member to allow default empty and copy constructors +private: /** XML File to be read containing configuration information */ - std::string m_ConfigFile; + const std::string m_ConfigFile; /** if true will do more checks, exceptions, warnings, expect slower code */ - bool m_DebugMode = false; + const bool m_DebugMode = false; /** transforms associated with ADIOS run */ std::vector<std::shared_ptr<Transform>> m_Transforms; diff --git a/source/adios2/helper/adiosFunctions.h b/source/adios2/helper/adiosFunctions.h index af3e98f18f93c75e745c2903ce5f7ab4e98c662f..e088875c7a4ec65bdbbed370a710b71dc834c71f 100644 --- a/source/adios2/helper/adiosFunctions.h +++ b/source/adios2/helper/adiosFunctions.h @@ -12,9 +12,10 @@ #ifndef ADIOS2_HELPER_ADIOSFUNCTIONS_H_ #define ADIOS2_HELPER_ADIOSFUNCTIONS_H_ -#include "adios2/helper/adiosMath.h" //math functions (cmath, algorithm) -#include "adios2/helper/adiosMemory.h" //memcpy, std::copy, insert, resize -#include "adios2/helper/adiosString.h" //std::string manipulation +#include "adios2/helper/adiosMPIFunctions.h" //MPI functions (Bcast, send/recv) +#include "adios2/helper/adiosMath.h" //math functions (cmath, algorithm) +#include "adios2/helper/adiosMemory.h" //memcpy, std::copy, insert, resize +#include "adios2/helper/adiosString.h" //std::string manipulation #include "adios2/helper/adiosSystem.h" //OS functionality, POSIX, filesystem #include "adios2/helper/adiosType.h" //Type casting, conversion, checks, etc. #include "adios2/helper/adiosXML.h" //XML parsing diff --git a/source/adios2/helper/adiosMPIFunctions.cpp b/source/adios2/helper/adiosMPIFunctions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd550b00ef5c2e1fb0f4baaa9f83a3a8da49cbd3 --- /dev/null +++ b/source/adios2/helper/adiosMPIFunctions.cpp @@ -0,0 +1,46 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adiosMPIFunctions.cpp + * + * Created on: Jul 20, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ +#include "adiosMPIFunctions.h" + +#include "adios2/ADIOSMPI.h" +#include "adios2/ADIOSTypes.h" + +namespace adios2 +{ + +std::string BroadcastString(const std::string &input, MPI_Comm mpiComm, + const int rankSource) +{ + int rank; + MPI_Comm_rank(mpiComm, &rank); + size_t length = 0; + std::string output; + + if (rank == rankSource) + { + length = input.size(); + MPI_Bcast(&length, 1, ADIOS2_MPI_SIZE_T, rankSource, mpiComm); + + MPI_Bcast(const_cast<char *>(input.data()), length, MPI_CHAR, + rankSource, mpiComm); + + return input; + } + else + { + MPI_Bcast(&length, 1, ADIOS2_MPI_SIZE_T, rankSource, mpiComm); + output.resize(length); + MPI_Bcast(const_cast<char *>(output.data()), length, MPI_CHAR, + rankSource, mpiComm); + } + return output; +} + +} // end namespace adios2 diff --git a/source/adios2/helper/adiosMPIFunctions.h b/source/adios2/helper/adiosMPIFunctions.h new file mode 100644 index 0000000000000000000000000000000000000000..a79345d6af4b735a57f718887c6d21f38b8878bb --- /dev/null +++ b/source/adios2/helper/adiosMPIFunctions.h @@ -0,0 +1,36 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adiosMPIFunctions.h : collection of MPI functions used across adios2 + * + * Created on: Jul 20, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_ +#define ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_ + +/// \cond EXCLUDE_FROM_DOXYGEN +#include <string> +/// \endcond + +#include "adios2/ADIOSMPICommOnly.h" + +namespace adios2 +{ + +/** + * rankSource: owns a string and broadcast to all other ranks + * Others: receive std::vector<char> and copy to a string + * @param mpiComm MPI communicator defining all ranks and size domain + * @param input string input from rankSource + * @param rankSource rank that broadcast the string, (default = 0) + * @return input contents for each rank + */ +std::string BroadcastString(const std::string &input, MPI_Comm mpiComm, + const int rankSource = 0); + +} // end namespace adios2 + +#endif /* ADIOS2_HELPER_ADIOMPIFUNCTIONS_H_ */ diff --git a/source/adios2/helper/adiosMemory.h b/source/adios2/helper/adiosMemory.h index 20ab7739562cd8cb7650ae0f136020f35f1ffe72..ad5dd0116d123da9a885c99ca940efa1e825b969 100644 --- a/source/adios2/helper/adiosMemory.h +++ b/source/adios2/helper/adiosMemory.h @@ -83,6 +83,14 @@ void MemcpyToBufferThreads(std::vector<char> &buffer, size_t &position, const T *source, size_t size, const unsigned int threads = 1); +/** + * Cast an element to uint64 and insert to a buffer + * @param buffer data destination + * @param element to be added to buffer + */ +template <class T> +void InsertU64(std::vector<char> &buffer, const T element) noexcept; + } // end namespace adios #include "adiosMemory.inl" diff --git a/source/adios2/helper/adiosMemory.inl b/source/adios2/helper/adiosMemory.inl index ee50425e2b1083eb2e076d8579b631de49b406eb..0eaa2662a765b1e8e5523c624d5ce853b3194a10 100644 --- a/source/adios2/helper/adiosMemory.inl +++ b/source/adios2/helper/adiosMemory.inl @@ -25,7 +25,7 @@ namespace adios2 template <class T> void InsertToBuffer(std::vector<char> &buffer, const T *source, - const std::size_t elements) noexcept + const size_t elements) noexcept { const char *src = reinterpret_cast<const char *>(source); buffer.insert(buffer.end(), src, src + elements * sizeof(T)); @@ -159,6 +159,13 @@ void MemcpyToBufferThreads(std::vector<char> &buffer, size_t &position, } } +template <class T> +void InsertU64(std::vector<char> &buffer, const T element) noexcept +{ + const uint64_t element64 = static_cast<const uint64_t>(element); + InsertToBuffer(buffer, &element64); +} + } // end namespace #endif /* ADIOS2_HELPER_ADIOSMEMORY_INL_ */ diff --git a/source/adios2/helper/adiosSystem.cpp b/source/adios2/helper/adiosSystem.cpp index 8e0b967c5e0d07b8620c29dce7beadaf8693a2f6..233f2d096cffde6bb1b482c75bcdcbbc5a36ee72 100644 --- a/source/adios2/helper/adiosSystem.cpp +++ b/source/adios2/helper/adiosSystem.cpp @@ -9,7 +9,7 @@ */ #include "adiosSystem.h" -#include <ctime> //std::ctime +#include <ctime> #include <chrono> //system_clock, now @@ -19,6 +19,11 @@ #include "adios2/ADIOSTypes.h" #include "adios2/helper/adiosString.h" +// remove ctime warning on Windows +#ifdef _WIN32 +#pragma warning(disable : 4996) +#endif + namespace adios2 { @@ -38,44 +43,7 @@ std::string LocalTimeDate() noexcept std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - return std::string(std::ctime(&now)); -} - -std::string BroadcastString(const std::string &input, MPI_Comm mpiComm) -{ - std::string receivedInput; - size_t characterCount = 0; - - int rank; - MPI_Comm_rank(mpiComm, &rank); - - if (rank == 0) // sender - { - characterCount = input.size(); - - // broadcast size for allocation - MPI_Bcast(&characterCount, 1, ADIOS2_MPI_SIZE_T, 0, mpiComm); - - // broadcast contents - MPI_Bcast(const_cast<char *>(input.c_str()), - static_cast<int>(characterCount), MPI_CHAR, 0, mpiComm); - - return input; - } - else // receivers - { - // receive size - MPI_Bcast(&characterCount, 1, ADIOS2_MPI_SIZE_T, 0, mpiComm); - - // allocate receiver - std::vector<char> stringReceiver(characterCount); - MPI_Bcast(stringReceiver.data(), static_cast<int>(characterCount), - MPI_CHAR, 0, mpiComm); - - receivedInput.assign(stringReceiver.begin(), stringReceiver.end()); - } - - return receivedInput; + return std::string(ctime(&now)); } } // end namespace adios diff --git a/source/adios2/helper/adiosSystem.h b/source/adios2/helper/adiosSystem.h index 844e73e47fbb4fbaed5772f28abb9a2569d1634f..650cba40987401a9452304de0a7e9d7b574307fd 100644 --- a/source/adios2/helper/adiosSystem.h +++ b/source/adios2/helper/adiosSystem.h @@ -17,8 +17,6 @@ #include <vector> /// \endcond -#include "adios2/ADIOSMPICommOnly.h" - namespace adios2 { @@ -43,15 +41,6 @@ bool IsLittleEndian() noexcept; */ std::string LocalTimeDate() noexcept; -/** - * Rank 0: opens file, dumps contents string and broadcast. - * Others: receive std::vector<char> and copy to a string - * @param fileName - * @param mpiComm - * @return fileContents as a single string - */ -std::string BroadcastString(const std::string &input, MPI_Comm mpiComm); - } // end namespace adios #endif /* ADIOS2_HELPER_ADIOSSYSTEM_H_ */ diff --git a/source/adios2/helper/adiosXML.cpp b/source/adios2/helper/adiosXML.cpp index 0045c4de336d3ec8b71fb5c85dbd1b5729ad7ec5..65d1cdd4c9fd2577687275a2542fdb8c0b5af8f7 100644 --- a/source/adios2/helper/adiosXML.cpp +++ b/source/adios2/helper/adiosXML.cpp @@ -6,6 +6,7 @@ * * Created on: May 17, 2017 * Author: William F Godoy godoywf@ornl.gov + * Chuck Atkins chuck.atkins@kitware.com */ #include "adiosXML.h" @@ -16,6 +17,7 @@ #include "adios2/ADIOSMPI.h" #include "adios2/ADIOSTypes.h" +#include "adios2/helper/adiosMPIFunctions.h" #include "adios2/helper/adiosString.h" #include <pugixml.hpp> @@ -23,93 +25,124 @@ namespace adios2 { -Params InitParametersXML(pugi::xml_node node, bool debugMode) +Params InitParametersXML(const pugi::xml_node &node, const bool debugMode) { Params params; - for (pugi::xml_node paramNode : node.children("parameter")) + for (const pugi::xml_node paramNode : node.children("parameter")) { - pugi::xml_attribute attrKey = paramNode.attribute("key"); - if (!attrKey) + const pugi::xml_attribute key = paramNode.attribute("key"); + if (debugMode) { - if (debugMode) + if (!key) { throw std::invalid_argument("ERROR: XML: No \"key\" attribute " - "found on <parameter> element."); + "found on <parameter> element, in " + "call to ADIOS constructor\n"); } - continue; } - pugi::xml_attribute attrValue = paramNode.attribute("value"); - if (!attrValue) + const pugi::xml_attribute value = paramNode.attribute("value"); + + if (debugMode) { - if (debugMode) + if (!value) { + throw std::invalid_argument("ERROR: XML: No \"value\" " "attribute found on <parameter> " - "element."); + "element, for key " + + std::string(key.value()) + + ", in call to ADIOS constructor\n"); + continue; } - continue; } - params.emplace(attrKey.value(), attrValue.value()); + params.emplace(key.value(), value.value()); } return params; } -void InitIOXML(const pugi::xml_node ioNode, const MPI_Comm mpiComm, +void InitIOXML(const pugi::xml_node &ioNode, const MPI_Comm mpiComm, const bool debugMode, std::vector<std::shared_ptr<Transform>> &transforms, std::map<std::string, IO> &ios) { // Extract <io name=""> attribute - pugi::xml_attribute nameAttr = ioNode.attribute("name"); + const pugi::xml_attribute nameAttr = ioNode.attribute("name"); if (!nameAttr) { if (debugMode) { - throw std::invalid_argument( - "ERROR: XML: No \"name\" attribute found on <io> element."); + throw std::invalid_argument("ERROR: XML: No \"name\" attribute " + "found on <io> element, in call to " + "ADIOS constructor.\n"); } return; } - std::string ioName = nameAttr.value(); + const std::string ioName = nameAttr.value(); // Build the IO object auto ioIt = ios.emplace(ioName, IO(ioName, mpiComm, true, debugMode)); IO &io = ioIt.first->second; // Extract <engine> element - pugi::xml_node engineNode = ioNode.child("engine"); - if (!engineNode) + if (debugMode) { - throw std::invalid_argument( - "ERROR: XML: No <engine> element found in <io> element."); + unsigned int count = 0; + + for (const pugi::xml_node engineNode : ioNode.children("engine")) + { + ++count; + if (count == 2) + { + throw std::invalid_argument( + "ERROR: XML only one <engine> element " + "can exist inside an <io> element from io " + + ioName + ", in call to ADIOS constructor\n"); + } + } } - pugi::xml_attribute engineTypeAttr = engineNode.attribute("type"); - if (!engineTypeAttr) + + const pugi::xml_node engineNode = ioNode.child("engine"); + if (engineNode) { - throw std::invalid_argument( - "ERROR: XML: No \"type\" attribute found on <engine> element."); + const pugi::xml_attribute engineTypeAttr = engineNode.attribute("type"); + + if (debugMode) + { + if (!engineTypeAttr) + { + throw std::invalid_argument( + "ERROR: XML: No \"type\" attribute " + "found on <engine> element, in call to " + "ADIOS constructor"); + } + } + + io.SetEngine(engineTypeAttr.value()); } - io.SetEngine(engineTypeAttr.value()); // Process <engine> parameters io.SetParameters(InitParametersXML(engineNode, debugMode)); // Extract and process <transport> elements - for (pugi::xml_node transportNode : ioNode.children("transport")) + for (const pugi::xml_node transportNode : ioNode.children("transport")) { - pugi::xml_attribute typeAttr = transportNode.attribute("type"); - if (!typeAttr) + const pugi::xml_attribute typeXMLAttribute = + transportNode.attribute("type"); + + if (debugMode) { - if (debugMode) + if (!typeXMLAttribute) { + throw std::invalid_argument("ERROR: XML: No \"type\" attribute " - "found on <transport> element."); + "found on <transport> element, in " + "call to ADIOS constructor\n"); } - continue; } - io.AddTransport(typeAttr.value(), + + io.AddTransport(typeXMLAttribute.value(), InitParametersXML(transportNode, debugMode)); } } @@ -122,49 +155,43 @@ void InitXML(const std::string configXML, const MPI_Comm mpiComm, int mpiRank; MPI_Comm_rank(mpiComm, &mpiRank); std::string fileContents; - unsigned long long len; // Read the file on rank 0 and broadcast it to everybody else if (mpiRank == 0) { fileContents = FileToString(configXML); - len = static_cast<unsigned long long>(fileContents.size()); - } - MPI_Bcast(&len, 1, MPI_UNSIGNED_LONG, 0, mpiComm); - if (mpiRank != 0) - { - fileContents.resize(len); } - MPI_Bcast(const_cast<char *>(fileContents.data()), len, MPI_CHAR, 0, - mpiComm); + + fileContents = BroadcastString(fileContents, mpiComm); pugi::xml_document doc; auto parse_result = doc.load_buffer_inplace( const_cast<char *>(fileContents.data()), fileContents.size()); - if (!parse_result) + + if (debugMode) { - if (debugMode) + if (!parse_result) { throw std::invalid_argument( - std::string("ERROR: XML: Parse error: ") + - parse_result.description()); + "ERROR: XML: parse error in file " + configXML + + " description: " + std::string(parse_result.description()) + + ", in call to ADIOS constructor\n"); } - return; } - pugi::xml_node configNode = doc.child("adios-config"); - if (!configNode) + const pugi::xml_node configNode = doc.child("adios-config"); + + if (debugMode) { - if (debugMode) + if (!configNode) { throw std::invalid_argument( - "ERROR: XML: No <adios-config> element found"); + "ERROR: XML: No <adios-config> element found in file " + + configXML + ", in call to ADIOS constructor\n"); } - return; } - ios.clear(); - for (pugi::xml_node ioNode : configNode.children("io")) + for (const pugi::xml_node ioNode : configNode.children("io")) { InitIOXML(ioNode, mpiComm, debugMode, transforms, ios); } diff --git a/source/adios2/mpidummy.cpp b/source/adios2/mpidummy.cpp index c6730df1c9a7d60c8d48b9cf8f4a74faa99b8ca5..c97938e95d78063c73195ac0cacd2275335f516c 100644 --- a/source/adios2/mpidummy.cpp +++ b/source/adios2/mpidummy.cpp @@ -26,7 +26,6 @@ #define open64 open #endif */ - #include <cinttypes> #include <cstdio> #include <cstring> @@ -34,6 +33,12 @@ #include <chrono> #include <string> +// remove warnings on Windows +#ifdef _WIN32 +#pragma warning(disable : 4996) // fopen +#pragma warning(disable : 4477) // strcpy, sprintf +#endif + namespace adios2 { @@ -296,7 +301,7 @@ int MPI_File_open(MPI_Comm /*comm*/, const char *filename, int amode, } mode += "b"; - *fh = fopen(filename, mode.c_str()); + *fh = std::fopen(filename, mode.c_str()); if (!*fh) { std::snprintf(mpierrmsg, MPI_MAX_ERROR_STRING, "File not found: %s", @@ -310,10 +315,10 @@ int MPI_File_close(MPI_File *fh) { return fclose(*fh); } int MPI_File_get_size(MPI_File fh, MPI_Offset *size) { - long curpos = ftell(fh); + long curpos = std::ftell(fh); fseek(fh, 0, SEEK_END); // go to end, returned is the size in bytes - long endpos = ftell(fh); - fseek(fh, curpos, SEEK_SET); // go back where we were + long endpos = std::ftell(fh); + std::fseek(fh, curpos, SEEK_SET); // go back where we were *size = static_cast<MPI_Offset>(endpos); // printf("MPI_File_get_size: fh=%d, size=%lld\n", fh, *size); return MPI_SUCCESS; @@ -325,7 +330,7 @@ int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, // FIXME: int count can read only 2GB (*datatype size) array at max size_t bytes_to_read = static_cast<size_t>(count) * datatype; size_t bytes_read; - bytes_read = fread(buf, 1, bytes_to_read, fh); + bytes_read = std::fread(buf, 1, bytes_to_read, fh); if (bytes_read != bytes_to_read) { std::snprintf(mpierrmsg, MPI_MAX_ERROR_STRING, @@ -343,7 +348,7 @@ int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence) { - return fseek(fh, offset, whence) == MPI_SUCCESS; + return std::fseek(fh, offset, whence) == MPI_SUCCESS; } int MPI_Get_count(const MPI_Status *status, MPI_Datatype, int *count) diff --git a/source/adios2/mpidummy.h b/source/adios2/mpidummy.h index f4607ea204c313de54f37a1a8b0a2f484fc50ade..5457f0dd7788c55653787571271a4294878d9079 100644 --- a/source/adios2/mpidummy.h +++ b/source/adios2/mpidummy.h @@ -14,9 +14,6 @@ #include <cstdint> #include <cstdio> -/// \cond EXCLUDE_FROM_DOXYGEN -/// \endcond - namespace adios2 { diff --git a/source/adios2/toolkit/capsule/Capsule.h b/source/adios2/toolkit/capsule/Capsule.h index 09ba7fd4c3daf7b992decd735c9a68a37442d142..0534e75ec69912a4b012befb0249048c9fad2a12 100644 --- a/source/adios2/toolkit/capsule/Capsule.h +++ b/source/adios2/toolkit/capsule/Capsule.h @@ -61,8 +61,8 @@ public: size_t GetAvailableDataSize() const; - virtual void ResizeData(size_t size); ///< resize data buffer - virtual void ResizeMetadata(size_t size); ///< resize metadata buffer + virtual void ResizeData(const size_t size); ///< resize data buffer + virtual void ResizeMetadata(const size_t size); ///< resize metadata buffer protected: const bool m_DebugMode = false; ///< true: extra exception checks diff --git a/source/adios2/toolkit/capsule/heap/STLVector.cpp b/source/adios2/toolkit/capsule/heap/STLVector.cpp index 57daca380aa539c9f7b765617bee9fb71132717e..5221f00faa3245c66a14d3dd44708d34a40b1f81 100644 --- a/source/adios2/toolkit/capsule/heap/STLVector.cpp +++ b/source/adios2/toolkit/capsule/heap/STLVector.cpp @@ -41,11 +41,12 @@ void STLVector::ResizeData(const size_t size) { m_Data.resize(size); } - catch (std::bad_alloc &e) + catch (...) { - throw std::runtime_error("ERROR: bad_alloc detected when resizing " - "data buffer with size " + - std::to_string(size) + "\n"); + std::throw_with_nested( + std::runtime_error("ERROR: possible overflow when resizing " + "data buffer with size " + + std::to_string(size) + "\n")); } } else @@ -62,11 +63,12 @@ void STLVector::ResizeMetadata(const size_t size) { m_Metadata.resize(size); } - catch (std::bad_alloc &e) + catch (...) { - throw std::runtime_error("ERROR: bad_alloc detected when resizing " - "metadata buffer with size " + - std::to_string(size) + "\n"); + std::throw_with_nested( + std::runtime_error("ERROR: possible overflow when resizing " + "metadata buffer with size " + + std::to_string(size) + "\n")); } } else diff --git a/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp b/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp index 62486da1d39580ba1e211928cf9a1bbb5ca9cf60..21ba4efcd636c739cfa8a3517d03f4d7db9e14c5 100644 --- a/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp +++ b/source/adios2/toolkit/capsule/shmem/ShmSystemV.cpp @@ -2,10 +2,10 @@ * Distributed under the OSI-approved Apache License, Version 2.0. See * accompanying file Copyright.txt for details. * - * ShmSystemV.cpp + * ShmSystemV.cpp : implementation of ShmSystemV class * * Created on: Dec 22, 2016 - * Author: wfg + * Author: William F Godoy godoywf@ornl.gov */ #include "ShmSystemV.h" diff --git a/source/adios2/toolkit/capsule/shmem/ShmSystemV.h b/source/adios2/toolkit/capsule/shmem/ShmSystemV.h index df997af7bf10a2a6cd46939c3fc544ffe15e89e6..b1bf0f48ea2c28a77c9571137c7e66d803b7eb09 100644 --- a/source/adios2/toolkit/capsule/shmem/ShmSystemV.h +++ b/source/adios2/toolkit/capsule/shmem/ShmSystemV.h @@ -1,6 +1,12 @@ /* * Distributed under the OSI-approved Apache License, Version 2.0. See * accompanying file Copyright.txt for details. + * + * ShmSystemV.h : ShmSystem class as a thin wrapper to a shared memory capsule + * using POSIX SystemV + * + * Created on: Dec 22, 2016 + * Author: William F Godoy godoywf@ornl.gov */ #ifndef ADIOS2_TOOLKIT_CAPSULE_SHMEM_SHMSYSTEMV_H_ diff --git a/source/adios2/toolkit/format/bp1/BP1Base.cpp b/source/adios2/toolkit/format/bp1/BP1Base.cpp index 387366b43fffc86c6736aa54d8799d3255dfd288..ecc990f38bef44f499eb417f0e9e609845ae5a6c 100644 --- a/source/adios2/toolkit/format/bp1/BP1Base.cpp +++ b/source/adios2/toolkit/format/bp1/BP1Base.cpp @@ -170,6 +170,8 @@ void BP1Base::InitParameterBufferGrowth(const std::string value) if (m_DebugMode) { bool success = true; + std::string description; + try { m_GrowthFactor = std::stof(value); @@ -177,6 +179,7 @@ void BP1Base::InitParameterBufferGrowth(const std::string value) catch (std::exception &e) { success = false; + description = std::string(e.what()); } if (!success || m_GrowthFactor <= 1.f) @@ -184,7 +187,8 @@ void BP1Base::InitParameterBufferGrowth(const std::string value) throw std::invalid_argument( "ERROR: BufferGrowthFactor value " "can't be less or equal than 1 (default = 1.5), or couldn't " - "convert number, in call to Open\n"); + "convert number,\n additional description:" + + description + "\n, in call to Open\n"); } } else @@ -195,15 +199,14 @@ void BP1Base::InitParameterBufferGrowth(const std::string value) void BP1Base::InitParameterInitBufferSize(const std::string value) { - const std::string errorMessage( - "ERROR: wrong value for InitialBufferSize, it must be larger than " - "16Kb (minimum default), in call to Open\n"); - if (m_DebugMode) { if (value.size() < 2) { - throw std::invalid_argument(errorMessage); + throw std::invalid_argument( + "ERROR: wrong value for InitialBufferSize, it must be larger " + "than " + "16Kb (minimum default), in call to Open\n"); } } @@ -215,6 +218,8 @@ void BP1Base::InitParameterInitBufferSize(const std::string value) if (m_DebugMode) { bool success = true; + std::string description; + try { bufferSize = static_cast<size_t>(std::stoul(number) * factor); @@ -222,11 +227,16 @@ void BP1Base::InitParameterInitBufferSize(const std::string value) catch (std::exception &e) { success = false; + description = std::string(e.what()); } if (!success || bufferSize < DefaultInitialBufferSize) // 16384b { - throw std::invalid_argument(errorMessage); + throw std::invalid_argument( + "ERROR: wrong value for InitialBufferSize, it must be larger " + "than " + "16Kb (minimum default), additional description: " + + description + " in call to Open\n"); } } else @@ -239,17 +249,15 @@ void BP1Base::InitParameterInitBufferSize(const std::string value) void BP1Base::InitParameterMaxBufferSize(const std::string value) { - const std::string errorMessage( - "ERROR: couldn't convert value of max_buffer_size IO " - "SetParameter, valid syntax: MaxBufferSize=10Gb, " - "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum default), " - " in call to Open"); - if (m_DebugMode) { if (value.size() < 2) { - throw std::invalid_argument(errorMessage); + throw std::invalid_argument( + "ERROR: couldn't convert value of max_buffer_size IO " + "SetParameter, valid syntax: MaxBufferSize=10Gb, " + "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum default), " + " in call to Open"); } } @@ -260,6 +268,8 @@ void BP1Base::InitParameterMaxBufferSize(const std::string value) if (m_DebugMode) { bool success = true; + std::string description; + try { m_MaxBufferSize = static_cast<size_t>(std::stoul(number) * factor); @@ -267,11 +277,17 @@ void BP1Base::InitParameterMaxBufferSize(const std::string value) catch (std::exception &e) { success = false; + description = std::string(e.what()); } if (!success || m_MaxBufferSize < 16 * 1024) // 16384b { - throw std::invalid_argument(errorMessage); + throw std::invalid_argument( + "ERROR: couldn't convert value of max_buffer_size IO " + "SetParameter, valid syntax: MaxBufferSize=10Gb, " + "MaxBufferSize=1000Mb, MaxBufferSize=16Kb (minimum default), " + "\nadditional description: " + + description + " in call to Open"); } } else @@ -287,6 +303,7 @@ void BP1Base::InitParameterThreads(const std::string value) if (m_DebugMode) { bool success = true; + std::string description; try { @@ -295,13 +312,15 @@ void BP1Base::InitParameterThreads(const std::string value) catch (std::exception &e) { success = false; + description = std::string(e.what()); } if (!success || threads < 1) { throw std::invalid_argument( "ERROR: value in Threads=value in IO SetParameters must be " - "an integer >= 1 (default), in call to Open\n"); + "an integer >= 1 (default) \nadditional description: " + + description + "\n, in call to Open\n"); } } else @@ -319,6 +338,7 @@ void BP1Base::InitParameterVerbose(const std::string value) if (m_DebugMode) { bool success = true; + std::string description; try { @@ -327,13 +347,15 @@ void BP1Base::InitParameterVerbose(const std::string value) catch (std::exception &e) { success = false; + description = std::string(e.what()); } if (!success || verbosity < 0 || verbosity > 5) { throw std::invalid_argument( "ERROR: value in Verbose=value in IO SetParameters must be " - "an integer in the range [0,5], in call to Open\n"); + "an integer in the range [0,5], \nadditional description: " + + description + "\n, in call to Open\n"); } } else diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.cpp b/source/adios2/toolkit/format/bp1/BP1Writer.cpp index c7b9210b3e63d6ab65eb7d2590da3cc3439ac624..7bc9f34b18e379806764b3c36808272b03d67e76 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.cpp +++ b/source/adios2/toolkit/format/bp1/BP1Writer.cpp @@ -42,7 +42,7 @@ void BP1Writer::WriteProcessGroupIndex( dataPosition += 8; // skip pg length (8) const std::size_t metadataPGLengthPosition = metadataBuffer.size(); - metadataBuffer.insert(metadataBuffer.end(), 2, 0); // skip pg length (2) + metadataBuffer.insert(metadataBuffer.end(), 2, '\0'); // skip pg length (2) // write name to metadata const std::string name(std::to_string(m_BP1Aggregator.m_RankMPI)); @@ -56,7 +56,8 @@ void BP1Writer::WriteProcessGroupIndex( WriteNameRecord(name, dataBuffer, dataPosition); // processID in metadata, - const uint32_t processID = static_cast<uint32_t>(m_BP1Aggregator.m_RankMPI); + const uint32_t processID = + static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI); InsertToBuffer(metadataBuffer, &processID); // skip coordination var in data ....what is coordination var? dataPosition += 4; @@ -71,22 +72,23 @@ void BP1Writer::WriteProcessGroupIndex( CopyToBuffer(dataBuffer, dataPosition, &m_MetadataSet.TimeStep); // offset to pg in data in metadata which is the current absolute position - InsertToBuffer(metadataBuffer, reinterpret_cast<uint64_t *>( - &m_HeapBuffer.m_DataAbsolutePosition)); + InsertU64(metadataBuffer, m_HeapBuffer.m_DataAbsolutePosition); // Back to writing metadata pg index length (length of group) - const uint16_t metadataPGIndexLength = - metadataBuffer.size() - metadataPGLengthPosition - 2; + const uint16_t metadataPGIndexLength = static_cast<const uint16_t>( + metadataBuffer.size() - metadataPGLengthPosition - 2); + size_t backPosition = metadataPGLengthPosition; CopyToBuffer(metadataBuffer, backPosition, &metadataPGIndexLength); // DONE With metadataBuffer // here write method in data const std::vector<uint8_t> methodIDs = GetTransportIDs(transportsTypes); - const uint8_t methodsCount = methodIDs.size(); + const uint8_t methodsCount = static_cast<const uint8_t>(methodIDs.size()); CopyToBuffer(dataBuffer, dataPosition, &methodsCount); // count // methodID (1) + method params length(2), no parameters for now - const uint16_t methodsLength = methodIDs.size() * 3; + const uint16_t methodsLength = + static_cast<const uint16_t>(methodsCount * 3); CopyToBuffer(dataBuffer, dataPosition, &methodsLength); // length @@ -253,23 +255,19 @@ void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, { if (offsets.empty()) { - for (const auto &localDimension : localDimensions) + for (const auto localDimension : localDimensions) { - InsertToBuffer(buffer, - reinterpret_cast<const uint64_t *>(&localDimension)); - buffer.insert(buffer.end(), 2 * sizeof(uint64_t), 0); + InsertU64(buffer, localDimension); + buffer.insert(buffer.end(), 2 * sizeof(uint64_t), '\0'); } } else { for (unsigned int d = 0; d < localDimensions.size(); ++d) { - InsertToBuffer(buffer, reinterpret_cast<const uint64_t *>( - &localDimensions[d])); - InsertToBuffer(buffer, reinterpret_cast<const uint64_t *>( - &globalDimensions[d])); - InsertToBuffer(buffer, - reinterpret_cast<const uint64_t *>(&offsets[d])); + InsertU64(buffer, localDimensions[d]); + InsertU64(buffer, globalDimensions[d]); + InsertU64(buffer, offsets[d]); } } } @@ -290,8 +288,9 @@ void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, CopyToBuffer(buffer, position, &no); } - CopyToBuffer(buffer, position, - reinterpret_cast<const uint64_t *>(&dimension)); + const uint64_t dimension64 = static_cast<const uint64_t>(dimension); + + CopyToBuffer(buffer, position, &dimension64); }; // BODY Starts here @@ -326,7 +325,7 @@ void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, void BP1Writer::WriteNameRecord(const std::string name, std::vector<char> &buffer) noexcept { - const uint16_t length = name.length(); + const uint16_t length = static_cast<const uint16_t>(name.length()); InsertToBuffer(buffer, &length); InsertToBuffer(buffer, name.c_str(), length); } @@ -335,7 +334,7 @@ void BP1Writer::WriteNameRecord(const std::string name, std::vector<char> &buffer, size_t &position) noexcept { - const uint16_t length = name.length(); + const uint16_t length = static_cast<const uint16_t>(name.length()); CopyToBuffer(buffer, position, &length); CopyToBuffer(buffer, position, name.c_str(), length); } @@ -434,23 +433,22 @@ void BP1Writer::FlattenMetadata() noexcept lf_IndexCountLength(m_MetadataSet.AttributesIndices, attributesCount, attributesLength); - const size_t footerSize = (pgLength + 16) + (varsLength + 12) + - (attributesLength + 12) + - m_MetadataSet.MiniFooterSize; + const size_t footerSize = static_cast<const size_t>( + (pgLength + 16) + (varsLength + 12) + (attributesLength + 12) + + m_MetadataSet.MiniFooterSize); auto &buffer = m_HeapBuffer.m_Data; auto &position = m_HeapBuffer.m_DataPosition; // reserve data to fit metadata, - // must replace with growth buffer strategy + // must replace with growth buffer strategy? m_HeapBuffer.ResizeData(position + footerSize); - // buffer.resize(position + footerSize); // write pg index CopyToBuffer(buffer, position, &pgCount); CopyToBuffer(buffer, position, &pgLength); CopyToBuffer(buffer, position, m_MetadataSet.PGIndex.Buffer.data(), - pgLength); + static_cast<const size_t>(pgLength)); // Vars indices lf_FlattenIndices(varsCount, varsLength, m_MetadataSet.VarsIndices, buffer, @@ -460,9 +458,12 @@ void BP1Writer::FlattenMetadata() noexcept m_MetadataSet.AttributesIndices, buffer, position); // getting absolute offsets, minifooter is 28 bytes for now - const uint64_t offsetPGIndex = m_HeapBuffer.m_DataAbsolutePosition; - const uint64_t offsetVarsIndex = offsetPGIndex + (pgLength + 16); - const uint64_t offsetAttributeIndex = offsetVarsIndex + (varsLength + 12); + const uint64_t offsetPGIndex = + static_cast<const uint64_t>(m_HeapBuffer.m_DataAbsolutePosition); + const uint64_t offsetVarsIndex = + static_cast<const uint64_t>(offsetPGIndex + (pgLength + 16)); + const uint64_t offsetAttributeIndex = + static_cast<const uint64_t>(offsetVarsIndex + (varsLength + 12)); CopyToBuffer(buffer, position, &offsetPGIndex); CopyToBuffer(buffer, position, &offsetVarsIndex); diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.h b/source/adios2/toolkit/format/bp1/BP1Writer.h index 44d306c3f2500cf61a216f58be108026ab0f58df..7f65b749e2730dece386db1e273a4f77cf7208cf 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.h +++ b/source/adios2/toolkit/format/bp1/BP1Writer.h @@ -72,7 +72,7 @@ public: void Advance(); /** Flattens data buffer and close current process group, doesn't - * advance time index */ + * advance time index */ void Flush(); /** diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.tcc b/source/adios2/toolkit/format/bp1/BP1Writer.tcc index 733f43195b2e8f85d864e0d78896e1bc28400c11..c1aa88ca6643d8e98fe48c3c4145b137b7ec7ff4 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.tcc +++ b/source/adios2/toolkit/format/bp1/BP1Writer.tcc @@ -37,7 +37,7 @@ void BP1Writer::WriteVariableMetadata(const Variable<T> &variable) noexcept stats.MemberID = variableIndex.MemberID; // write metadata header in data and extract offsets - stats.Offset = m_HeapBuffer.m_DataAbsolutePosition; + stats.Offset = static_cast<uint64_t>(m_HeapBuffer.m_DataAbsolutePosition); WriteVariableMetadataInData(variable, stats); stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition; @@ -109,7 +109,8 @@ void BP1Writer::WriteVariableMetadataInData( constexpr char no = 'n'; // isDimension CopyToBuffer(buffer, position, &no); - const uint8_t dimensions = variable.m_Count.size(); + const uint8_t dimensions = + static_cast<const uint8_t>(variable.m_Count.size()); CopyToBuffer(buffer, position, &dimensions); // count // 27 is from 9 bytes for each: var y/n + local, var y/n + global dimension, @@ -145,11 +146,11 @@ void BP1Writer::WriteVariableMetadataInIndex( if (isNew) // write variable header (might be shared with // attributes index) { - buffer.insert(buffer.end(), 4, 0); // skip var length (4) + buffer.insert(buffer.end(), 4, '\0'); // skip var length (4) InsertToBuffer(buffer, &stats.MemberID); - buffer.insert(buffer.end(), 2, 0); // skip group name + buffer.insert(buffer.end(), 2, '\0'); // skip group name WriteNameRecord(variable.m_Name, buffer); - buffer.insert(buffer.end(), 2, 0); // skip path + buffer.insert(buffer.end(), 2, '\0'); // skip path const std::uint8_t dataType = GetDataType<T>(); InsertToBuffer(buffer, &dataType); @@ -256,15 +257,17 @@ void BP1Writer::WriteVariableCharacteristics( // going back at the end const size_t characteristicsCountPosition = buffer.size(); // skip characteristics count(1) + length (4) - buffer.insert(buffer.end(), 5, 0); + buffer.insert(buffer.end(), 5, '\0'); uint8_t characteristicsCounter = 0; // DIMENSIONS uint8_t characteristicID = characteristic_dimensions; InsertToBuffer(buffer, &characteristicID); - const uint8_t dimensions = variable.m_Count.size(); + const uint8_t dimensions = + static_cast<const uint8_t>(variable.m_Count.size()); InsertToBuffer(buffer, &dimensions); // count - const uint16_t dimensionsLength = 24 * dimensions; + const uint16_t dimensionsLength = + static_cast<const uint16_t>(24 * dimensions); InsertToBuffer(buffer, &dimensionsLength); // length WriteDimensionsRecord(variable.m_Count, variable.m_Shape, variable.m_Start, buffer); @@ -276,9 +279,10 @@ void BP1Writer::WriteVariableCharacteristics( WriteCharacteristicRecord(characteristic_time_index, characteristicsCounter, stats.TimeIndex, buffer); + const uint32_t rankU32 = + static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI); WriteCharacteristicRecord(characteristic_file_index, characteristicsCounter, - static_cast<uint32_t>(m_BP1Aggregator.m_RankMPI), - buffer); + rankU32, buffer); WriteCharacteristicRecord(characteristic_offset, characteristicsCounter, stats.Offset, buffer); @@ -293,8 +297,8 @@ void BP1Writer::WriteVariableCharacteristics( CopyToBuffer(buffer, backPosition, &characteristicsCounter); // count (1) // remove its own length (4) + characteristic counter (1) - const uint32_t characteristicsLength = - buffer.size() - characteristicsCountPosition - 4 - 1; + const uint32_t characteristicsLength = static_cast<const uint32_t>( + buffer.size() - characteristicsCountPosition - 4 - 1); CopyToBuffer(buffer, backPosition, &characteristicsLength); // length } @@ -315,9 +319,11 @@ void BP1Writer::WriteVariableCharacteristics( uint8_t characteristicID = characteristic_dimensions; CopyToBuffer(buffer, position, &characteristicID); - const uint8_t dimensions = variable.m_Count.size(); + const uint8_t dimensions = + static_cast<const uint8_t>(variable.m_Count.size()); CopyToBuffer(buffer, position, &dimensions); // count - const uint16_t dimensionsLength = 24 * dimensions; + const uint16_t dimensionsLength = + static_cast<const uint16_t>(24 * dimensions); CopyToBuffer(buffer, position, &dimensionsLength); // length WriteDimensionsRecord(variable.m_Count, variable.m_Shape, variable.m_Start, buffer, position, true); // isCharacteristic = true @@ -333,8 +339,8 @@ void BP1Writer::WriteVariableCharacteristics( CopyToBuffer(buffer, backPosition, &characteristicsCounter); // remove its own length (4) + characteristic counter (1) - const uint32_t characteristicsLength = - position - characteristicsCountPosition - 4 - 1; + const uint32_t characteristicsLength = static_cast<const uint32_t>( + position - characteristicsCountPosition - 4 - 1); CopyToBuffer(buffer, backPosition, &characteristicsLength); } diff --git a/source/adios2/toolkit/transport/file/FilePointer.cpp b/source/adios2/toolkit/transport/file/FilePointer.cpp index 82b764bd58548119564bf60f8fda0416d2967a46..e11c4f9fb9dc17a6118f4cec5d8fc6f933061eb8 100644 --- a/source/adios2/toolkit/transport/file/FilePointer.cpp +++ b/source/adios2/toolkit/transport/file/FilePointer.cpp @@ -14,6 +14,11 @@ #include <ios> //std::ios_base::failure /// \endcond +// removes fopen warning on Windows +#ifdef _WIN32 +#pragma warning(disable : 4996) // fopen +#endif + namespace adios2 { namespace transport @@ -28,7 +33,7 @@ FilePointer::~FilePointer() { if (m_IsOpen) { - fclose(m_File); + std::fclose(m_File); } } @@ -48,19 +53,19 @@ void FilePointer::Open(const std::string &name, const OpenMode openMode) if (m_OpenMode == OpenMode::Write) { - m_File = std::fopen(name.c_str(), "w"); + m_File = std::fopen(name.c_str(), "wb"); } else if (m_OpenMode == OpenMode::Append) { // need to change when implemented - m_File = std::fopen(name.c_str(), "a"); + m_File = std::fopen(name.c_str(), "ab"); } else if (m_OpenMode == OpenMode::Read) { - m_File = std::fopen(name.c_str(), "r"); + m_File = std::fopen(name.c_str(), "rb"); } - if (std::ferror(m_File)) + if (ferror(m_File)) { throw std::ios_base::failure("ERROR: couldn't open file " + name + ", " diff --git a/source/adios2/toolkit/transport/file/FilePointer.h b/source/adios2/toolkit/transport/file/FilePointer.h index 7c14b48066d1291790411adac6ffef5194bb6cb1..6d1521a3d5d99fff26f00806871194f9461fa5a8 100644 --- a/source/adios2/toolkit/transport/file/FilePointer.h +++ b/source/adios2/toolkit/transport/file/FilePointer.h @@ -45,7 +45,7 @@ public: private: /** C File pointer */ - std::FILE *m_File = nullptr; // NULL or nullptr? + FILE *m_File = nullptr; // NULL or nullptr? }; } // end namespace transport diff --git a/source/adios2/toolkit/transport/file/FileStream.cpp b/source/adios2/toolkit/transport/file/FileStream.cpp index 50c05e0e22443b37be4721c0e60eb5568bdae081..3609394539420b2a3c3333bc31506f45b05b76a7 100644 --- a/source/adios2/toolkit/transport/file/FileStream.cpp +++ b/source/adios2/toolkit/transport/file/FileStream.cpp @@ -40,16 +40,17 @@ void FileStream::Open(const std::string &name, const OpenMode openMode) if (m_OpenMode == OpenMode::Write) { - m_FileStream.open(name, std::fstream::out); + m_FileStream.open(name, std::fstream::out | std::fstream::binary); } else if (m_OpenMode == OpenMode::Append) { // to be changed to rw? - m_FileStream.open(name, std::fstream::out | std::fstream::app); + m_FileStream.open(name, std::fstream::out | std::fstream::app | + std::fstream::binary); } else if (m_OpenMode == OpenMode::Read) { - m_FileStream.open(name, std::fstream::in); + m_FileStream.open(name, std::fstream::in | std::fstream::binary); } if (!m_FileStream) diff --git a/testing/adios2/xml/TestXMLConfig.cpp b/testing/adios2/xml/TestXMLConfig.cpp index 16b45d2f3f551ddc930097dad64f09b9b5e98f1d..5d3cb161b01080cd33a19083516deba70d3caaaa 100644 --- a/testing/adios2/xml/TestXMLConfig.cpp +++ b/testing/adios2/xml/TestXMLConfig.cpp @@ -51,6 +51,20 @@ TEST_F(XMLConfigTest, TwoIOs) }); } +TEST_F(XMLConfigTest, TwoEnginesException) +{ + std::string configFile = configDir + "/config2.xml"; + +#ifdef ADIOS2_HAVE_MPI + EXPECT_THROW( + adios2::ADIOS adios(configFile, MPI_COMM_WORLD, adios2::DebugON), + std::invalid_argument); +#else + EXPECT_THROW(adios2::ADIOS adios(configFile, adios2::DebugON), + std::invalid_argument); +#endif +} + int main(int argc, char **argv) { #ifdef ADIOS2_HAVE_MPI diff --git a/testing/adios2/xml/config2.xml b/testing/adios2/xml/config2.xml new file mode 100644 index 0000000000000000000000000000000000000000..c26d2ec852400e34cf12d287ad3cbdf2b2b18672 --- /dev/null +++ b/testing/adios2/xml/config2.xml @@ -0,0 +1,7 @@ +<?xml version="1.0"?> +<adios-config> + <io name="Test IO 2"> + <engine type="BPFileWriter" /> + <engine type="Other" /> <!-- std::invalid_argument exception --> + </io> +</adios-config>