CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
job_timer.hpp
1 #ifndef CPPAD_CG_JOB_TIMER_INCLUDED
2 #define CPPAD_CG_JOB_TIMER_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2013 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 namespace CppAD {
19 namespace cg {
20 
24 class JobType {
25 private:
29  std::string _action;
33  std::string _actionEnd;
34 public:
35 
36  inline JobType(const std::string& action,
37  const std::string& actionEnd) :
38  _action(action),
39  _actionEnd(actionEnd) {
40  }
41 
42  inline const std::string& getActionName() const {
43  return _action;
44  }
45 
46  inline void setActionName(const std::string& action) {
47  _action = action;
48  }
49 
50  inline const std::string& getActionEndName()const {
51  return _actionEnd;
52  }
53 
54  inline void setActionEndName(const std::string& actionEnd) {
55  _actionEnd = actionEnd;
56  }
57 
58  inline virtual ~JobType() {
59  }
60 };
61 
65 template<int T = 0 >
67 public:
68  static const JobType DEFAULT;
69  static const JobType LOOP_DETECTION;
70  static const JobType GRAPH;
71  static const JobType SOURCE_FOR_MODEL;
72  static const JobType SOURCE_GENERATION;
73  static const JobType COMPILING_FOR_MODEL;
74  static const JobType COMPILING;
75  static const JobType COMPILING_DYNAMIC_LIBRARY;
76  static const JobType DYNAMIC_MODEL_LIBRARY;
77  static const JobType STATIC_MODEL_LIBRARY;
78  static const JobType ASSEMBLE_STATIC_LIBRARY;
79  static const JobType JIT_MODEL_LIBRARY;
80 };
81 
82 template<int T>
83 const JobType JobTypeHolder<T>::DEFAULT("generating", "generated");
84 
85 template<int T>
86 const JobType JobTypeHolder<T>::LOOP_DETECTION("starting loop detection", "ended loop detection");
87 
88 template<int T>
89 const JobType JobTypeHolder<T>::GRAPH("creating operation graph for", "created operation graph for");
90 
91 template<int T>
92 const JobType JobTypeHolder<T>::SOURCE_FOR_MODEL("source-code for model", "source-code for model");
93 
94 template<int T>
95 const JobType JobTypeHolder<T>::SOURCE_GENERATION("generating source for", "generated source for");
96 
97 template<int T>
98 const JobType JobTypeHolder<T>::COMPILING_FOR_MODEL("compiling object files", "compiled object files");
99 
100 template<int T>
101 const JobType JobTypeHolder<T>::COMPILING("compiling", "compiled");
102 
103 template<int T>
104 const JobType JobTypeHolder<T>::COMPILING_DYNAMIC_LIBRARY("compiling dynamic library", "compiled library");
105 
106 template<int T>
107 const JobType JobTypeHolder<T>::DYNAMIC_MODEL_LIBRARY("creating library", "created library");
108 
109 template<int T>
110 const JobType JobTypeHolder<T>::STATIC_MODEL_LIBRARY("creating library", "created library");
111 
112 template<int T>
113 const JobType JobTypeHolder<T>::ASSEMBLE_STATIC_LIBRARY("assembling static library", "assembled static library");
114 
115 template<int T>
116 const JobType JobTypeHolder<T>::JIT_MODEL_LIBRARY("preparing JIT library", "prepared JIT library");
117 
121 class Job {
122 private:
126  const JobType* _type;
130  std::string _name;
134  std::chrono::steady_clock::time_point _beginTime;
138  bool _nestedJobs;
139 public:
140 
141  inline Job(const JobType& type,
142  const std::string& name) :
143  _type(&type),
144  _name(name),
145  _beginTime(std::chrono::steady_clock::now()),
146  _nestedJobs(false) {
147  }
148 
149  inline const JobType& getType()const {
150  return *_type;
151  }
152 
153  inline const std::string& name() const {
154  return _name;
155  }
156 
157  inline std::chrono::steady_clock::time_point beginTime() const {
158  return _beginTime;
159  }
160 
161  inline virtual ~Job() {
162  }
163 
164  friend class JobTimer;
165 };
166 
170 class JobListener {
171 public:
172  using duration = std::chrono::steady_clock::duration;
173 
174  virtual void jobStarted(const std::vector<Job>& job) = 0;
175 
176  virtual void jobEndended(const std::vector<Job>& job,
177  duration elapsed) = 0;
178 };
179 
183 class JobTimer : public JobTypeHolder<> {
184 protected:
189  bool _verbose;
190 private:
194  std::vector<Job> _jobs;
198  size_t _maxLineWidth;
202  size_t _indent;
206  std::ostringstream _os;
210  std::string _action;
214  std::string _actionEnd;
218  std::set<JobListener*> _listeners;
219 public:
220 
221  JobTimer() :
222  _verbose(false),
223  _maxLineWidth(80),
224  _indent(2) {
225  }
226 
227  inline bool isVerbose() const {
228  return _verbose;
229  }
230 
231  inline void setVerbose(bool verbose) {
232  _verbose = verbose;
233  }
234 
235  inline size_t getMaxLineWidth() const {
236  return _maxLineWidth;
237  }
238 
239  inline void setMaxLineWidth(size_t width) {
240  _maxLineWidth = width;
241  }
242 
248  inline size_t getJobCount() const {
249  return _jobs.size();
250  }
251 
252  inline void addListener(JobListener& l) {
253  _listeners.insert(&l);
254  }
255 
256  inline bool removeListener(JobListener& l) {
257  return _listeners.erase(&l) > 0;
258  }
259 
260  inline void startingJob(const std::string& jobName,
261  const JobType& type = JobTypeHolder<>::DEFAULT,
262  const std::string& prefix = "") {
263 
264  _jobs.push_back(Job(type, jobName));
265 
266  if (_verbose) {
267  OStreamConfigRestore osr(std::cout);
268 
269  Job& job = _jobs.back();
270 
271  size_t indent = 0;
272  if (_jobs.size() > 1) {
273  Job& parent = _jobs[_jobs.size() - 2]; // must be after adding job
274  if (!parent._nestedJobs) {
275  parent._nestedJobs = true;
276  std::cout << "\n";
277  }
278  indent = _indent * (_jobs.size() - 1);
279  }
280 
281  _os.str("");
282  if (indent > 0) _os << std::string(indent, ' ');
283  if (!prefix.empty()) _os << prefix << " ";
284  _os << type.getActionName() << " " << job.name() << " ...";
285 
286  char f = std::cout.fill();
287  std::cout << std::setw(_maxLineWidth) << std::setfill('.') << std::left << _os.str();
288  std::cout.flush();
289  std::cout.fill(f); // restore fill character
290  }
291 
292  // notify listeners
293  for (JobListener* l : _listeners) {
294  l->jobStarted(_jobs);
295  }
296  }
297 
298  inline void finishedJob() {
299  using namespace std::chrono;
300 
301  CPPADCG_ASSERT_UNKNOWN(_jobs.size() > 0);
302 
303  Job& job = _jobs.back();
304 
305  std::chrono::steady_clock::duration elapsed = steady_clock::now() - job.beginTime();
306 
307  if (_verbose) {
308  OStreamConfigRestore osr(std::cout);
309 
310  if (job._nestedJobs) {
311  _os.str("");
312  if (!_jobs.empty())
313  _os << std::string(_indent * (_jobs.size() - 1), ' ');
314  _os << job.getType().getActionEndName() << " " << job.name() << " ...";
315 
316  char f = std::cout.fill();
317  std::cout << std::setw(_maxLineWidth) << std::setfill('.') << std::left << _os.str();
318  std::cout.fill(f); // restore fill character
319  }
320 
321  std::cout << " done [" << std::fixed << std::setprecision(3) << duration<float>(elapsed).count() << "]" << std::endl;
322  }
323 
324  // notify listeners
325  for (JobListener* l : _listeners) {
326  l->jobEndended(_jobs, elapsed);
327  }
328 
329  _jobs.pop_back();
330  }
331 
332 };
333 
334 } // END cg namespace
335 } // END CppAD namespace
336 
337 #endif
size_t getJobCount() const
Definition: job_timer.hpp:248