LevelS C++ support library  3.83
walltimer.cc
1 /*
2  * This file is part of libcxxsupport.
3  *
4  * libcxxsupport is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * libcxxsupport is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with libcxxsupport; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /*
20  * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
21  * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
22  * (DLR).
23  */
24 
25 /*
26  * This file contains functionality related to wall-clock timers
27  *
28  * Copyright (C) 2010, 2011, 2012 Max-Planck-Society
29  * Author: Martin Reinecke
30  */
31 
32 #include <iostream>
33 #include <utility>
34 #include <cstdio>
35 #include <cmath>
36 #include <algorithm>
37 #include <chrono>
38 #include "walltimer.h"
39 #include "error_handling.h"
40 
41 using namespace std;
42 
43 namespace {
44 
45 using clock = std::chrono::steady_clock;
46 
47 double wallTime()
48  {
49  static clock::time_point starttime(clock::now());
50  return chrono::duration<double>(clock::now() - starttime).count();
51  }
52 
53 } // unnamed namespace
54 
55 void wallTimer::start()
56  { start(wallTime()); }
57 void wallTimer::stop()
58  { stop(wallTime()); }
59 double wallTimer::acc() const
60  { return acc(wallTime()); }
61 
62 int wallTimerSet::getIndex(const string &name)
63  {
64  maptype::const_iterator it = lut.find(name);
65  if (it!=lut.end())
66  return it->second;
67  timer.push_back(wallTimer());
68  lut[name]=timer.size()-1;
69  return timer.size()-1;
70  }
71 
72 void wallTimerSet::start(int index)
73  { timer[index].start(); }
74 void wallTimerSet::stop(int index)
75  { timer[index].stop(); }
76 void wallTimerSet::stopstart(int index1, int index2)
77  { double t=wallTime(); timer[index1].stop(t); timer[index2].start(t); }
78 void wallTimerSet::reset(int index)
79  { timer[index].reset(); }
80 double wallTimerSet::acc(int index)
81  { return timer[index].acc(); }
82 void wallTimerSet::start(const string &name)
83  { start(getIndex(name)); }
84 void wallTimerSet::stop(const string &name)
85  { stop(getIndex(name)); }
86 void wallTimerSet::stopstart(const string &name1, const string &name2)
87  { stopstart(getIndex(name1),getIndex(name2)); }
88 void wallTimerSet::reset(const string &name)
89  { reset(getIndex(name)); }
90 double wallTimerSet::acc(const string &name)
91  { return acc(getIndex(name)); }
92 
93 void wallTimerSet::report() const
94  {
95  cout << "\nWall clock timer report:" << endl;
96  for (maptype::const_iterator it=lut.begin(); it!=lut.end(); ++it)
97  printf(" %-15s: %10.5fs\n", it->first.c_str(), timer[it->second].acc());
98  cout << "End wall clock timer report\n" << endl;
99  }
100 
101 wallTimerSet wallTimers;
102 
103 namespace {
104 
105 class tstack_node;
106 
107 typedef map<string,tstack_node>::iterator Ti;
108 typedef map<string,tstack_node>::const_iterator Tci;
109 typedef pair<Tci,double> Tipair;
110 
111 class tstack_node
112  {
113  public:
114  tstack_node *parent;
115  wallTimer wt;
116  string name;
117  map<string,tstack_node> child;
118 
119  tstack_node(const string &name_, tstack_node *parent_)
120  : parent(parent_), name(name_) {}
121 
122  int max_namelen() const
123  {
124  int res=name.length();
125  for (Tci it=child.begin(); it!=child.end(); ++it)
126  res=max(res,it->second.max_namelen());
127  return res;
128  }
129  };
130 
131 tstack_node tstack_root("root",0);
132 tstack_node *curnode=0;
133 double overhead=0.;
134 
135 struct timecomp
136  {
137  bool operator() (const Tipair &a, const Tipair &b) const
138  { return a.second>b.second; }
139  };
140 
141 void tstack_report(const tstack_node &node, const string &indent, int twidth,
142  int slen)
143  {
144  double total=node.wt.acc();
145  vector<Tipair> tmp;
146  for (Tci it=node.child.begin(); it!=node.child.end(); ++it)
147  tmp.push_back(make_pair(it,it->second.wt.acc()));
148 
149  if (tmp.size()>0)
150  {
151  sort(tmp.begin(),tmp.end(),timecomp());
152  double tsum=0;
153  printf("%s|\n", indent.c_str());
154  for (unsigned i=0; i<tmp.size(); ++i)
155  {
156  printf("%s+- %-*s:%6.2f%% (%*.4fs)\n",indent.c_str(),slen,
157  (tmp[i].first->first).c_str(), 100*tmp[i].second/total,twidth,
158  tmp[i].second);
159  tstack_report(tmp[i].first->second,indent+"| ",twidth,slen);
160  tsum+=tmp[i].second;
161  }
162  printf("%s+- %-*s:%6.2f%% (%*.4fs)\n%s\n",indent.c_str(),slen,
163  "<unaccounted>",100*(total-tsum)/total,twidth,total-tsum,indent.c_str());
164  }
165  }
166 
167 } // unnamed namespace
168 
169 void tstack_push(const string &name)
170  {
171  double t0=wallTime();
172  if (curnode==0) curnode=&tstack_root;
173  Ti it=curnode->child.find(name);
174  if (it==curnode->child.end())
175  it=curnode->child.insert (make_pair(name,tstack_node(name,curnode))).first;
176  curnode=&(it->second);
177  double t1=wallTime();
178  curnode->wt.start(0.5*(t0+t1));
179  overhead+=t1-t0;
180  }
181 void tstack_pop(const string &name)
182  {
183  double t0=wallTime();
184  planck_assert(curnode && (curnode->name==name), "invalid tstack operation");
185  double t1=wallTime();
186  curnode->wt.stop(0.5*(t0+t1));
187  curnode=curnode->parent;
188  overhead+=t1-t0;
189  }
190 void tstack_pop()
191  {
192  double t0=wallTime();
193  planck_assert(curnode, "invalid tstack operation");
194  double t1=wallTime();
195  curnode->wt.stop(0.5*(t0+t1));
196  curnode=curnode->parent;
197  overhead+=t1-t0;
198  }
199 void tstack_replace(const string &name2)
200  {
201  double t0=wallTime();
202  planck_assert(curnode, "invalid tstack operation");
203  tstack_node *savenode=curnode;
204  curnode=curnode->parent;
205  Ti it=curnode->child.find(name2);
206  if (it==curnode->child.end())
207  it=curnode->child.insert(make_pair(name2,tstack_node(name2,curnode))).first;
208  curnode=&(it->second);
209  double t1=wallTime();
210  double t=0.5*(t0+t1);
211  savenode->wt.stop(t);
212  curnode->wt.start(t);
213  overhead+=t1-t0;
214  }
215 void tstack_replace(const string &name1, const string &name2)
216  {
217  planck_assert(curnode && (curnode->name==name1), "invalid tstack operation");
218  tstack_replace(name2);
219  }
220 
221 void tstack_report(const string &stem)
222  {
223  const tstack_node *ptr = 0;
224  for (Tci it=tstack_root.child.begin(); it!=tstack_root.child.end(); ++it)
225  if (it->first==stem) ptr=&(it->second);
226  planck_assert(ptr,"invalid stem");
227  int slen=string("<unaccounted>").size();
228  slen = max(slen,ptr->max_namelen());
229 
230  double total=ptr->wt.acc();
231  printf("\nTotal wall clock time for '%s': %1.4fs\n",stem.c_str(),total);
232 
233  int logtime=max(1,int(log10(total)+1));
234  tstack_report(*ptr,"",logtime+5,slen);
235 
236  printf("\nAccumulated timing overhead: approx. %1.4fs\n",overhead);
237  }
#define planck_assert(testval, msg)

Generated on Wed Nov 13 2024 12:18:16 for LevelS C++ support library