source: ThirdParty/CodePatterns/src/Helpers/Chronos.cpp@ 7516f6

Action_Thermostats Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.1 ChemicalSpaceEvaluator Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Exclude_Hydrogens_annealWithBondGraph Fix_Verbose_Codepatterns ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion Gui_displays_atomic_force_velocity JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool PythonUI_with_named_parameters Recreated_GuiChecks StoppableMakroAction TremoloParser_IncreasedPrecision
Last change on this file since 7516f6 was 9a9f847, checked in by Frederik Heber <frederik.heber@…>, 8 years ago

Chronos can now be safely used in multithread environements.

  • this fixes a bug with JobMarket where JobMarketPoolWorker would crash because handle_ReceiveJobs and Work would both try to access Chronos.
  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * Chronos.cpp
10 *
11 * Created on: Mar 14, 2011
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20//#include "CodePatterns/MemDebug.hpp"
21
22#include <iostream>
23
24#include <boost/thread/locks.hpp>
25
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#ifdef HAVE_SYS_TIMES_H
29# include <sys/times.h>
30#else
31# include <time.h>
32#endif
33#else
34# include <time.h>
35#endif
36
37#include "CodePatterns/Chronos.hpp"
38
39#include "CodePatterns/Singleton_impl.hpp"
40
41Chronos::Chronos()
42{
43 // get time and store it internally as base time
44#ifdef HAVE_TIME_H
45 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &basetime);
46#else
47#ifdef HAVE_SYS_TIME_H
48 struct timezone timezone1;
49 gettimeofday(&basetime, &timezone1);
50#else
51#ifdef HAVE_SYS_TIMES_H
52 struct tms *basetime = new tms;
53 times(basetime);
54#endif
55#endif
56#endif
57}
58
59Chronos::~Chronos()
60{
61#ifndef HAVE_TIME_H
62#ifndef HAVE_SYS_TIME_H
63#ifdef HAVE_SYS_TIMES_H
64 delete basetime;
65#endif
66#endif
67#endif
68}
69
70double Chronos::getTime(const std::string &_name) const
71{
72 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
73 // only those functions have a time that have run already
74 if (AccountedTime.count(_name) != 0) {
75 // return -1 if function is currently running
76 if (StartingTime.count(_name) == 0.)
77 return AccountedTime.at(_name);
78 else
79 return -1.;
80 }
81 return 0.;
82}
83
84void Chronos::resetTime(const std::string &_name)
85{
86 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
87 // set accounted time to zero
88 if (AccountedTime.count(_name) != 0) {
89 AccountedTime[_name] = 0.;
90 }
91 // and end if it's currently running
92 StartingTime.erase(_name);
93 RecursionMap.erase(_name);
94}
95
96void Chronos::startTiming(const std::string &_name)
97{
98 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
99 // start time keeping
100 if ((RecursionMap.count(_name) == 0) || (RecursionMap[_name] == 0)) {
101 StartingTime[_name] = getCurrentTime();
102 RecursionMap[_name] = 1;
103 } else {
104 ++RecursionMap[_name];
105 }
106}
107
108double Chronos::calculateCorrectTimeDifference(
109 const sec_ncsec_t &_time1,
110 const sec_ncsec_t &_time2)
111{
112 double currenttime = 0.;
113 if (_time1.second < _time2.second)
114 currenttime = (_time1.first - _time2.first - 1)
115 + (1e9 + _time1.second - _time2.second) * 1.e-9;
116 else
117 currenttime = (_time1.first - _time2.first)
118 + (_time1.second - _time2.second) * 1.e-9;
119 return currenttime;
120}
121
122double Chronos::getCurrentTime() const
123{
124 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
125#ifdef HAVE_TIME_H
126 // clock_gettime gives nanoseconds accuracy
127 timespec time1;
128 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
129 double currenttime = calculateCorrectTimeDifference(
130 std::make_pair( time1.tv_sec, time1.tv_nsec),
131 std::make_pair( basetime.tv_sec, basetime.tv_nsec)
132 );
133#else
134#ifdef HAVE_SYS_TIME_H
135 struct timezone timezone1;
136 timeval time1;
137 // gettimeofday gives microseconds accuracy
138 gettimeofday(&time1, &timezone1);
139 double currenttime = calculateCorrectTimeDifference(
140 std::make_pair( time1.tv_sec, time1.tv_usec),
141 std::make_pair( basetime.tv_sec, basetime.tv_usec)
142 );
143#else
144#ifdef HAVE_SYS_TIMES_H
145 // clock is only accurate up to milliseconds
146 struct tms *buffer = new tms;
147 if (times(buffer) != (clock_t)(-1))
148 currenttime =
149 (double)(buffer->tms_utime - basetime->tms_utime)/(double)sysconf(_SC_CLK_TCK);
150 else
151 currenttime = 0.;
152 delete buffer;
153#else
154 // no time keeping possible
155 const double currenttime = 0.;
156#endif
157#endif
158#endif
159 //std::cout << "Current time is " << currenttime << std::endl;
160 return currenttime;
161}
162
163void Chronos::endTiming(const std::string &_name)
164{
165 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
166 // check whether we are the topmost function, return if not
167 if (--RecursionMap[_name] != 0)
168 return;
169
170 // if present
171 ASSERT(StartingTime.count(_name), "Chronos::endTiming() - no timer under "
172 +_name+" running.");
173 ASSERT(RecursionMap.count(_name), "Chronos::endTiming() - negative recursion level for "
174 +_name+".");
175
176 // finish time keeping
177 const double endtime = getCurrentTime();
178 const double starttime = StartingTime[_name];
179 const double RunTime = ((double)endtime - starttime);
180 if (AccountedTime.count(_name) != 0)
181 AccountedTime[_name] += RunTime;
182 else
183 AccountedTime[_name] = RunTime;
184
185 // and zero for next run
186 StartingTime.erase(_name);
187}
188
189double Chronos::SumUpTotalTime() const
190{
191 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
192 double sum = 0.;
193 for (TimekeepingMap::const_iterator iter = AccountedTime.begin();
194 iter != AccountedTime.end();
195 ++iter) {
196 sum += iter->second;
197 }
198 return sum;
199}
200
201size_t Chronos::SumUpTotalFunctions() const
202{
203 boost::recursive_mutex::scoped_lock lock(ChronosMutex);
204 return AccountedTime.size();
205}
206
207std::ostream& operator<<(std::ostream &ost, const Chronos &_time)
208{
209 boost::recursive_mutex::scoped_lock lock(_time.ChronosMutex);
210 ost << "List of functions present:" << std::endl;
211 for (Chronos::TimekeepingMap::const_iterator iter = _time.AccountedTime.begin();
212 iter != _time.AccountedTime.end();
213 ++iter)
214 ost << "\t" << iter->first << "\t" << iter->second << "s" << std::endl;
215 ost << "Total time passed: " << _time.SumUpTotalTime() << std::endl;
216 ost << "Total functions: " << _time.SumUpTotalFunctions() << std::endl;
217 return ost;
218}
219
220// construct the remainder of the singleton
221CONSTRUCT_SINGLETON(Chronos)
222
223// catch if someone wants to use Info objects in here
224#ifdef INFO_HPP_
225BOOST_PP_ASSERT_MSG(1,\
226 ERROR: This is a safety measure to generate a compiler warning\n \
227 if you really try to use info.hpp in __FILE__.)
228#endif
229
Note: See TracBrowser for help on using the repository browser.