JeVois  1.3
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Timer.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 #include <jevois/Debug/Timer.H>
19 #include <jevois/Debug/Log.H>
20 #include <sstream>
21 #include <iomanip>
22 #include <fstream>
23 
24 #define _BSD_SOURCE /* See feature_test_macros(7) */
25 #include <stdlib.h> // for getloadavg()
26 
27 namespace
28 {
29  void secs2str(std::ostringstream & ss, double secs)
30  {
31  if (secs < 1.0e-6) ss << secs * 1.0e9 << "ns";
32  else if (secs < 1.0e-3) ss << secs * 1.0e6 << "us";
33  else if (secs < 1.0) ss << secs * 1.0e3 << "ms";
34  else ss << secs << 's';
35  }
36 }
37 
38 // ####################################################################################################
39 jevois::Timer::Timer(char const * prefix, size_t interval, int loglevel) :
40  itsPrefix(prefix), itsInterval(interval), itsLogLevel(loglevel), itsCount(0),
41  itsStartTime(std::chrono::high_resolution_clock::now()), itsSecs(0.0),
42  itsMinSecs(1.0e30), itsMaxSecs(-1.0e30), itsStr("-- fps, --% CPU"),
43  itsStartTimeForCpu(std::chrono::high_resolution_clock::now())
44 {
45  if (interval == 0) LFATAL("Interval must be > 0");
46  getrusage(RUSAGE_SELF, &itsStartRusage);
47 }
48 
49 // ####################################################################################################
51 {
52  itsStartTime = std::chrono::high_resolution_clock::now();
53  if (itsCount == 0) { getrusage(RUSAGE_SELF, &itsStartRusage); itsStartTimeForCpu = itsStartTime; }
54 }
55 
56 // ####################################################################################################
57 std::string const & jevois::Timer::stop()
58 {
59  std::chrono::duration<double> const dur = std::chrono::high_resolution_clock::now() - itsStartTime;
60  double secs = dur.count();
61 
62  // Update average duration computation:
63  itsSecs += secs; ++itsCount;
64 
65  // Update min and max:
66  if (secs < itsMinSecs) itsMinSecs = secs;
67  if (secs > itsMaxSecs) itsMaxSecs = secs;
68 
69  if (itsCount >= itsInterval)
70  {
71  double avgsecs = itsSecs / itsInterval;
72  std::ostringstream ss;
73  ss << itsPrefix << " average (" << itsInterval << ") duration "; secs2str(ss, avgsecs);
74  ss << " ["; secs2str(ss, itsMinSecs); ss << " .. "; secs2str(ss, itsMaxSecs); ss<< ']';
75 
76  float fps = 0.0F;
77  if (avgsecs > 0.0) { fps = 1.0F / float(avgsecs); ss << " (" << fps << " fps)"; }
78 
79  switch (itsLogLevel)
80  {
81  case LOG_INFO: LINFO(ss.str()); break;
82  case LOG_ERR: LERROR(ss.str()); break;
83  case LOG_CRIT: LFATAL(ss.str()); break;
84  default: LDEBUG(ss.str());
85  }
86 
87  // Compute percent CPU used: since often we only run a chunk of code between start() and stop() that we want to
88  // evaluate, we cannot use itsSecs is as a denominator, we need the total elapsed time since the first call to
89  // start() over the current interval, hence our use of itsStartTimeForCpu here. Hence, note that the CPU load
90  // reported is for the whole process that is running, not just for the critical chunk of code that is executed
91  // between start() and stop(). Indeed the goal is to get an idea of the overall machine utilization:
92  rusage stoprusage; getrusage(RUSAGE_SELF, &stoprusage);
93 
94  double const user_secs = double(stoprusage.ru_utime.tv_sec) - double(itsStartRusage.ru_utime.tv_sec) +
95  (double(stoprusage.ru_utime.tv_usec) - double(itsStartRusage.ru_utime.tv_usec)) / 1000000.0;
96 
97  std::chrono::duration<double> const cpudur = std::chrono::high_resolution_clock::now() - itsStartTimeForCpu;
98 
99  double const cpu = 100.0 * user_secs / cpudur.count();
100 
101  // Get the CPU temperature:
102  int temp = 30;
103  std::ifstream ifs("/sys/class/thermal/thermal_zone0/temp");
104  if (ifs.is_open()) { std::string t; std::getline(ifs, t); temp = std::stoi(t); ifs.close(); }
105 
106  // Most hosts report milli-degrees, platform reports straight degrees:
107 #ifndef JEVOIS_PLATFORM
108  temp /= 1000;
109 #endif
110 
111  // Finally get the CPU frequency:
112  int freq = 1344;
113  std::ifstream ifs2("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq");
114  if (ifs2.is_open()) { std::string f; std::getline(ifs2, f); freq = std::stoi(f) / 1000; ifs2.close(); }
115 
116  // Ready to return all that info:
117  std::ostringstream os; os << std::fixed << std::setprecision(1) << fps << " fps, " << cpu << "% CPU, "
118  << temp << "C, " << freq << " MHz";
119  itsStr = os.str();
120 
121  // Get ready for the next cycle:
122  itsSecs = 0.0; itsMinSecs = 1.0e30; itsMaxSecs = -1.0e30; itsCount = 0;
123  }
124 
125  return itsStr;
126 }
127 
128 
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level. ...
Definition: Log.H:155
void start()
Start a time measurement period.
Definition: Timer.C:50
STL namespace.
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level. ...
Definition: Log.H:193
Timer(char const *prefix, size_t interval=100, int loglevel=LOG_INFO)
Constructor.
Definition: Timer.C:39
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level. ...
Definition: Log.H:212
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition: Log.H:176
std::string const & stop()
End a time measurement period, report time spent if reporting interval is reached.
Definition: Timer.C:57