PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Basics/Timing.h

https://gitlab.com/schiotz/asap
C Header | 311 lines | 251 code | 27 blank | 33 comment | 31 complexity | 6f2a8b0a1f955b6b91ee4a67d2204271 MD5 | raw file
Possible License(s): GPL-3.0
  1. // Timing.h -- -*- C++ -*-
  2. // If compiled with -DTIMING the USETIMER("functionname") macro
  3. // can be used to time functions. If TIMING is not defined, USETIMER does
  4. // nothing.
  5. //
  6. // Copyright (C) 2001-2011 Jakob Schiotz and Center for Individual
  7. // Nanoparticle Functionality, Department of Physics, Technical
  8. // University of Denmark. Email: schiotz@fysik.dtu.dk
  9. //
  10. // This file is part of Asap version 3.
  11. // Asap is released under the GNU Lesser Public License (LGPL) version 3.
  12. // However, the parts of Asap distributed within the OpenKIM project
  13. // (including this file) are also released under the Common Development
  14. // and Distribution License (CDDL) version 1.0.
  15. //
  16. // This program is free software: you can redistribute it and/or
  17. // modify it under the terms of the GNU Lesser General Public License
  18. // version 3 as published by the Free Software Foundation. Permission
  19. // to use other versions of the GNU Lesser General Public License may
  20. // granted by Jakob Schiotz or the head of department of the
  21. // Department of Physics, Technical University of Denmark, as
  22. // described in section 14 of the GNU General Public License.
  23. //
  24. // This program is distributed in the hope that it will be useful,
  25. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. // GNU General Public License for more details.
  28. //
  29. // You should have received a copy of the GNU General Public License
  30. // and the GNU Lesser Public License along with this program. If not,
  31. // see <http://www.gnu.org/licenses/>.
  32. #ifndef _TIMING_H
  33. #define _TIMING_H
  34. #include "Asap.h"
  35. #ifdef TIMING
  36. #define USETIMER(x) Timing_administrator timer__(x)
  37. #else
  38. #define USETIMER(x)
  39. #endif
  40. #ifdef TIMING
  41. #include <sys/times.h>
  42. #include <unistd.h>
  43. #include <map>
  44. #include <stack>
  45. #include <sstream>
  46. #include <vector>
  47. #include "Exception.h"
  48. #include <string>
  49. #ifdef _OPENMP
  50. #include <omp.h>
  51. #endif
  52. using namespace std;
  53. namespace ASAPSPACE {
  54. class Timing_timer {
  55. public:
  56. inline Timing_timer(string name);
  57. inline void Start(Timing_timer *parent = 0);
  58. inline void Start(clock_t w, clock_t c);
  59. inline void Stop();
  60. inline void GoToChild(clock_t w, clock_t c);
  61. inline void ReturnFromChild(clock_t w, clock_t c);
  62. inline void Sync();
  63. inline void Report(string &name, double &wall, double &cpu,
  64. double &wall_c, double &cpu_c, int &count);
  65. public:
  66. string name;
  67. clock_t cputime;
  68. clock_t walltime;
  69. clock_t cputime_c;
  70. clock_t walltime_c;
  71. int count;
  72. int active;
  73. std::map<string, Timing_timer *> masters;
  74. private:
  75. clock_t runningcpu;
  76. clock_t runningwall;
  77. Timing_timer *parenttimer;
  78. Timing_timer *activemaster;
  79. };
  80. class Timing_administrator {
  81. public:
  82. inline Timing_administrator(string name, bool inuse = true);
  83. inline ~Timing_administrator();
  84. private:
  85. Timing_timer *timer;
  86. int threadnum;
  87. bool inuse;
  88. };
  89. // Global variables
  90. #ifdef ALLOCATE_TIMING
  91. #define EXTERN
  92. #else
  93. #define EXTERN extern
  94. #endif
  95. EXTERN std::map<string, Timing_timer *> Timing_timerpool;
  96. EXTERN std::vector<std::stack<Timing_timer *> > Timing_timerstack;
  97. EXTERN Timing_timer *Timing_metatimer;
  98. EXTERN clock_t Timing_Resolution;
  99. #undef EXTERN
  100. void Timing_assert_failed(const char *assertion, const char *file,
  101. const unsigned int line);
  102. // Inline functions
  103. inline void Timing_init() {
  104. Timing_timerpool.clear();
  105. #ifdef _OPENMP
  106. int ncpu = omp_get_num_procs();
  107. Timing_timerstack.resize(ncpu);
  108. #else
  109. Timing_timerstack.resize(1);
  110. #endif
  111. Timing_timer *global = new Timing_timer("Global");
  112. Timing_timerpool["Global"] = global;
  113. Timing_timerstack[0].push(global);
  114. global->Start();
  115. Timing_Resolution = sysconf(_SC_CLK_TCK);
  116. Timing_metatimer = new Timing_timer("Timing overhead");
  117. Timing_timerpool["Timing overhead"] = Timing_metatimer;
  118. }
  119. inline Timing_administrator::Timing_administrator(string name, bool inuse) {
  120. this->inuse = inuse;
  121. if (inuse)
  122. {
  123. #ifdef _OPENMP
  124. threadnum = omp_get_thread_num();
  125. char buffer[100];
  126. if (threadnum == 0)
  127. Timing_metatimer->Start();
  128. sprintf(buffer, "-%d", threadnum);
  129. name += buffer;
  130. #else
  131. threadnum = 0;
  132. Timing_metatimer->Start();
  133. #endif
  134. #ifdef _OPENMP
  135. #pragma omp critical
  136. #endif // _OPENMP
  137. {
  138. timer = Timing_timerpool[name];
  139. if (!timer)
  140. {
  141. timer = new Timing_timer(name);
  142. Timing_timerpool[name] = timer;
  143. }
  144. }
  145. Timing_timer *lastt = NULL;
  146. if (Timing_timerstack[threadnum].size())
  147. lastt = Timing_timerstack[threadnum].top();
  148. timer->Start(lastt);
  149. Timing_timerstack[threadnum].push(timer);
  150. if (threadnum == 0)
  151. Timing_metatimer->Stop();
  152. }
  153. }
  154. inline Timing_administrator::~Timing_administrator() {
  155. if (inuse)
  156. {
  157. if (threadnum == 0)
  158. Timing_metatimer->Start();
  159. Timing_timer *lastt = Timing_timerstack[threadnum].top();
  160. Timing_timerstack[threadnum].pop();
  161. if (lastt != timer)
  162. throw AsapError("INCONSISTENT TIMER: Stopping ") << timer->name
  163. << " but last timer is " << lastt->name;
  164. timer->Stop();
  165. if (threadnum == 0)
  166. Timing_metatimer->Stop();
  167. }
  168. }
  169. inline void Timing_gettimes(clock_t *wall, clock_t *cpu) {
  170. struct tms t;
  171. *wall = times(&t);
  172. *cpu = t.tms_utime + t.tms_stime;
  173. }
  174. Timing_timer::Timing_timer(string name) : masters()
  175. {
  176. this->name = name;
  177. cputime = 0;
  178. walltime = 0;
  179. cputime_c = 0;
  180. walltime_c = 0;
  181. active = 0;
  182. parenttimer = 0;
  183. activemaster = 0;
  184. count = 0;
  185. }
  186. void Timing_timer::Start(Timing_timer *parent)
  187. {
  188. assert(active == 0);
  189. active = 1;
  190. count++;
  191. Timing_gettimes(&runningwall, &runningcpu);
  192. parenttimer = parent;
  193. if (parent) {
  194. parent->GoToChild(runningwall, runningcpu);
  195. activemaster = masters[parent->name];
  196. if (!activemaster) {
  197. activemaster = new Timing_timer(parent->name);
  198. masters[parent->name] = activemaster;
  199. }
  200. activemaster->Start(runningwall, runningcpu);
  201. }
  202. else
  203. activemaster = 0;
  204. }
  205. void Timing_timer::Start(clock_t w, clock_t c)
  206. {
  207. assert(active == 0);
  208. active = 1;
  209. count++;
  210. runningwall = w;
  211. runningcpu = c;
  212. parenttimer = 0;
  213. activemaster = 0;
  214. }
  215. void Timing_timer::Stop()
  216. {
  217. assert(active == 1);
  218. active = 0;
  219. clock_t w, c;
  220. Timing_gettimes(&w, &c);
  221. walltime += w - runningwall;
  222. cputime += c - runningcpu;
  223. if (parenttimer)
  224. parenttimer->ReturnFromChild(w, c);
  225. if (activemaster)
  226. activemaster->Stop();
  227. }
  228. void Timing_timer::GoToChild(clock_t w, clock_t c)
  229. {
  230. assert(active == 1);
  231. active = 2;
  232. walltime += w - runningwall;
  233. cputime += c - runningcpu;
  234. runningwall = w;
  235. runningcpu = c;
  236. if (activemaster)
  237. activemaster->GoToChild(w, c);
  238. }
  239. void Timing_timer::ReturnFromChild(clock_t w, clock_t c)
  240. {
  241. assert(active == 2);
  242. active = 1;
  243. walltime_c += w - runningwall;
  244. cputime_c += c - runningcpu;
  245. runningwall = w;
  246. runningcpu = c;
  247. if (activemaster)
  248. activemaster->ReturnFromChild(w, c);
  249. }
  250. void Timing_timer::Sync()
  251. {
  252. if (active) {
  253. clock_t w, c;
  254. Timing_gettimes(&w, &c);
  255. if (active == 1)
  256. {
  257. walltime += w - runningwall;
  258. cputime += c - runningcpu;
  259. }
  260. if (active == 2)
  261. {
  262. walltime_c += w - runningwall;
  263. cputime_c += c - runningcpu;
  264. }
  265. runningwall = w;
  266. runningcpu = c;
  267. }
  268. if (activemaster)
  269. activemaster->Sync();
  270. }
  271. inline void Timing_timer::Report(string &name, double &wall, double &cpu,
  272. double &wall_c, double &cpu_c, int &count)
  273. {
  274. Sync();
  275. name = this->name;
  276. wall = 1.0 * walltime / Timing_Resolution;
  277. cpu = 1.0 * cputime / Timing_Resolution;
  278. wall_c = 1.0 * walltime_c / Timing_Resolution;
  279. cpu_c = 1.0 * cputime_c / Timing_Resolution;
  280. count = this->count;
  281. }
  282. } // end namespace
  283. #endif // TIMING
  284. #endif // _TIMING_H