1 /**
2  **   Copyright (C) 2006 – 2018 by Diether Knof
3  **
4  **   This program is free software; you can redistribute it and/or
5  **   modify it under the terms of the GNU General Public License as
6  **   published by the Free Software Foundation; either version 2 of
7  **   the License, or (at your option) any later version.
8  **
9  **   This program 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  **   You can find this license in the file 'gpl.txt'.
14  **
15  **   You should have received a copy of the GNU General Public License
16  **   along with this program; if not, write to the Free Software
17  **   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  **   MA  02111-1307  USA
19  **
20  **  Contact:
21  **    Diether Knof dknof@posteo.de
22  **/
23 
24 #include "stop_watch.h"
25 
26 #include <iostream>
27 using namespace std;
28 
29 /** constructor
30  ** starts the stop watch
31  **/
StartStopProxy(StopWatch & stop_watch)32 StopWatch::StartStopProxy::StartStopProxy(StopWatch& stop_watch) :
33   stop_watch(&stop_watch)
34 { this->stop_watch->start(); }
35 
36 /** destructor
37  ** stops the stop watch
38  **/
~StartStopProxy()39 StopWatch::StartStopProxy::~StartStopProxy()
40 { this->stop_watch->stop(); }
41 
42 /** -> result
43  **
44  ** @param    start_time   start time
45  **
46  ** @return   difference from 'start_time' to 'now'
47  **            '0' on error
48  **/
49 MSecCounter
diff_to_now(clock_t const start_time)50 StopWatch::diff_to_now(clock_t const start_time) {
51   clock_t const stop_time = clock();
52   if (stop_time == static_cast<clock_t>(-1)) {
53     cerr << "StopWatch::diff_to_now()\n"
54       << "  could not get time"
55       << endl;
56     return 0;
57   }
58 
59   if (start_time > stop_time) {
60     cerr << "StopWatch::diff_to_now()\n"
61       << "  overflow: "
62       << "start time = " << start_time
63       << " > " << stop_time << " = stop time"
64       << endl;
65     return 0;
66   }
67 
68   // under Microsoft Windows 'CLOCKS_PER_SEC' is 1000,
69   // under GNU/Linux (Posix) 1000000,
70   // under FreeBSD < 1000
71   // So in order to do integer calculation we have to split the code
72 
73   // The variable is needed because 'CLOCKS_PER_SEC' need not to be a
74   // constant (so no '#if CLOCKS_PER_SEC < 1000' can be used).
75   // But with a constant in FreeBSD 'CLOCKS_PER_SEC / 1000' equals 0,
76   // this leads to the warning division with zero (g++-3.4.4).
77   clock_t clocks_per_sec = CLOCKS_PER_SEC;
78   if (clocks_per_sec < 1000) {
79     return ((stop_time - start_time) * (1000 / clocks_per_sec));
80   } else {
81     return ((stop_time - start_time) / (clocks_per_sec / 1000));
82   }
83 } // static MSecCounter StopWatch::diff_to_now(clock_t start_time)
84 
85 
86 /** constructor
87  **/
StopWatch()88 StopWatch::StopWatch() :
89   start_time(static_cast<clock_t>(-1))
90 { }
91 
92 /** destructor
93  **/
~StopWatch()94 StopWatch::~StopWatch()
95 {
96 #ifdef DKNOF
97   if (this->depth > 0) {
98     cerr << "StopWatch::~StopWatch()\n"
99       << "  depth is not 0: " << this->depth
100       << endl;
101 #ifndef RELEASE
102     abort();
103 #endif
104   }
105 #endif
106 } // StopWatch::~StopWatch()
107 
108 /** @return   a start stop proxy
109  **/
110 std::unique_ptr<StopWatch::StartStopProxy>
start_stop_proxy()111 StopWatch::start_stop_proxy()
112 { return std::make_unique<StartStopProxy>(*this); }
113 
114 /** start the time counter
115  **/
116 void
start()117 StopWatch::start()
118 {
119   if (this->depth == 0)
120     this->start_time = clock();
121 
122   if (this->start_time == static_cast<clock_t>(-1)) {
123     cerr << "StopWatch::start()\n"
124       << "  clock could not be started"
125       << endl;
126     return ;
127   }
128 
129   this->depth += 1;
130   this->calls_ += 1;
131 } // void StopWatch::start()
132 
133 /** stop the time counter
134  **/
135 void
stop()136 StopWatch::stop()
137 {
138   if (   (this->start_time == static_cast<clock_t>(-1))
139       || (this->depth == 0) ) {
140 #ifdef DKNOF
141     cerr << "StopWatch::stop()\n"
142       << "clock not started"
143       << endl;
144 #ifndef RELEASE
145     //  (*reinterpret_cast<int*>(NULL) = 0);
146 #endif
147 #endif
148     return ;
149   }
150 
151   this->depth -= 1;
152 
153   if (this->depth == 0) {
154     this->msec_ += StopWatch::diff_to_now(this->start_time);
155 
156     this->start_time = static_cast<clock_t>(-1);
157   }
158 } // void StopWatch::stop()
159 
160 /** reset the counter
161  **/
162 void
reset()163 StopWatch::reset()
164 {
165   this->start_time = static_cast<clock_t>(-1);
166   this->msec_ = 0;
167   this->depth = 0;
168 } // void StopWatch::reset()
169 
170 /** @return   whether the stop watch is running
171  **/
172 bool
running() const173 StopWatch::running() const
174 {
175   return (this->start_time != static_cast<clock_t>(-1));
176 } // bool StopWatch::running() const
177 
178 /** @return   the stopped time in miliseconds
179  **/
180 MSecCounter
msec() const181 StopWatch::msec() const
182 {
183   if (this->start_time != static_cast<clock_t>(-1))
184     return this->msec_ + StopWatch::diff_to_now(this->start_time);
185   else
186     return this->msec_;
187 } // MSecCounter StopWatch::msec() const
188 
189 /** @return   how many calls (of start) has been made
190  **/
191 int
calls() const192 StopWatch::calls() const
193 {
194   return this->calls_;
195 } // int StopWatch::calls() const
196