/* Copyright (C) 2014 InfiniDB, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /****************************************************************************** * $Id: timeset.h 9655 2013-06-25 23:08:13Z xlou $ * *****************************************************************************/ /** @file timeset.h * Used to maintain collection of timers tracking elapsed times for set of tasks */ #pragma once #include #include #include #include namespace joblist { //------------------------------------------------------------------------------ /** @brief Maintains a group of simulated timers and their elapsed times. * * This class maintains a collection of timers that can be used to collect * statistics about the cumulative elapsed time spent on selected tasks. */ //------------------------------------------------------------------------------ class TimeSet { // TimerMap maps a timer to its start time // ElapsedMap maps a timer to its cumulative elapsed time typedef std::map TimerMap; typedef std::map ElapsedMap; public: TimeSet() : fTimer(), fElapsed() { } void displayAll() const; void display(const std::string& key) const; double totalTime() const; double totalTime(const std::string& key) const; void holdTimer(const std::string& key); void startTimer(const std::string& key); void stopTimer(const std::string& key); void setTimer(const std::string& key, bool start = true); TimeSet& operator+=(const TimeSet& rhs); void clear() { fTimer.clear(); fElapsed.clear(); } private: void timespec_sub(const struct timespec& tv1, // start time const struct timespec& tv2, // end time struct timespec& diff) const; void timespec_add(const struct timespec& tv1, const struct timespec& tv2, struct timespec& sum) const; TimerMap fTimer; ElapsedMap fElapsed; }; //------------------------------------------------------------------------------ // Print the contents (to std::cout) of all timers in the ElapsedMap map. //------------------------------------------------------------------------------ inline void TimeSet::displayAll() const { ElapsedMap::const_iterator itend = fElapsed.end(); for (ElapsedMap::const_iterator it = fElapsed.begin(); it != itend; ++it) { double t; t = (double)it->second.tv_sec + (double)it->second.tv_nsec / 1000000000.0; std::cout << "TimeSet " << it->first << ": " << t << "s\n"; } std::cout.flush(); } //------------------------------------------------------------------------------ // Print the specified timer to std::cout. // If specified timer is in the ElapsedMap map, then the contents of that // timer will be printed, else if the specified timer is in the TimerMap map, // then the contents of that timer will be printed. // key (in) - string that identifies the timer to be printed. //------------------------------------------------------------------------------ inline void TimeSet::display(const std::string& key) const { ElapsedMap::const_iterator em = fElapsed.find(key); if (fElapsed.end() != em) { double t; t = (double)em->second.tv_sec + (double)em->second.tv_nsec / 1000000000.0; std::cout << "TimeSet elapse " << em->first << ": " << t << "s\n"; } else { TimerMap::const_iterator tm = fTimer.find(key); if (fTimer.end() != tm) { double t; t = (double)tm->second.tv_sec + (double)tm->second.tv_nsec / 1000000000.0; std::cout << "TimeSet start " << tm->first << ": " << t << "s\n"; } } std::cout.flush(); } //------------------------------------------------------------------------------ // Return sum of all timer elapsed times. //------------------------------------------------------------------------------ inline double TimeSet::totalTime() const { struct timespec tSum = {0, 0}; ElapsedMap::const_iterator itend = fElapsed.end(); for (ElapsedMap::const_iterator it = fElapsed.begin(); it != itend; ++it) { } double totSeconds; totSeconds = (double)tSum.tv_sec + (double)tSum.tv_nsec / 1000000000.0; return totSeconds; } //------------------------------------------------------------------------------ // Return current elapsed time for the specified timer. // key (in) - string that identifies the timer of interest. //------------------------------------------------------------------------------ inline double TimeSet::totalTime(const std::string& key) const { ElapsedMap::const_iterator el = fElapsed.find(key); if (fElapsed.end() != el) { double totSeconds; totSeconds = (double)el->second.tv_sec + (double)el->second.tv_nsec / 1000000000.0; return totSeconds; } else { return 0; } } //------------------------------------------------------------------------------ // "Hold" the specified timer. // Elapsed time is recorded, and added to total elapsed time. // Unlike stopTimer(), the start time is not reset to current time; instead // startTimer() or setTimer() must be called by the application code when it // is time to reset the start time and effectively resume or restart the timer. // key (in) - string that identifies the timer to be "held". //------------------------------------------------------------------------------ inline void TimeSet::holdTimer(const std::string& key) { TimerMap::iterator it = fTimer.find(key); if (fTimer.end() != it) { struct timespec tEnd; struct timespec tDiff; #if defined(CLOCK_REALTIME) clock_gettime(CLOCK_REALTIME, &tEnd); #else tEnd.tv_sec = tEnd.tv_nsec = 0; #endif timespec_sub(it->second, tEnd, tDiff); struct timespec tElapsed = fElapsed[key]; timespec_add(tElapsed, tDiff, fElapsed[key]); } } //------------------------------------------------------------------------------ // Start the specified timer. // Start time is set to current time. // key (in) - string that identifies the timer to be started. //------------------------------------------------------------------------------ inline void TimeSet::startTimer(const std::string& key) { struct timespec ts; #if defined(CLOCK_REALTIME) clock_gettime(CLOCK_REALTIME, &ts); #else ts.tv_sec = ts.tv_nsec = 0; #endif fTimer[key] = ts; } //------------------------------------------------------------------------------ // Stop the specified timer. // Elapsed time is recorded, and start time is set to current time. // key (in) - string that identifies the timer to be stopped. //------------------------------------------------------------------------------ inline void TimeSet::stopTimer(const std::string& key) { TimerMap::iterator it = fTimer.find(key); if (fTimer.end() != it) { struct timespec tEnd; struct timespec tDiff; #if defined(CLOCK_REALTIME) clock_gettime(CLOCK_REALTIME, &tEnd); #else tEnd.tv_sec = tEnd.tv_nsec = 0; #endif timespec_sub(it->second, tEnd, tDiff); fElapsed[key] = tDiff; fTimer[key] = tEnd; } } //------------------------------------------------------------------------------ // Start or stop the specified timer. // key (in) - string that identifies the timer to be started or stopped. // start (in) - boolean indicating whether to start or stop the timer. //------------------------------------------------------------------------------ inline void TimeSet::setTimer(const std::string& key, bool start /*= true*/) { if (start) startTimer(key); else stopTimer(key); } //------------------------------------------------------------------------------ // Adds the specified TimeSet elapsed times to "this" TimeSet. // rhs (in) - TimeSet with elapsed times to be added to "this" TimeSet. //------------------------------------------------------------------------------ inline TimeSet& TimeSet::operator+=(const TimeSet& rhs) { ElapsedMap::const_iterator itend = rhs.fElapsed.end(); for (ElapsedMap::const_iterator it = rhs.fElapsed.begin(); it != itend; ++it) { struct timespec tLhs = fElapsed[it->first]; timespec_add(tLhs, it->second, fElapsed[it->first]); } return (*this); } //------------------------------------------------------------------------------ // Takes the difference between 2 timespec values. // tv1 (in) - first timespec value (subtracted from tv2) // tv2 (in) - second timespec value // diff (out) - value of tv2 - tv1 //------------------------------------------------------------------------------ inline void TimeSet::timespec_sub(const struct timespec& tv1, // start time const struct timespec& tv2, // end time struct timespec& diff) const { if (tv2.tv_nsec < tv1.tv_nsec) { diff.tv_sec = tv2.tv_sec - tv1.tv_sec - 1; diff.tv_nsec = tv2.tv_nsec + 1000000000 - tv1.tv_nsec; } else { diff.tv_sec = tv2.tv_sec - tv1.tv_sec; diff.tv_nsec = tv2.tv_nsec - tv1.tv_nsec; } } //------------------------------------------------------------------------------ // Add 2 timespec values. // tv1 (in) - first timespec value // tv2 (in) - second timespec value // sum (out) - sum of tv1 and tv2 //------------------------------------------------------------------------------ inline void TimeSet::timespec_add(const struct timespec& tv1, // start time const struct timespec& tv2, // end time struct timespec& sum) const { sum.tv_sec = tv1.tv_sec + tv2.tv_sec; sum.tv_nsec = tv1.tv_nsec + tv2.tv_nsec; if (sum.tv_nsec >= 1000000000) { sum.tv_sec += 1; sum.tv_nsec -= 1000000000; } } }; // namespace joblist