1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkSimpleFilterWatcher_h
19 #define itkSimpleFilterWatcher_h
20 
21 #include "itkCommand.h"
22 #include "itkProcessObject.h"
23 #include "itkTimeProbe.h"
24 
25 namespace itk
26 {
27 /** \class SimpleFilterWatcher
28  * \brief Simple mechanism for monitoring the pipeline events of a filter
29  * and reporting these events to std::cout.
30  *
31  * SimpleFilterWatcher provides a simple mechanism for monitoring the
32  * execution of filter.  SimpleFilterWatcher is a stack-based object
33  * which takes a pointer to a ProcessObject at constructor
34  * time. SimpleFilterWatcher creates a series of commands that are
35  * registered as observers to the specified ProcessObject. The events
36  * monitored are:
37  *
38  *      StartEvent
39  *      EndEvent
40  *      ProgressEvent
41  *      IterationEvent
42  *      AbortEvent
43  *
44  * The callbacks routines registered for these events emit a simple
45  * message to std::cout.
46  *
47  * Example of use:
48  *
49  * using FilterType = itk::BinaryThresholdImageFilter<ImageType>;
50  * FilterType::Pointer thresholdFilter = FilterType::New();
51  *
52  * SimpleFilterWatcher watcher(thresholdFilter, "Threshold");
53  *
54  * The second argument to the constructor to SimpleFilterWatcher is an
55  * optional string that is prepended to the event messages. This
56  * allows the user to associate the emitted messages to a particular
57  * filter/variable.
58  *
59  * \todo Allow any stream object to be used for the output (not just std::cout)
60  *
61  * \ingroup ITKCommon
62  *
63  * \wiki
64  * \wikiexample{Utilities/SimpleFilterWatcher,Monitor a filter}
65  * \endwiki
66  */
67 class ITKCommon_EXPORT SimpleFilterWatcher
68 {
69 public:
70   /** Constructor. Takes a ProcessObject to monitor and an optional
71    * comment string that is prepended to each event message. */
72   SimpleFilterWatcher(itk::ProcessObject *o, const char *comment = "");
73 
74   /** Copy constructor */
75   SimpleFilterWatcher(const SimpleFilterWatcher &);
76 
77   /** Default constructor. Only provided so that you can have
78    * std::vectors of SimpleFilterWatchers. */
79   SimpleFilterWatcher();
80 
81   /** operator=  */
82   SimpleFilterWatcher & operator=(const SimpleFilterWatcher &);
83 
84   /** Destructor. */
85   virtual ~SimpleFilterWatcher();
86 
87   /** Method to get the name of the class be monitored by this
88    *  SimpleFilterWatcher */
GetNameOfClass()89   const char * GetNameOfClass()
90   {
91     return ( m_Process ? m_Process->GetNameOfClass() : "None" );
92   }
93 
94   /** Methods to control the verbosity of the messages. Quiet
95    * reporting limits the information emitted at a ProgressEvent. */
QuietOn()96   void QuietOn() { m_Quiet = true; }
QuietOff()97   void QuietOff() { m_Quiet = false; }
98 
99   /** Methods to use to test the AbortEvent of the a filter. If
100    * TestAbort is on, the filter being watched will be aborted when
101    * the progress reaches 30%. */
TestAbortOn()102   void TestAbortOn() { m_TestAbort = true; }
TestAbortOff()103   void TestAbortOff() { m_TestAbort = false; }
104 
105   /** Methods to access member data */
106   /** Get a pointer to the process object being watched. */
GetProcess()107   ProcessObject * GetProcess() { return m_Process.GetPointer(); }
108 
109   /** Set/Get the steps completed. */
SetSteps(int val)110   void SetSteps(int val) { m_Steps = val; }
GetSteps()111   int GetSteps() { return m_Steps; }
112 
113   /** Set/Get the number of iterations completed. */
SetIterations(int val)114   void SetIterations(int val) { m_Iterations = val; }
GetIterations()115   int GetIterations() { return m_Iterations; }
116 
117   /** Set/Get the quiet mode boolean. If true, verbose progress is
118     * reported. */
SetQuiet(bool val)119   void SetQuiet(bool val) { m_Quiet = val; }
GetQuiet()120   bool GetQuiet() { return m_Quiet; }
121 
122   /** Get the comment for the watcher. */
GetComment()123   std::string GetComment() { return m_Comment; }
124 
125   /** Get a reference to the TimeProbe */
GetTimeProbe()126   TimeProbe & GetTimeProbe() { return m_TimeProbe; }
127 
128 protected:
129 
130   /** Callback method to show the ProgressEvent */
ShowProgress()131   virtual void ShowProgress()
132   {
133     if ( m_Process )
134       {
135       m_Steps++;
136       if ( !m_Quiet )
137         {
138         std::cout << " | " << m_Process->GetProgress() << std::flush;
139         if ( ( m_Steps % 10 ) == 0 )
140           {
141           std::cout << std::endl;
142           }
143         }
144       if ( m_TestAbort )
145         {
146         if ( m_Process->GetProgress() > .03 )
147           {
148           m_Process->AbortGenerateDataOn();
149           }
150         }
151       }
152   }
153 
154   /** Create commands for different event types. */
155   void CreateCommands();
156 
157   /** Remove observers we have on the process object. */
158   void RemoveObservers();
159 
160   /** The common code for copying this class. */
161   void DeepCopy(const SimpleFilterWatcher & watch);
162 
163   /** Callback method to show the AbortEvent */
ShowAbort()164   virtual void ShowAbort()
165   {
166     std::cout << std::endl << "-------Aborted" << std::endl << std::flush;
167   }
168 
169   /** Callback method to show the IterationEvent */
ShowIteration()170   virtual void ShowIteration()
171   {
172     std::cout << " #" << std::flush;
173     m_Iterations++;
174   }
175 
176   /** Callback method to show the StartEvent */
StartFilter()177   virtual void StartFilter()
178   {
179     m_Steps = 0;
180     m_Iterations = 0;
181     m_TimeProbe.Start();
182     std::cout << "-------- Start "
183               << ( m_Process.GetPointer() ? m_Process->GetNameOfClass() : "None" )
184               << " \"" << m_Comment << "\" ";
185     if ( !m_Quiet )
186       {
187       if ( m_Process )
188         {
189         std::cout << m_Process;
190         }
191       else
192         {
193         std::cout << "Null";
194         }
195       }
196     std::cout << ( m_Quiet ? "Progress Quiet " : "Progress " )
197               << std::flush;
198   }
199 
200   /** Callback method to show the EndEvent */
EndFilter()201   virtual void EndFilter()
202   {
203     m_TimeProbe.Stop();
204     std::cout << std::endl << "Filter took "
205               << m_TimeProbe.GetMean()
206               << " seconds.";
207     std::cout << std::endl
208               << "-------- End "
209               << ( m_Process.GetPointer() ? m_Process->GetNameOfClass() : "None" )
210               << " \"" << m_Comment << "\" " << std::endl;
211     if ( !m_Quiet )
212       {
213       if ( m_Process )
214         {
215         std::cout << m_Process;
216         }
217       else
218         {
219         std::cout << "None";
220         }
221       std::cout << std::flush;
222       }
223     if ( m_Steps < 1 )
224       {
225       itkExceptionMacro ("Filter does not have progress.");
226       }
227   }
228 
229 private:
230   TimeProbe                   m_TimeProbe;
231   int                         m_Steps{0};
232   int                         m_Iterations{0};
233   bool                        m_Quiet{false};
234   bool                        m_TestAbort{false};
235   std::string                 m_Comment;
236   itk::ProcessObject::Pointer m_Process;
237 
238   using CommandType = SimpleMemberCommand< SimpleFilterWatcher >;
239   CommandType::Pointer m_StartFilterCommand;
240   CommandType::Pointer m_EndFilterCommand;
241   CommandType::Pointer m_ProgressFilterCommand;
242   CommandType::Pointer m_IterationFilterCommand;
243   CommandType::Pointer m_AbortFilterCommand;
244 
245   unsigned long m_StartTag{0};
246   unsigned long m_EndTag{0};
247   unsigned long m_ProgressTag{0};
248   unsigned long m_IterationTag{0};
249   unsigned long m_AbortTag{0};
250 };
251 } // end namespace itk
252 
253 #endif
254