Enable parallel tests.
[hoomd-blue.git] / libhoomd / utils / Messenger.h
blob759d51d23a75ae56d350f7d4e79468fba6d77c8f
1 /*
2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
32 permission.
34 Disclaimer
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 // Maintainer: joaander
52 /*! \file Messenger.h
53 \brief Declares the Messenger class
56 #include <iostream>
57 #include <fstream>
58 #include <string>
59 #include <boost/shared_ptr.hpp>
60 #include <sstream>
62 #ifdef ENABLE_MPI
63 #include "HOOMDMPI.h"
64 #include <boost/iostreams/stream.hpp>
65 #include <boost/iostreams/categories.hpp>
66 #endif
68 #ifdef NVCC
69 #error This header cannot be compiled by nvcc
70 #endif
72 #ifndef __MESSENGER_H__
73 #define __MESSENGER_H__
75 //! A null stream that doesn't write anything sent to it
76 /*! From: http://bytes.com/topic/c/answers/127843-null-output-stream#post444998
78 struct nullstream: std::ostream
80 //! Construct a null stream
81 nullstream(): std::ios(0), std::ostream(0) {}
84 #ifdef ENABLE_MPI
85 //! Class that supports writing to a shared log file using MPI-IO
86 class mpi_io
88 public:
89 typedef boost::iostreams::sink_tag category; //!< Define this iostream as a sink
90 typedef char char_type; //!< This is a character-type sink
92 //! Constructor
93 mpi_io(const MPI_Comm& mpi_comm, const std::string& filename);
94 virtual ~mpi_io() { };
96 //! Close the log file
97 void close();
99 //! \return true if file is open
100 bool is_open()
102 return m_file_open;
105 //! Write a sequence of characters
106 std::streamsize write ( const char * s, std::streamsize n );
108 private:
109 MPI_Comm m_mpi_comm; //!< The MPI communciator
110 MPI_File m_file; //!< The file handle
111 bool m_file_open; //!< Whether the file is open
113 #endif
115 //! Utility class for controlling message printing
116 /*! Large code projects need something more inteligent than just cout's for warning and
117 notices and cerr for errors. To aid in user debugging, multiple levels of notice messages are required. Not all
118 notice levels need to be printed in every run. A notice level can be set to control how much information is printed.
119 Furthermore, in MPI runs not all processes need to print messages or one may wan to log the output of every rank to
120 a different file.
122 The Messenger class solves these issues. It provides a set of message levels that can be linked to chosen streams.
123 The streams are returned by function calls so that users of this class can do the following:
124 \code
125 msg.error() << "Bad input" << endl;
126 msg.warning() << "I hope you know what you are doing" << endl;
127 msg.notice(1) << "Some useful info" << endl;
128 msg.notice(5) << "Info that nobody cares about, unless they are debugging" << endl;
129 \endcode
130 Calls to notice(N) with N > the notice level will return a null stream so that the output is not printed.
132 Furthermore, a chosen header may be added to messages of each type. So that the screen output from the previous
133 could be:
134 \code
135 error!!!!: Bad input
136 warning!!: I hope you know what you are doing
137 Some useful info
138 notice(5): Info that nobody cares about, unless they are debugging
139 \endcode
141 Messenger is copyable. This enables use cases where one global Messegner (possibly even having an open file)
142 is copied into a local class and local settings changes applied.
144 \b Implemntation
146 - Errors and warnings are always printed.
147 - Notice messages are printed when n <= the notice level.
148 - 1 Should be the minimum notice level actually used so that all noticed messages may be silenced by setting 0.
149 - Streams for each level are stored separately as pointers and can be set.
150 - Streams default to cerr for errors and warnings and cout for notice messages.
151 - Arbitrary streams may be set - however, since they are stored by pointer the caller is responsible for
152 deleting them when set in this manner.
153 - An alternate interface openFile opens a file for overwrite for all output levels, owned by the Messenger.
155 \b HOOMD specific
157 One global Messenger will be initialized in python and passed to the ExecutionConfiguration. From there, all C++
158 classes can print messages via commands like m_exec_conf->msg->notice(1) << "blah". Maybe a macro NOTICE() to
159 simplify the typing??? Need to debate that.
161 The following notice levels will be used:
162 - Error: Any condtition that is erroneous and will prevent the run from continuing
163 - Generally followed by a thrown exception
164 - Warning: Out of bounds parameters, settings that will use a lot of memory, etc... Things that won't prevent
165 continued execution, but that may lead to incorrect behavior.
166 - 1: typical status messages
167 - python command echos
168 - TPS reports
169 - which hardware is active
170 - 2: notifications of general interest that most people want to see
171 - notices that certain hardware is unavailable
172 - status information printed at the end of a run
173 - 3,4: Additional details on top of 2.
174 - 5-10: Varying debug messages, number chosen arbitrarily based on how often the message is likely to print
175 - Some examples for consistency
176 - 5 construction/desctruction messages from every major class
177 - 6 memory allocation/reallocation notices from every major class
178 - 7 memory allocation/reallocation notices from GPUArray
179 - 10: Trace messages that may print many times per time step.
181 class Messenger
183 public:
184 //! Construct a messenger
185 Messenger();
187 //! Copy constructor
188 Messenger(const Messenger& msg);
190 //! Assignment operator
191 Messenger& operator=(Messenger& msg);
193 //! Destructor
194 ~Messenger();
196 //! Get the error stream
197 std::ostream& error() const;
199 //! Alternate method to print error strings
200 void errorStr(const std::string& msg) const;
202 //! Get the warning stream
203 std::ostream& warning() const;
205 //! Alternate method to print warning strings
206 void warningStr(const std::string& msg) const;
208 //! Get a notice stream
209 std::ostream& notice(unsigned int level) const;
211 //! Print a notice message in rank-order
212 void collectiveNoticeStr(unsigned int level, const std::string& msg) const;
214 //! Alternate method to print notice strings
215 void noticeStr(unsigned int level, const std::string& msg) const;
217 //! Set processor rank
218 /*! Error and warning messages are prefixed with rank information.
220 Notice messages are only output on processor with rank 0.
222 \param rank This processor's rank
225 void setRank(unsigned int rank, unsigned int partition)
227 // prefix all messages with rank information
228 m_rank = rank;
229 m_nranks = 1;
230 #ifdef ENABLE_MPI
231 bcast(m_notice_level,0,m_mpi_comm);
233 // get communicator size
234 int nranks;
235 if (m_rank != 0) m_notice_level = 0;
236 MPI_Comm_size(m_mpi_comm, &nranks);
237 m_nranks = nranks;
238 #endif
239 m_partition = partition;
243 #ifdef ENABLE_MPI
244 //! Set MPI communicator
245 /*! \param mpi_comm The MPI communicator to use
247 void setMPICommunicator(const MPI_Comm mpi_comm)
249 // clean up data associated with old communicator
250 releaseSharedMem();
252 m_mpi_comm = mpi_comm;
254 // open shared log file if necessary
255 if (m_shared_filename != "")
256 openSharedFile();
258 // initialize RMA memory for error messages
259 initializeSharedMem();
262 //! Revert to MPI_COMM_WORLD communicator
263 void unsetMPICommunicator()
265 if (m_shared_filename != "")
266 openStd();
268 releaseSharedMem();
270 m_mpi_comm = MPI_COMM_WORLD;
272 // initialize RMA memory for error messages
273 initializeSharedMem();
275 #endif
277 //! Get the notice level
278 /*! \returns Current notice level
280 unsigned int getNoticeLevel() const
282 return m_notice_level;
285 //! Set the notice level
286 /*! \param level Notice level to set
288 void setNoticeLevel(unsigned int level)
290 m_notice_level = (m_rank == 0) ? level : 0;
293 //! Set the error stream
294 /*! If not a built-in stream, the caller is responsible for deleting it
296 void setErrorStream(std::ostream& stream)
298 m_err_stream = &stream;
301 //! Set the warning stream
302 /*! If not a built-in stream, the caller is responsible for deleting it
304 void setWarningStream(std::ostream& stream)
306 m_warning_stream = &stream;
309 //! Set the notice stream
310 /*! If not a built-in stream, the caller is responsible for deleting it
312 void setNoticeStream(std::ostream& stream)
314 m_notice_stream = &stream;
317 //! Get the null stream
318 /*! Use this with set*Stream: i.e. msg.setNoticeStream(msg.getNullStream()).
319 Since this is passing an internal reference back in, there are no dangling reference problems. And there is
320 no need for the caller to manage the creation and deletion of a null stream.
322 std::ostream& getNullStream() const
324 return *m_nullstream;
327 //! Get the error prefix
328 /*! \returns Current prefix applied to error messages
330 const std::string& getErrorPrefix() const
332 return m_err_prefix;
335 //! Set the error prefix
336 /*! \param prefix Prefix to apply to error messages
337 \note ": " is appened to the end of the prefix
339 void setErrorPrefix(const std::string& prefix)
341 m_err_prefix = prefix;
344 //! Get the warning prefix
345 /*! \returns Current prefix applied to warning messages
347 const std::string& getWarningPrefix() const
349 return m_warning_prefix;
352 //! Set the warning prefix
353 /*! \param prefix Prefix to apply to warning messages
354 \note ": " is appened to the end of the prefix
356 void setWarningPrefix(const std::string& prefix)
358 m_warning_prefix = prefix;
361 //! Get the notice prefix
362 /*! \returns Current prefix applied to notice messages
364 const std::string& getNoticePrefix() const
366 return m_notice_prefix;
369 //! Set the notice prefix
370 /*! \param prefix Prefix to apply to notice messages
371 \note "(level): " is appened to the end of the prefix when level > 1
373 void setNoticePrefix(const std::string& prefix)
375 m_notice_prefix = prefix;
378 //! Open a file for error, warning, and notice streams
379 void openFile(const std::string& fname);
381 #ifdef ENABLE_MPI
382 //! Request logging of notices, warning and errors into shared log file
383 /*! \param fname The filenam
385 void setSharedFile(const std::string& fname)
387 m_shared_filename = fname;
389 openSharedFile();
392 //! Returns true if this if this rank has exclusive stdout access for error messages
393 bool hasLock() const
395 return m_has_lock;
398 //! Returns true if any process has locked the output
399 bool isLocked() const
401 int flag;
402 MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0,0, m_mpi_win);
403 MPI_Get(&flag, 1, MPI_INT, 0, 0, 1, MPI_INT, m_mpi_win);
404 MPI_Win_unlock(0, m_mpi_win);
405 return flag;
407 #endif
409 //! Open stdout and stderr again, closing any open file
410 void openStd();
411 private:
412 std::ostream *m_err_stream; //!< error stream
413 std::ostream *m_warning_stream; //!< warning stream
414 std::ostream *m_notice_stream; //!< notice stream
416 boost::shared_ptr<nullstream> m_nullstream; //!< null stream
417 boost::shared_ptr<std::ostream> m_file; //!< File stream
419 std::string m_err_prefix; //!< Prefix for error messages
420 std::string m_warning_prefix; //!< Prefix for warning messages
421 std::string m_notice_prefix; //!< Prefix for notice messages
423 unsigned int m_notice_level; //!< Notice level
425 unsigned int m_rank; //!< The MPI rank (default 0)
426 unsigned int m_partition; //!< The MPI partition
427 unsigned int m_nranks; //!< Number of ranks in communicator
429 #ifdef ENABLE_MPI
430 std::string m_shared_filename; //!< Filename of shared log file
431 MPI_Comm m_mpi_comm; //!< The MPI communicator
433 MPI_Win m_mpi_win; //!< MPI Window for atomic printing of error messages
434 int *m_error_flag; //!< Flag on (on processor 0) to lock stdout
435 mutable bool m_has_lock; //!< True if this rank has exclusive access to stdout
437 //! Open a shared file for error, warning, and notice streams
438 void openSharedFile();
440 //! Initialize RMA
441 void initializeSharedMem();
443 //! Free RMA
444 void releaseSharedMem();
445 #endif
448 //! Exports Messenger to python
449 void export_Messenger();
451 #endif // #ifndef __MESSENGER_H__