Commit 73a016f0 authored by Joseph Mirabel's avatar Joseph Mirabel Committed by Olivier Stasse
Browse files

Add macros to use real time logs.

parent 3b391ca7
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
# include <boost/shared_ptr.hpp> # include <boost/shared_ptr.hpp>
# include <dynamic-graph/config.hh> # include <dynamic-graph/config.hh>
# include <dynamic-graph/debug.h>
namespace dynamicgraph namespace dynamicgraph
{ {
...@@ -50,7 +52,8 @@ namespace dynamicgraph ...@@ -50,7 +52,8 @@ namespace dynamicgraph
{ {
public: public:
RTLoggerStream (RealTimeLogger* logger, std::ostream& os) : logger_(logger), os_ (os) {} RTLoggerStream (RealTimeLogger* logger, std::ostream& os) : logger_(logger), os_ (os) {}
template <typename T> RTLoggerStream& operator<< (T t) { os_ << t; return *this; } template <typename T> inline RTLoggerStream& operator<< (T t) { os_ << t; return *this; }
inline RTLoggerStream& operator<< (std::ostream& (*pf)(std::ostream&)) { os_ << pf; return *this; }
~RTLoggerStream(); ~RTLoggerStream();
private: private:
...@@ -65,6 +68,10 @@ namespace dynamicgraph ...@@ -65,6 +68,10 @@ namespace dynamicgraph
class DYNAMIC_GRAPH_DLLAPI RealTimeLogger class DYNAMIC_GRAPH_DLLAPI RealTimeLogger
{ {
public: public:
static RealTimeLogger& instance();
static void destroy();
/// \todo add an argument to preallocate the internal string to a given size. /// \todo add an argument to preallocate the internal string to a given size.
RealTimeLogger (const std::size_t& bufferSize); RealTimeLogger (const std::size_t& bufferSize);
...@@ -72,9 +79,6 @@ namespace dynamicgraph ...@@ -72,9 +79,6 @@ namespace dynamicgraph
inline void addOutputStream (const LoggerStreamPtr_t& os) { outputs_.push_back(os); } inline void addOutputStream (const LoggerStreamPtr_t& os) { outputs_.push_back(os); }
/// The function to be called by the thread who exports the outputs
//void spin ();
/// Write next message to output. /// Write next message to output.
/// It does nothing if the buffer is empty. /// It does nothing if the buffer is empty.
/// \return true if it wrote something /// \return true if it wrote something
...@@ -104,7 +108,7 @@ namespace dynamicgraph ...@@ -104,7 +108,7 @@ namespace dynamicgraph
return backIdx_ + buffer_.size() - frontIdx_; return backIdx_ + buffer_.size() - frontIdx_;
} }
inline std::size_t getBufferSize () { return buffer_.capacity(); } inline std::size_t getBufferSize () { return buffer_.size(); }
~RealTimeLogger (); ~RealTimeLogger ();
...@@ -121,7 +125,21 @@ namespace dynamicgraph ...@@ -121,7 +125,21 @@ namespace dynamicgraph
/// Index of the slot where to write next value (does not contain valid data). /// Index of the slot where to write next value (does not contain valid data).
std::size_t backIdx_; std::size_t backIdx_;
std::ostream oss_; std::ostream oss_;
struct thread;
static RealTimeLogger* instance_;
static thread* thread_;
}; };
} // end of namespace dynamicgraph } // end of namespace dynamicgraph
#ifdef ENABLE_RT_LOG
# define dgADD_OSTREAM_TO_RTLOG(ostr) ::dynamicgraph::RealTimeLogger::instance() \
.addOutputStream(::dynamicgraph::LoggerStreamPtr_t(new ::dynamicgraph::LoggerIOStream(ostr)))
# define dgRTLOG() ::dynamicgraph::RealTimeLogger::instance().front()
#else // ENABLE_RT_LOG
# define dgADD_OSTREAM_TO_RTLOG(ostr) struct __end_with_semicolon
# define dgRTLOG() if (1) ; else __null_stream()
#endif
#endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H #endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include <dynamic-graph/real-time-logger.h> #include <dynamic-graph/real-time-logger.h>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace dynamicgraph namespace dynamicgraph
{ {
RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize) RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize)
...@@ -68,4 +71,47 @@ namespace dynamicgraph ...@@ -68,4 +71,47 @@ namespace dynamicgraph
os_ << std::ends; os_ << std::ends;
if (logger_ != NULL) logger_->frontReady(); if (logger_ != NULL) logger_->frontReady();
} }
struct RealTimeLogger::thread
{
bool requestShutdown_;
boost::thread t_;
thread (RealTimeLogger* logger)
: requestShutdown_ (false)
, t_ (&thread::spin, this, logger)
{}
void spin (RealTimeLogger* logger)
{
while (!requestShutdown_ || !logger->empty())
{
// If the logger did not write anything, it means the buffer is empty.
// Do a pause
if (!logger->spinOnce())
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
}
};
RealTimeLogger* RealTimeLogger::instance_ = NULL;
RealTimeLogger::thread* RealTimeLogger::thread_ = NULL;
RealTimeLogger& RealTimeLogger::instance()
{
if (instance_ == NULL) {
instance_ = new RealTimeLogger (1000);
thread_ = new thread (instance_);
}
return *instance_;
}
void RealTimeLogger::destroy ()
{
if (instance_ == NULL) return;
thread_->requestShutdown_ = true;
thread_->t_.join();
delete instance_;
delete thread_;
}
} }
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
#include <iostream> #include <iostream>
#define ENABLE_RT_LOG
#include <dynamic-graph/real-time-logger.h> #include <dynamic-graph/real-time-logger.h>
#define BOOST_TEST_MODULE real_time_logger #define BOOST_TEST_MODULE real_time_logger
...@@ -25,7 +27,6 @@ ...@@ -25,7 +27,6 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp> #include <boost/test/output_test_stream.hpp>
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
...@@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread) ...@@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread)
rtl.spinOnce(); rtl.spinOnce();
} }
bool requestShutdown = false;
void spin (RealTimeLogger* logger)
{
while (!requestShutdown || !logger->empty())
{
// If the logger did not write anything, it means the buffer is empty.
// Do a pause
if (!logger->spinOnce())
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
}
BOOST_AUTO_TEST_CASE (multithread) BOOST_AUTO_TEST_CASE (multithread)
{ {
RealTimeLogger rtl (10); RealTimeLogger& rtl = RealTimeLogger::instance();
rtl.addOutputStream (LoggerStreamPtr_t (new LoggerIOStream(std::cout))); dgADD_OSTREAM_TO_RTLOG (std::cout);
boost::thread loggerThread (spin, &rtl);
for (int i = 0; i < 10; ++i) { for (std::size_t i = 0; i < rtl.getBufferSize()-1; ++i)
boost::this_thread::sleep(boost::posix_time::milliseconds(20));
rtl.front() << "Call number " << i << '\n'; rtl.front() << "Call number " << i << '\n';
for (std::size_t i = 0; i < 12; ++i) {
boost::this_thread::sleep(boost::posix_time::milliseconds(20));
rtl.front() << "Call number " << i << std::endl;
BOOST_CHECK (!rtl.full()); BOOST_CHECK (!rtl.full());
} }
rtl.front() << "This call should appear in the output" << '\n'; dgRTLOG() << "This call should appear in the output" << '\n';
requestShutdown = true; RealTimeLogger::destroy();
loggerThread.join();
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment