Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slic open before flush #1387

Merged
merged 25 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a024ef8
First attempt at a open only before write constructor for GenericOutp…
bmhan12 Jul 16, 2024
be0b210
Doxygen
bmhan12 Jul 17, 2024
526ac69
Unit test for GenericOutputStream
bmhan12 Jul 17, 2024
73280de
Remove ofstream(std::string) problematic test case logic
bmhan12 Jul 17, 2024
ab952b1
Check GenericOutputStream before and after message is logged
bmhan12 Jul 17, 2024
4963ef4
First pass at LumberjackStream and SynchronizedStream open before wri…
bmhan12 Jul 17, 2024
b2b177e
Handle memory leak with GenericOutputStream owning ostream; remove pr…
bmhan12 Jul 17, 2024
d87eca9
Handle memory leaks for Synchronized and Lumberjack streams
bmhan12 Jul 19, 2024
9ba8ee6
GenericOutputStream - Open file when flushing messages the first time
bmhan12 Jul 19, 2024
29fc27a
Sync and Lumberjack - Open file when flushing messages the first time
bmhan12 Jul 19, 2024
4a3cc79
Windows being difficult - ignore for now...
bmhan12 Jul 22, 2024
496d34a
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 12, 2024
2d212c5
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 14, 2024
37eba96
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 19, 2024
ed73866
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 23, 2024
c9b27c8
Add getter method to m_stream for LogStream instances
bmhan12 Aug 23, 2024
2e2458c
Adjust note
bmhan12 Aug 26, 2024
ded4ea8
Revert debugging commit "Add getter method to m_stream for LogStream …
bmhan12 Aug 26, 2024
543abe1
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 26, 2024
35a997c
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Aug 28, 2024
d9ee957
Clarify and concisely fix string constructor note
bmhan12 Aug 28, 2024
d43699c
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Sep 3, 2024
c8187ef
Merge branch 'develop' into feature/han12/slic_open_on_write
bmhan12 Sep 4, 2024
6c808f4
Merge branch 'develop' into feature/han12/slic_open_on_write
rhornung67 Sep 16, 2024
f301731
Apply review changes + update notes
bmhan12 Sep 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ The Axom project release numbers follow [Semantic Versioning](http://semver.org/
## [Unreleased] - Release date yyyy-mm-dd

### Added
- SLIC constructors added to streams that take in a `std::string`. If string is
interpreted as a file name, the file is not opened until SLIC flushes and the
stream has at least one message logged.
- Primal: Adds a `clip()` operator overload for clipping a 2D polygon against
another 2D polygon.
- Primal: Adds `Polygon::reverseOrientation()` to reverse orientation of
Expand Down
64 changes: 59 additions & 5 deletions src/axom/slic/streams/GenericOutputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,46 @@ namespace axom
{
namespace slic
{
GenericOutputStream::GenericOutputStream(std::ostream* os) : m_stream(os) { }
GenericOutputStream::GenericOutputStream(std::ostream* os)
: m_stream(os)
, m_file_name()
, m_opened(true)
, m_isOstreamOwnedBySLIC(false)
{ }

//------------------------------------------------------------------------------
GenericOutputStream::GenericOutputStream(const std::string& stream)
{
if(stream == "cout")
{
m_stream = &std::cout;
m_file_name = std::string();
m_opened = true;
m_isOstreamOwnedBySLIC = false;
}
else if(stream == "cerr")
{
m_stream = &std::cerr;
m_file_name = std::string();
m_opened = true;
m_isOstreamOwnedBySLIC = false;
}
else
{
m_stream = new std::ofstream(stream);
m_stream = new std::ostringstream();
m_file_name = stream;
m_opened = false;
m_isOstreamOwnedBySLIC = true;
}
}

//------------------------------------------------------------------------------
GenericOutputStream::GenericOutputStream(std::ostream* os,
const std::string& format)
: m_stream(os)
, m_file_name()
, m_opened(true)
, m_isOstreamOwnedBySLIC(false)
{
this->setFormatString(format);
}
Expand All @@ -53,7 +70,14 @@ GenericOutputStream::GenericOutputStream(const std::string& stream,
}

//------------------------------------------------------------------------------
GenericOutputStream::~GenericOutputStream() { }
GenericOutputStream::~GenericOutputStream()
{
if(m_isOstreamOwnedBySLIC)
{
delete m_stream;
m_stream = static_cast<std::ostream*>(nullptr);
}
}

//------------------------------------------------------------------------------
void GenericOutputStream::append(message::Level msgLevel,
Expand All @@ -80,10 +104,40 @@ void GenericOutputStream::append(message::Level msgLevel,
}

//------------------------------------------------------------------------------
void GenericOutputStream::outputLocal() { m_stream->flush(); }
void GenericOutputStream::openBeforeFlush()
{
if(m_isOstreamOwnedBySLIC && !m_opened)
{
std::ostringstream* oss = dynamic_cast<std::ostringstream*>(m_stream);
if(oss != nullptr)
{
// Converting stream from ostringstream to ofstream and
// writing ostringstream's string buffer to ofstream
std::string buffer = oss->str();
if(!buffer.empty())
{
delete m_stream;
m_stream = new std::ofstream(m_file_name);
(*m_stream) << buffer;
m_opened = true;
}
}
}
}

//------------------------------------------------------------------------------
void GenericOutputStream::flush() { m_stream->flush(); }
void GenericOutputStream::outputLocal()
{
openBeforeFlush();
m_stream->flush();
}

//------------------------------------------------------------------------------
void GenericOutputStream::flush()
{
openBeforeFlush();
m_stream->flush();
}

} /* namespace slic */

Expand Down
24 changes: 22 additions & 2 deletions src/axom/slic/streams/GenericOutputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class GenericOutputStream : public LogStream
* - "cerr" makes std::cerr the output stream
* - Any other input will construct a std::ofstream associated with input
* \param [in] stream the string to control type of stream created
*
* \note This constructor avoids creating an empty file if this
* GenericOutputStream never flushes a message.
*/
GenericOutputStream(const std::string& stream);

Expand All @@ -57,20 +60,24 @@ class GenericOutputStream : public LogStream
* message formatting.
* \param [in] os pointer to a user-supplied ostream instance.
* \param [in] format the format string.
* \pre os != NULL
* \see LogStream::setFormatString for the format string.
*/
GenericOutputStream(std::ostream* os, const std::string& format);

/*!
* \brief Constructs a GenericOutputStream instance specified by the given
* string and message formatting.
* string and message formatting.
* The string input determines the stream as follows:
* - "cout" makes std::cout the output stream
* - "cerr" makes std::cerr the output stream
* - Any other input will construct a std::ofstream associated with input
* \param [in] stream the string to control type of stream created
* \param [in] format the format string.
* \see LogStream::setFormatString for the format string.
*
* \note This constructor avoids creating an empty file if this
* GenericOutputStream never flushes a message.
*/
GenericOutputStream(const std::string& stream, const std::string& format);

Expand Down Expand Up @@ -100,12 +107,25 @@ class GenericOutputStream : public LogStream

private:
std::ostream* m_stream;
std::string m_file_name;
bool m_opened;
bool m_isOstreamOwnedBySLIC;

/*!
* \brief Default constructor.
* \note Made private to prevent applications from using it.
*/
GenericOutputStream() : m_stream(static_cast<std::ostream*>(nullptr)) {};
GenericOutputStream()
: m_stream(static_cast<std::ostream*>(nullptr))
, m_file_name()
, m_opened(false)
, m_isOstreamOwnedBySLIC(false) {};

/*!
* \brief Opens a file before flushing stream when GenericOutputStream
* has ownership of ostream to a file (std::string constructor)
*/
void openBeforeFlush();

DISABLE_COPY_AND_ASSIGNMENT(GenericOutputStream);
DISABLE_MOVE_AND_ASSIGNMENT(GenericOutputStream);
Expand Down
118 changes: 118 additions & 0 deletions src/axom/slic/streams/LumberjackStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <vector>

#include "axom/core/Macros.hpp"
#include "axom/core/utilities/StringUtilities.hpp"

#include "axom/lumberjack/BinaryTreeCommunicator.hpp"
#include "axom/lumberjack/Lumberjack.hpp"
Expand All @@ -22,7 +23,10 @@ LumberjackStream::LumberjackStream(std::ostream* stream,
MPI_Comm comm,
int ranksLimit)
: m_isLJOwnedBySLIC(false)
, m_isOstreamOwnedBySLIC(false)
, m_stream(stream)
, m_file_name()
, m_opened(true)
{
this->initializeLumberjack(comm, ranksLimit);
}
Expand All @@ -33,7 +37,10 @@ LumberjackStream::LumberjackStream(std::ostream* stream,
int ranksLimit,
const std::string& format)
: m_isLJOwnedBySLIC(false)
, m_isOstreamOwnedBySLIC(false)
, m_stream(stream)
, m_file_name()
, m_opened(true)
{
this->initializeLumberjack(comm, ranksLimit);
this->setFormatString(format);
Expand All @@ -44,7 +51,10 @@ LumberjackStream::LumberjackStream(std::ostream* stream,
axom::lumberjack::Lumberjack* lj)
: m_lj(lj)
, m_isLJOwnedBySLIC(false)
, m_isOstreamOwnedBySLIC(false)
, m_stream(stream)
, m_file_name()
, m_opened(true)
{ }

//------------------------------------------------------------------------------
Expand All @@ -53,18 +63,116 @@ LumberjackStream::LumberjackStream(std::ostream* stream,
const std::string& format)
: m_lj(lj)
, m_isLJOwnedBySLIC(false)
, m_isOstreamOwnedBySLIC(false)
, m_stream(stream)
, m_file_name()
, m_opened(true)
{
this->setFormatString(format);
}

//------------------------------------------------------------------------------
LumberjackStream::LumberjackStream(const std::string stream,
MPI_Comm comm,
int ranksLimit)
{
this->initializeLumberjack(comm, ranksLimit);

if(stream == "cout")
{
m_isOstreamOwnedBySLIC = false;
m_stream = &std::cout;
m_file_name = std::string();
m_opened = true;
}
else if(stream == "cerr")
{
m_isOstreamOwnedBySLIC = false;
m_stream = &std::cerr;
m_file_name = std::string();
m_opened = true;
}
else
{
m_isOstreamOwnedBySLIC = true;
m_stream = new std::ofstream();
m_file_name = stream;
m_opened = false;
}
}

//------------------------------------------------------------------------------
LumberjackStream::LumberjackStream(const std::string stream,
MPI_Comm comm,
int ranksLimit,
const std::string& format)
: LumberjackStream::LumberjackStream(stream, comm, ranksLimit)
{
// Fix newline and tab characters if needed
std::string format_fixed = axom::utilities::string::replaceAllInstances(
axom::utilities::string::replaceAllInstances(format, "\\n", "\n"),
"\\t",
"\t");
this->setFormatString(format_fixed);
}

//------------------------------------------------------------------------------
LumberjackStream::LumberjackStream(const std::string stream,
axom::lumberjack::Lumberjack* lj)
{
m_lj = lj;
m_isLJOwnedBySLIC = false;

if(stream == "cout")
{
m_isOstreamOwnedBySLIC = false;
m_stream = &std::cout;
m_file_name = std::string();
m_opened = true;
}
else if(stream == "cerr")
{
m_isOstreamOwnedBySLIC = false;
m_stream = &std::cerr;
m_file_name = std::string();
m_opened = true;
}
else
{
m_isOstreamOwnedBySLIC = true;
m_stream = new std::ofstream();
m_file_name = stream;
m_opened = false;
}
}

//------------------------------------------------------------------------------
LumberjackStream::LumberjackStream(const std::string stream,
axom::lumberjack::Lumberjack* lj,
const std::string& format)
: LumberjackStream::LumberjackStream(stream, lj)
{
// Fix newline and tab characters if needed
std::string format_fixed = axom::utilities::string::replaceAllInstances(
axom::utilities::string::replaceAllInstances(format, "\\n", "\n"),
"\\t",
"\t");
this->setFormatString(format_fixed);
}

//------------------------------------------------------------------------------
LumberjackStream::~LumberjackStream()
{
if(m_isLJOwnedBySLIC)
{
this->finalizeLumberjack();
}

if(m_isOstreamOwnedBySLIC)
{
delete m_stream;
m_stream = static_cast<std::ostream*>(nullptr);
}
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -146,6 +254,16 @@ void LumberjackStream::write(bool local)
continue;
}

if(m_isOstreamOwnedBySLIC && !m_opened)
{
std::ofstream* ofs = dynamic_cast<std::ofstream*>(m_stream);
if(ofs != nullptr)
{
ofs->open(m_file_name);
m_opened = true;
}
}

(*m_stream) << this->getFormatedMessage(
message::getLevelAsString(
static_cast<message::Level>(curr_message->level())),
Expand Down
Loading