timer.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. // Copyright (c) 2018 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Contains utils for getting resource utilization
  15. #ifndef SOURCE_UTIL_TIMER_H_
  16. #define SOURCE_UTIL_TIMER_H_
  17. #if defined(SPIRV_TIMER_ENABLED)
  18. #include <sys/resource.h>
  19. #include <cassert>
  20. #include <iostream>
  21. // A macro to call spvtools::utils::PrintTimerDescription(std::ostream*, bool).
  22. // The first argument must be given as std::ostream*. If it is NULL, the
  23. // function does nothing. Otherwise, it prints resource types measured by Timer
  24. // class. The second is optional and if it is true, the function also prints
  25. // resource type fields related to memory. Otherwise, it does not print memory
  26. // related fields. Its default is false. In usual, this must be placed before
  27. // calling Timer::Report() to inform what those fields printed by
  28. // Timer::Report() indicate (or spvtools::utils::PrintTimerDescription() must be
  29. // used instead).
  30. #define SPIRV_TIMER_DESCRIPTION(...) \
  31. spvtools::utils::PrintTimerDescription(__VA_ARGS__)
  32. // Creates an object of ScopedTimer to measure the resource utilization for the
  33. // scope surrounding it as the following example:
  34. //
  35. // { // <-- beginning of this scope
  36. //
  37. // /* ... code out of interest ... */
  38. //
  39. // SPIRV_TIMER_SCOPED(std::cout, tag);
  40. //
  41. // /* ... lines of code that we want to know its resource usage ... */
  42. //
  43. // } // <-- end of this scope. The destructor of ScopedTimer prints tag and
  44. // the resource utilization to std::cout.
  45. #define SPIRV_TIMER_SCOPED(...) \
  46. spvtools::utils::ScopedTimer<spvtools::utils::Timer> timer##__LINE__( \
  47. __VA_ARGS__)
  48. namespace spvtools {
  49. namespace utils {
  50. // Prints the description of resource types measured by Timer class. If |out| is
  51. // NULL, it does nothing. Otherwise, it prints resource types. The second is
  52. // optional and if it is true, the function also prints resource type fields
  53. // related to memory. Its default is false. In usual, this must be placed before
  54. // calling Timer::Report() to inform what those fields printed by
  55. // Timer::Report() indicate.
  56. void PrintTimerDescription(std::ostream*, bool = false);
  57. // Status of Timer. kGetrusageFailed means it failed in calling getrusage().
  58. // kClockGettimeWalltimeFailed means it failed in getting wall time when calling
  59. // clock_gettime(). kClockGettimeCPUtimeFailed means it failed in getting CPU
  60. // time when calling clock_gettime().
  61. enum UsageStatus {
  62. kSucceeded = 0,
  63. kGetrusageFailed = 1 << 0,
  64. kClockGettimeWalltimeFailed = 1 << 1,
  65. kClockGettimeCPUtimeFailed = 1 << 2,
  66. };
  67. // Timer measures the resource utilization for a range of code. The resource
  68. // utilization consists of CPU time (i.e., process time), WALL time (elapsed
  69. // time), USR time, SYS time, RSS delta, and the delta of the number of page
  70. // faults. RSS delta and the delta of the number of page faults are measured
  71. // only when |measure_mem_usage| given to the constructor is true. This class
  72. // should be used as the following example:
  73. //
  74. // spvtools::utils::Timer timer(std::cout);
  75. // timer.Start(); // <-- set |usage_before_|, |wall_before_|,
  76. // and |cpu_before_|
  77. //
  78. // /* ... lines of code that we want to know its resource usage ... */
  79. //
  80. // timer.Stop(); // <-- set |cpu_after_|, |wall_after_|, and
  81. // |usage_after_|
  82. // timer.Report(tag); // <-- print tag and the resource utilization to
  83. // std::cout.
  84. class Timer {
  85. public:
  86. Timer(std::ostream* out, bool measure_mem_usage = false)
  87. : report_stream_(out),
  88. usage_status_(kSucceeded),
  89. measure_mem_usage_(measure_mem_usage) {}
  90. // Sets |usage_before_|, |wall_before_|, and |cpu_before_| as results of
  91. // getrusage(), clock_gettime() for the wall time, and clock_gettime() for the
  92. // CPU time respectively. Note that this method erases all previous state of
  93. // |usage_before_|, |wall_before_|, |cpu_before_|.
  94. virtual void Start();
  95. // Sets |cpu_after_|, |wall_after_|, and |usage_after_| as results of
  96. // clock_gettime() for the wall time, and clock_gettime() for the CPU time,
  97. // getrusage() respectively. Note that this method erases all previous state
  98. // of |cpu_after_|, |wall_after_|, |usage_after_|.
  99. virtual void Stop();
  100. // If |report_stream_| is NULL, it does nothing. Otherwise, it prints the
  101. // resource utilization (i.e., CPU/WALL/USR/SYS time, RSS delta) between the
  102. // time of calling Timer::Start() and the time of calling Timer::Stop(). If we
  103. // cannot get a resource usage because of failures, it prints "Failed" instead
  104. // for the resource.
  105. void Report(const char* tag);
  106. // Returns the measured CPU Time (i.e., process time) for a range of code
  107. // execution. If kClockGettimeCPUtimeFailed is set by the failure of calling
  108. // clock_gettime(), it returns -1.
  109. virtual double CPUTime() {
  110. if (usage_status_ & kClockGettimeCPUtimeFailed) return -1;
  111. return TimeDifference(cpu_before_, cpu_after_);
  112. }
  113. // Returns the measured Wall Time (i.e., elapsed time) for a range of code
  114. // execution. If kClockGettimeWalltimeFailed is set by the failure of
  115. // calling clock_gettime(), it returns -1.
  116. virtual double WallTime() {
  117. if (usage_status_ & kClockGettimeWalltimeFailed) return -1;
  118. return TimeDifference(wall_before_, wall_after_);
  119. }
  120. // Returns the measured USR Time for a range of code execution. If
  121. // kGetrusageFailed is set because of the failure of calling getrusage(), it
  122. // returns -1.
  123. virtual double UserTime() {
  124. if (usage_status_ & kGetrusageFailed) return -1;
  125. return TimeDifference(usage_before_.ru_utime, usage_after_.ru_utime);
  126. }
  127. // Returns the measured SYS Time for a range of code execution. If
  128. // kGetrusageFailed is set because of the failure of calling getrusage(), it
  129. // returns -1.
  130. virtual double SystemTime() {
  131. if (usage_status_ & kGetrusageFailed) return -1;
  132. return TimeDifference(usage_before_.ru_stime, usage_after_.ru_stime);
  133. }
  134. // Returns the measured RSS delta for a range of code execution. If
  135. // kGetrusageFailed is set because of the failure of calling getrusage(), it
  136. // returns -1.
  137. virtual long RSS() const {
  138. if (usage_status_ & kGetrusageFailed) return -1;
  139. return usage_after_.ru_maxrss - usage_before_.ru_maxrss;
  140. }
  141. // Returns the measured the delta of the number of page faults for a range of
  142. // code execution. If kGetrusageFailed is set because of the failure of
  143. // calling getrusage(), it returns -1.
  144. virtual long PageFault() const {
  145. if (usage_status_ & kGetrusageFailed) return -1;
  146. return (usage_after_.ru_minflt - usage_before_.ru_minflt) +
  147. (usage_after_.ru_majflt - usage_before_.ru_majflt);
  148. }
  149. virtual ~Timer() {}
  150. private:
  151. // Returns the time gap between |from| and |to| in seconds.
  152. static double TimeDifference(const timeval& from, const timeval& to) {
  153. assert((to.tv_sec > from.tv_sec) ||
  154. (to.tv_sec == from.tv_sec && to.tv_usec >= from.tv_usec));
  155. return static_cast<double>(to.tv_sec - from.tv_sec) +
  156. static_cast<double>(to.tv_usec - from.tv_usec) * .000001;
  157. }
  158. // Returns the time gap between |from| and |to| in seconds.
  159. static double TimeDifference(const timespec& from, const timespec& to) {
  160. assert((to.tv_sec > from.tv_sec) ||
  161. (to.tv_sec == from.tv_sec && to.tv_nsec >= from.tv_nsec));
  162. return static_cast<double>(to.tv_sec - from.tv_sec) +
  163. static_cast<double>(to.tv_nsec - from.tv_nsec) * .000000001;
  164. }
  165. // Output stream to print out the resource utilization. If it is NULL,
  166. // Report() does nothing.
  167. std::ostream* report_stream_;
  168. // Status to stop measurement if a system call returns an error.
  169. unsigned usage_status_;
  170. // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
  171. // Timer::Start() is called. It is used as the base status of CPU time.
  172. timespec cpu_before_;
  173. // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
  174. // Timer::Start() is called. It is used as the base status of WALL time.
  175. timespec wall_before_;
  176. // Variable to save the result of getrusage() when Timer::Start() is called.
  177. // It is used as the base status of USR time, SYS time, and RSS.
  178. rusage usage_before_;
  179. // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
  180. // Timer::Stop() is called. It is used as the last status of CPU time. The
  181. // resouce usage is measured by subtracting |cpu_before_| from it.
  182. timespec cpu_after_;
  183. // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
  184. // Timer::Stop() is called. It is used as the last status of WALL time. The
  185. // resouce usage is measured by subtracting |wall_before_| from it.
  186. timespec wall_after_;
  187. // Variable to save the result of getrusage() when Timer::Stop() is called. It
  188. // is used as the last status of USR time, SYS time, and RSS. Those resouce
  189. // usages are measured by subtracting |usage_before_| from it.
  190. rusage usage_after_;
  191. // If true, Timer reports the memory usage information too. Otherwise, Timer
  192. // reports only USR time, WALL time, SYS time.
  193. bool measure_mem_usage_;
  194. };
  195. // The purpose of ScopedTimer is to measure the resource utilization for a
  196. // scope. Simply creating a local variable of ScopedTimer will call
  197. // Timer::Start() and it calls Timer::Stop() and Timer::Report() at the end of
  198. // the scope by its destructor. When we use this class, we must choose the
  199. // proper Timer class (for class TimerType template) in advance. This class
  200. // should be used as the following example:
  201. //
  202. // { // <-- beginning of this scope
  203. //
  204. // /* ... code out of interest ... */
  205. //
  206. // spvtools::utils::ScopedTimer<spvtools::utils::Timer>
  207. // scopedtimer(std::cout, tag);
  208. //
  209. // /* ... lines of code that we want to know its resource usage ... */
  210. //
  211. // } // <-- end of this scope. The destructor of ScopedTimer prints tag and
  212. // the resource utilization to std::cout.
  213. //
  214. // The template<class TimerType> is used to choose a Timer class. Currently,
  215. // only options for the Timer class are Timer and MockTimer in the unit test.
  216. template <class TimerType>
  217. class ScopedTimer {
  218. public:
  219. ScopedTimer(std::ostream* out, const char* tag,
  220. bool measure_mem_usage = false)
  221. : timer(new TimerType(out, measure_mem_usage)), tag_(tag) {
  222. timer->Start();
  223. }
  224. // At the end of the scope surrounding the instance of this class, this
  225. // destructor saves the last status of resource usage and reports it.
  226. virtual ~ScopedTimer() {
  227. timer->Stop();
  228. timer->Report(tag_);
  229. delete timer;
  230. }
  231. private:
  232. // Actual timer that measures the resource utilization. It must be an instance
  233. // of Timer class if there is no special reason to use other class.
  234. TimerType* timer;
  235. // A tag that will be printed in front of the trace reported by Timer class.
  236. const char* tag_;
  237. };
  238. // CumulativeTimer is the same as Timer class, but it supports a cumulative
  239. // measurement as the following example:
  240. //
  241. // CumulativeTimer *ctimer = new CumulativeTimer(std::cout);
  242. // ctimer->Start();
  243. //
  244. // /* ... lines of code that we want to know its resource usage ... */
  245. //
  246. // ctimer->Stop();
  247. //
  248. // /* ... code out of interest ... */
  249. //
  250. // ctimer->Start();
  251. //
  252. // /* ... lines of code that we want to know its resource usage ... */
  253. //
  254. // ctimer->Stop();
  255. // ctimer->Report(tag);
  256. // delete ctimer;
  257. //
  258. class CumulativeTimer : public Timer {
  259. public:
  260. CumulativeTimer(std::ostream* out, bool measure_mem_usage = false)
  261. : Timer(out, measure_mem_usage),
  262. cpu_time_(0),
  263. wall_time_(0),
  264. usr_time_(0),
  265. sys_time_(0),
  266. rss_(0),
  267. pgfaults_(0) {}
  268. // If we cannot get a resource usage because of failures, it sets -1 for the
  269. // resource usage.
  270. void Stop() override {
  271. Timer::Stop();
  272. if (cpu_time_ >= 0 && Timer::CPUTime() >= 0)
  273. cpu_time_ += Timer::CPUTime();
  274. else
  275. cpu_time_ = -1;
  276. if (wall_time_ >= 0 && Timer::WallTime() >= 0)
  277. wall_time_ += Timer::WallTime();
  278. else
  279. wall_time_ = -1;
  280. if (usr_time_ >= 0 && Timer::UserTime() >= 0)
  281. usr_time_ += Timer::UserTime();
  282. else
  283. usr_time_ = -1;
  284. if (sys_time_ >= 0 && Timer::SystemTime() >= 0)
  285. sys_time_ += Timer::SystemTime();
  286. else
  287. sys_time_ = -1;
  288. if (rss_ >= 0 && Timer::RSS() >= 0)
  289. rss_ += Timer::RSS();
  290. else
  291. rss_ = -1;
  292. if (pgfaults_ >= 0 && Timer::PageFault() >= 0)
  293. pgfaults_ += Timer::PageFault();
  294. else
  295. pgfaults_ = -1;
  296. }
  297. // Returns the cumulative CPU Time (i.e., process time) for a range of code
  298. // execution.
  299. double CPUTime() override { return cpu_time_; }
  300. // Returns the cumulative Wall Time (i.e., elapsed time) for a range of code
  301. // execution.
  302. double WallTime() override { return wall_time_; }
  303. // Returns the cumulative USR Time for a range of code execution.
  304. double UserTime() override { return usr_time_; }
  305. // Returns the cumulative SYS Time for a range of code execution.
  306. double SystemTime() override { return sys_time_; }
  307. // Returns the cumulative RSS delta for a range of code execution.
  308. long RSS() const override { return rss_; }
  309. // Returns the cumulative delta of number of page faults for a range of code
  310. // execution.
  311. long PageFault() const override { return pgfaults_; }
  312. private:
  313. // Variable to save the cumulative CPU time (i.e., process time).
  314. double cpu_time_;
  315. // Variable to save the cumulative wall time (i.e., elapsed time).
  316. double wall_time_;
  317. // Variable to save the cumulative user time.
  318. double usr_time_;
  319. // Variable to save the cumulative system time.
  320. double sys_time_;
  321. // Variable to save the cumulative RSS delta.
  322. long rss_;
  323. // Variable to save the cumulative delta of the number of page faults.
  324. long pgfaults_;
  325. };
  326. } // namespace utils
  327. } // namespace spvtools
  328. #else // defined(SPIRV_TIMER_ENABLED)
  329. #define SPIRV_TIMER_DESCRIPTION(...)
  330. #define SPIRV_TIMER_SCOPED(...)
  331. #endif // defined(SPIRV_TIMER_ENABLED)
  332. #endif // SOURCE_UTIL_TIMER_H_