//! To compile code including this header file, you'll need to links it //! against librt. On GCC, use: g++ -lrt main.cpp -o main #ifndef CHRONO_HPP_ #define CHRONO_HPP_ #include <stdexcept> #include <time.h> namespace benchmark { namespace details { //! \brief Substarct two timespec structures. //! \param t1 The first time point. //! \param t2 The second time point. //! \return The difference between the two timespec structures. timespec tdiff(const timespec& t1, const timespec& t2) { timespec result; // The tv_sec member corresponds to a number of seconds while tv_nsec // member corresponds to the number of nanoseconds expired in the // current second. if ((t2.tv_nsec - t1.tv_nsec) < 0 /* ns */) { result.tv_sec = t2.tv_sec - t1.tv_sec - 1; result.tv_nsec = 1000000000 /* ns */ + t2.tv_nsec - t1.tv_nsec; } else { result.tv_sec = t2.tv_sec - t1.tv_sec; result.tv_nsec = t2.tv_nsec - t1.tv_nsec; } return result; } //! \brief Add two timespec structures. //! \param t1 The first time point. //! \param t2 The second time point. //! \return The difference between the two timespec structures. timespec tadd(const timespec& t1, const timespec& t2) { timespec result; // The tv_sec member corresponds to a number of seconds while tv_nsec // member corresponds to the number of nanoseconds expired in the // current second. if ((t1.tv_nsec + t2.tv_nsec) > 1000000000 /* ns */) { result.tv_sec = t1.tv_sec + t2.tv_sec + 1; result.tv_nsec = t1.tv_nsec + t2.tv_nsec - 1000000000 /* ns */; } else { result.tv_sec = t1.tv_sec + t2.tv_sec; result.tv_nsec = t1.tv_nsec + t2.tv_nsec; } return result; } } // namespace details //! \brief Chronometer's clock specifier. struct Clock { enum Type { Thread, Process, }; }; //! \brief Wrapper around the clock_gettime function. class Chronometer { private: timespec _start; /**< Chronometer start time, relative to process start. */ timespec _total; /**< Total chronometer running time. */ int _clock_id; /**< Chronometer underlying clock (thread or process). */ bool _stopped; /**< Set to false on chronometer start. */ public: //! \brief Default chronometer's constructor. //! //! Build a process based chronometer. Chronometer(): _stopped(true), _clock_id(CLOCK_PROCESS_CPUTIME_ID) { _total.tv_sec = 0; _total.tv_nsec = 0; } //! \brief Chronometer's constructor. //! \param clock The clock type used by the chronometer. //! //! Build a chronometer, specifying the underlying clock. Chronometer(Clock::Type clock): _stopped(true) { if (clock == Clock::Thread) { _clock_id = CLOCK_THREAD_CPUTIME_ID; } else { _clock_id = CLOCK_PROCESS_CPUTIME_ID; } _total.tv_sec = 0; _total.tv_nsec = 0; } //! \brief Start chronometer. void start() throw(std::runtime_error) { if (_stopped) { if (clock_gettime(_clock_id, &_start) != 0) { throw std::runtime_error("Error while retrieving clock value."); } _stopped = false; } } //! \brief Stop chronometer. //! \post The elapsed process or thread time since last call to //! the start method is added to the current chronometer's time. void stop() throw(std::runtime_error) { if (!_stopped) { timespec _stop; if (clock_gettime(_clock_id, &_stop) != 0) { throw std::runtime_error("Error while retrieving clock value."); } timespec diff = details::tdiff(_start, _stop); _total = details::tadd(_total, diff); _stopped = true; } } //! \brief Reset chronometer's time. void reset() { _stopped = true; _total.tv_nsec = 0; _total.tv_sec = 0; } //! \brief Retrieve chronometer's second count. //! \return The chronometer's second count. long int nsec() const throw (std::logic_error) { if (!_stopped) { throw std::logic_error("Can't retrieve " "time while chronometer is running."); } return _total.tv_nsec; } //! \brief Retrieve chronometer's nanosecond count. //! \return The chronometer's nanosecond count. long int sec() const throw (std::logic_error) { if (!_stopped) { throw std::logic_error("Can't retrieve " "time while chronometer is running."); } return _total.tv_sec; } }; } // namespace benchmark #endif /* CHRONO_HPP_ */