MueLu  Version of the Day
MueLu_MutuallyExclusiveTime.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_MUTUALLYEXCLUSIVETIME_HPP
47 #define MUELU_MUTUALLYEXCLUSIVETIME_HPP
48 
49 #include <string>
50 #include <stack>
51 #include <map>
52 #include <iostream> // for basic_ostream, etc
53 #include <utility> // for pair
54 #include "Teuchos_FancyOStream.hpp" // for basic_FancyOStream, etc
55 #include "Teuchos_RCP.hpp" // for RCP::operator->, etc
56 #include "Teuchos_RCPDecl.hpp" // for RCP
57 #include "Teuchos_TestForException.hpp" // for TEUCHOS_TEST_FOR_EXCEPTION
58 #include "Teuchos_Time.hpp"
59 #include "Teuchos_TimeMonitor.hpp"
60 #include "MueLu_ConfigDefs.hpp"
61 #include "MueLu_Exceptions.hpp"
62 #include "MueLu_BaseClass.hpp"
63 #include "MueLu_VerbosityLevel.hpp" // for MsgType::Debug, etc
64 
65 namespace MueLu {
66 
67  // Map that record parent/child relations for post-processing.
68  extern std::map<std::string,std::string> myParent_;
69 
84  template<class TagName>
86 
87  public:
88 
90 
91  MutuallyExclusiveTime(const std::string &name, bool startFlag=false)
93  : name_(name),
94  timer_(rcp(new Teuchos::Time(name, false))), // second argument is false in any case, because if start==true,
95  // timer has to be started by MutuallyExclusiveTime::start() instead of Teuchos::Time::start().
96  isPaused_(false)
97  {
98  if (startFlag == true) timer_->start();
99  }
100 
103  // This timer can only be destroyed if it is not in the stack
104  if (isPaused()) {
105  // error message because cannot throw an exception in destructor
106  GetOStream(Errors) << "MutuallyExclusiveTime::~MutuallyExclusiveTime(): Error: destructor called on a paused timer." << std::endl;
107  //TODO: Even if timing results will be wrong, the timer can be removed from the stack to avoid a segmentation fault.
108  }
109 
110  stop(); // if isRunning(), remove from the stack, resume previous timer
111  }
113 
117  void start(bool reset=false) {
118  TEUCHOS_TEST_FOR_EXCEPTION(isPaused(), Exceptions::RuntimeError, "MueLu::MutuallyExclusiveTime::start(): timer is paused. Use resume().");
119 
120  if (isRunning()) { return; } // If timer is already running, do not pause/push-in-the-stack/start the timer.
121  // Otherwise, something bad will happen when this.stop() will be called
122 
123  // pause currently running timer
124  if (!timerStack_.empty()) {
125  GetOStream(Debug) << "pausing parent timer " << timerStack_.top()->name_ << std::endl;
126  timerStack_.top()->pause();
127  GetOStream(Debug) << "starting child timer " << this->name_ << std::endl;
128  myParent_[this->name_] = timerStack_.top()->name_;
129  } else {
130  GetOStream(Debug) << "starting orphan timer " << this->name_ << std::endl;
131  myParent_[this->name_] = "no parent";
132  }
133 
134  // start this timer
135  timer_->start(reset);
136  timerStack_.push(this);
137  }
138 
140 
141 
145  double stop() {
146  TEUCHOS_TEST_FOR_EXCEPTION(isPaused(), Exceptions::RuntimeError, "MueLu::MutuallyExclusiveTime::start(): timer is paused. Use resume().");
147  if (!isRunning()) { return timer_->stop(); } // stop() can be called on stopped timer
148 
149  // Here, timer is running, so it is the head of the stack
150  TopOfTheStack();
151 
152  timerStack_.pop();
153  double r = timer_->stop();
154 
155  if (!timerStack_.empty()) {
156  GetOStream(Debug) << "resuming timer " << timerStack_.top()->name_ << std::endl;
157  timerStack_.top()->resume();
158  }
159 
160  return r;
161  }
162 
164  void pause() {
165  if (isPaused()) // calling twice pause() is allowed
166  return;
167 
168  TopOfTheStack();
169 
170  timer_->stop();
171  isPaused_ = true;
172  }
173 
177 
178  void resume() {
179  TopOfTheStack();
180 
181  // no 'shortcut' test necessary:
182  // - if timer is stop, it is in pause (cannot be stop and not in pause because this timer is the head of the stack).
183  // - if timer is running, nothing is changed by this function.
184 
185  timer_->start(false);
186  isPaused_ = false;
187  }
188 
190 
191 
193 
194 
195  bool isRunning() {
196  if (timer_->isRunning()) {
197  // TEUCHOS_TEST_FOR_EXCEPTION(timerStack_.top() != this, Exceptions::RuntimeError,
198  // "MueLu::MutuallyExclusiveTime::isRunning(): this timer is active so it is supposed to be the head of the stack");
199  }
200  return timer_->isRunning();
201  }
202 
203  bool isPaused() {
205  return isPaused_;
206  }
207 
209 
211  // Note: this function is provided by the timer class, not by a monitor (!= Teuchos)
212  static RCP<MutuallyExclusiveTime<TagName> > getNewTimer(const std::string& name) {
214  timer->name_ = name;
215  return timer;
216  }
217 
220 
222  std::string name_;
223 
230  static void PrintParentChildPairs() {
231  //key is child, value is parent
232  RCP<Teuchos::FancyOStream> fos = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)); fos->setOutputToRootOnly(0);
233  *fos << "Parent Child Map" << std::endl;
234  std::map<std::string, std::string >::const_iterator iter;
235  for (iter = ::MueLu::myParent_.begin(); iter != ::MueLu::myParent_.end(); ++iter) {
236  *fos << "Key: " << iter->first << " Value: " << iter->second << std::endl;
237  }
238  }
239 
240  private:
241 
245  : timer_(timer), isPaused_(false)
246  { }
247 
248  // MutuallyExclusiveTime() { }
249 
252  bool isPaused_;
253 
255  // - empty when no active timer
256  // - head is the active timer
257  // - other timers are timers paused to enforce the mutually exclusive property of the timer set.
258  static std::stack<MutuallyExclusiveTime<TagName>*> timerStack_;
259  //static std::map<std::string,std::string> myParent_;
260 
262  void TopOfTheStack() {
263  TEUCHOS_TEST_FOR_EXCEPTION(timerStack_.empty(), Exceptions::RuntimeError, "MueLu::MutuallyExclusiveTime::TopOfTheStack(): timer is not the head of the stack (stack is empty).");
264  // TEUCHOS_TEST_FOR_EXCEPTION(timerStack_.top() != this, Exceptions::RuntimeError, "MueLu::MutuallyExclusiveTime::TopOfTheStack(): timer is not the head of the stack.");
265  TEUCHOS_TEST_FOR_EXCEPTION(!(isRunning() || isPaused()), Exceptions::RuntimeError, "MueLu::MutuallyExclusiveTime::TopOfTheStack(): head of the stack timer is neither active nor paused.");
266  }
267 
268  //TODO: test integrity of the stack:
269  // Head = running or paused
270  // Other timers of the stack = paused
271 
272  };
273 
274 } // namespace MueLu
275 
276 #endif // MUELU_MUTUALLYEXCLUSIVETIME_HPP
277 
278 
void TopOfTheStack()
Check if &#39;this&#39; is the head of the stack.
static std::stack< MutuallyExclusiveTime< TagName > * > timerStack_
Stack of created timers (active or paused timers).
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
static void PrintParentChildPairs()
Print std::map of (child,parent) pairs for post-run analysis.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Print additional debugging information.
Namespace for MueLu classes and methods.
void start(bool reset=false)
Starts the timer. If a MutuallyExclusiveTime timer is running, it will be stopped.
static RCP< Time > getNewTimer(const std::string &name)
std::map< std::string, std::string > myParent_
double stop()
Stops the timer. The previous MutuallyExclusiveTime that has been paused when this timer was started ...
void start(bool reset=false)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
std::string name_
Name of this mutually exclusive timer.
double stop()
void incrementNumCalls()
Increment the number of times this timer has been called.
RCP< Teuchos::Time > timer_
Using an RCP allows to use Teuchos::TimeMonitor to keep track of the timer.
static RCP< MutuallyExclusiveTime< TagName > > getNewTimer(const std::string &name)
Return a new MutuallyExclusiveTime that is registered with the Teuchos::TimeMonitor (for timer summar...
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
void pause()
Pause running timer. Used internally by start().
Base class for MueLu classes.
void resume()
Resume paused timer. Used internally by stop(). Timer is not reset.
This class wraps a Teuchos::Time and maintains a mutually exclusive property between wrapped timers...
bool isRunning() const
Exception throws to report errors in the internal logical of the program.
void incrementNumCalls()
MutuallyExclusiveTime(const std::string &name, bool startFlag=false)
Constructor.
MutuallyExclusiveTime(RCP< Teuchos::Time > timer)