diff --git a/SConstruct b/SConstruct index 18ebea2af..6127113b6 100755 --- a/SConstruct +++ b/SConstruct @@ -703,6 +703,13 @@ if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'): print ' Please install zlib and try again.' Exit(1) +# Check for librt. +have_posix_clock = conf.CheckLib(None, 'clock_nanosleep', 'time.h') or \ + conf.CheckLib('rt', 'clock_nanosleep', 'time.h') + +if not have_posix_clock: + print "Can't find library for POSIX clocks." + # Check for (C99 FP environment control) have_fenv = conf.CheckHeader('fenv.h', '<>') if not have_fenv: @@ -819,6 +826,7 @@ sticky_vars.AddVariables( 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', False), BoolVariable('USE_MYSQL', 'Use MySQL for stats output', have_mysql), + BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock), BoolVariable('USE_FENV', 'Use IEEE mode control', have_fenv), BoolVariable('USE_CHECKER', 'Use checker for detailed CPU models', False), BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False), @@ -828,7 +836,8 @@ sticky_vars.AddVariables( # These variables get exported to #defines in config/*.hh (see src/SConscript). export_vars += ['FULL_SYSTEM', 'USE_FENV', 'USE_MYSQL', 'NO_FAST_ALLOC', 'FAST_ALLOC_DEBUG', 'FAST_ALLOC_STATS', - 'SS_COMPATIBLE_FP', 'USE_CHECKER', 'TARGET_ISA', 'CP_ANNOTATE'] + 'SS_COMPATIBLE_FP', 'USE_CHECKER', 'TARGET_ISA', 'CP_ANNOTATE', + 'USE_POSIX_CLOCK' ] ################################################### # diff --git a/src/base/time.cc b/src/base/time.cc index a1732773e..b9bbb0830 100644 --- a/src/base/time.cc +++ b/src/base/time.cc @@ -28,85 +28,35 @@ * Authors: Nathan Binkert */ -#include -#include -#include #include -#include +#include #include "base/time.hh" +#include "config/use_posix_clock.hh" using namespace std; -struct _timeval +void +Time::_set(bool monotonic) { +#if USE_POSIX_CLOCK + ::clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &_time); +#else timeval tv; -}; - -double -convert(const timeval &tv) -{ - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} - -Time::Time(bool set_now) -{ - time = new _timeval; - if (set_now) - set(); -} - -Time::Time(const timeval &val) -{ - time = new _timeval; - set(val); -} - -Time::Time(const Time &val) -{ - time = new _timeval; - set(val.get()); -} - -Time::~Time() -{ - delete time; -} - -const timeval & -Time::get() const -{ - return time->tv; -} - -void -Time::set() -{ - ::gettimeofday(&time->tv, NULL); -} - -void -Time::set(const timeval &tv) -{ - memcpy(&time->tv, &tv, sizeof(timeval)); -} - -double -Time::operator()() const -{ - return convert(get()); + ::gettimeofday(&tv, NULL); + operator=(tv); +#endif } string -Time::date(string format) const +Time::date(const string &format) const { - const timeval &tv = get(); - time_t sec = tv.tv_sec; + time_t sec = this->sec(); char buf[256]; if (format.empty()) { #ifdef __SUNPRO_CC - ctime_r(&sec, buf, 256); + ctime_r(&sec, buf, sizeof(buf)); #else ctime_r(&sec, buf); #endif @@ -119,19 +69,44 @@ Time::date(string format) const return buf; } -ostream & -operator<<(ostream &out, const Time &start) +string +Time::time() const { - out << start.date(); - return out; + double time = double(*this); + double secs = fmod(time, 60.0); + double all_mins = floor(time / 60.0); + double mins = fmod(all_mins, 60.0); + double hours = floor(all_mins / 60.0); + + stringstream str; + + if (hours > 0.0) { + if (hours < 10.0) + str << '0'; + str << hours << ':'; + } + + if (mins > 0.0) { + if (mins < 10.0) + str << '0'; + str << mins << ':'; + } + + if (secs < 10.0 && !str.str().empty()) + str << '0'; + str << secs; + + return str.str(); } -Time -operator-(const Time &l, const Time &r) +void +sleep(const Time &time) { - timeval tv; - timersub(&l.get(), &r.get(), &tv); - return tv; -} + timespec ts = time; -const Time Time::start(true); +#if USE_POSIX_CLOCK + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); +#else + nanosleep(&ts, NULL); +#endif +} diff --git a/src/base/time.hh b/src/base/time.hh index 565ea0aac..2c54f2675 100644 --- a/src/base/time.hh +++ b/src/base/time.hh @@ -29,84 +29,223 @@ * Nathan Binkert */ -#ifndef __SIM_TIME_HH__ -#define __SIM_TIME_HH__ +#ifndef __BASE_TIME_HH__ +#define __BASE_TIME_HH__ #include +#include + +#include +#include +#include #include #include -struct _timeval; - class Time { protected: - mutable _timeval *time; + timespec _time; + + /** + * Internal time set function + */ + void _set(bool monotonic); public: - explicit Time(bool set_now = false); - Time(const timeval &val); - Time(const Time &val); - ~Time(); - - void set(); - const timeval &get() const; - void set(const timeval &val); - - double operator()() const; - std::string date(std::string format = "") const; + static const long NSEC_PER_SEC = 1000 * 1000 * 1000; + static const long NSEC_PER_MSEC = 1000 * 1000; + static const long NSEC_PER_USEC = 1000; public: - static const Time start; + explicit Time() { clear(); } + explicit Time(double sec) { operator=(sec); } + Time(const Time &val) : _time(val._time) { } + Time(uint64_t sec, uint64_t nsec) { set(sec, nsec); } + Time(const timeval &tv) { operator=(tv); } + Time(const timespec &ts) { operator=(ts); } + + /** + * Accessors for getting and setting the current clock + */ + time_t sec() const { return _time.tv_sec; } + long msec() const { return _time.tv_nsec / NSEC_PER_MSEC; } + long usec() const { return _time.tv_nsec / NSEC_PER_USEC; } + long nsec() const { return _time.tv_nsec; } + + void sec(time_t sec) { _time.tv_sec = sec; } + void msec(long msec) { _time.tv_nsec = msec * NSEC_PER_MSEC; } + void usec(long usec) { _time.tv_nsec = usec * NSEC_PER_USEC; } + void nsec(long nsec) { _time.tv_nsec = nsec; } + + /** + * Clear the time + */ + void clear() { memset(&_time, 0, sizeof(_time)); } + + /** + * Use this to set time for the purposes of time measurement (use + * a monotonic clock if it is available + */ + void setTimer() { _set(true); } + + /** + * Use this to set the time to the actual current time + */ + void setWallclock() { _set(false); } + + /** + * Set the current time + */ + void set(time_t _sec, long _nsec) { sec(_sec); nsec(_nsec); } + + const Time & + operator=(const Time &other) + { + sec(other.sec()); + nsec(other.nsec()); + return *this; + } + + const Time & + operator=(double new_time) + { + double seconds = floor(new_time); + sec((time_t)seconds); + nsec((long)((seconds - new_time) * 1e9)); + return *this; + } + + const Time & + operator=(const timeval &tv) + { + sec(tv.tv_sec); + nsec(tv.tv_usec * 1000); + return *this; + } + + const Time & + operator=(const timespec &ts) + { + sec(ts.tv_sec); + nsec(ts.tv_nsec); + return *this; + } + + /** + * Get the time in floating point seconds + */ + operator double() const + { + return (double)sec() + ((double)nsec()) * 1e-9; + } + + /** + * operators for time conversion + */ + operator timespec() const { return _time; } + operator timeval() const + { + timeval tv; + tv.tv_sec = sec(); + tv.tv_usec = usec(); + return tv; + } + + const Time & + operator+=(const Time &other) + { + + _time.tv_sec += other.sec(); + _time.tv_nsec += other.nsec(); + if (_time.tv_nsec > NSEC_PER_SEC) { + _time.tv_sec++; + _time.tv_nsec -= NSEC_PER_SEC; + } + + return *this; + } + + const Time & + operator-=(const Time &other) + { + _time.tv_sec -= other.sec(); + _time.tv_nsec -= other.nsec(); + if (_time.tv_nsec < 0) { + _time.tv_sec--; + _time.tv_nsec += NSEC_PER_SEC; + } + + return *this; + } + + std::string date(const std::string &format = "") const; + std::string time() const; }; -Time operator-(const Time &l, const Time &r); +void sleep(const Time &time); -std::ostream &operator<<(std::ostream &out, const Time &time); +inline bool +operator==(const Time &l, const Time &r) +{ + return l.sec() == r.sec() && l.nsec() == r.nsec(); +} +inline bool +operator!=(const Time &l, const Time &r) +{ + return l.sec() != r.sec() || l.nsec() != r.nsec(); +} -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)time.h 8.2 (Berkeley) 7/10/94 - */ +inline bool +operator<(const Time &l, const Time &r) +{ + return (l.sec() < r.sec()) || + (l.sec() == r.sec() && l.nsec() < r.nsec()); +} -#if defined(__sun) -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) -#endif +inline bool +operator<=(const Time &l, const Time &r) +{ + return (l.sec() < r.sec()) || + (l.sec() == r.sec() && l.nsec() <= r.nsec()); +} -#endif // __SIM_TIME_HH__ +inline bool +operator>(const Time &l, const Time &r) +{ + return (l.sec() > r.sec()) || + (l.sec() == r.sec() && l.nsec() > r.nsec()); +} + +inline bool +operator>=(const Time &l, const Time &r) +{ + return (l.sec() > r.sec()) || + (l.sec() == r.sec() && l.nsec() >= r.nsec()); +} + +inline Time +operator+(const Time &l, const Time &r) +{ + Time time(l); + time += r; + return time; +} + +inline Time +operator-(const Time &l, const Time &r) +{ + Time time(l); + time -= r; + return time; +} + +inline std::ostream & +operator<<(std::ostream &out, const Time &time) +{ + out << time.date(); + return out; +} + +#endif // __BASE_TIME_HH__ diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc index f2c7c8a2e..ad1d4a9e4 100644 --- a/src/sim/stat_control.cc +++ b/src/sim/stat_control.cc @@ -65,7 +65,7 @@ struct SimTicksReset : public Callback { void process() { - statTime.set(); + statTime.setTimer(); startTick = curTick(); } }; @@ -73,9 +73,11 @@ struct SimTicksReset : public Callback double statElapsedTime() { - Time now(true); + Time now; + now.setTimer(); + Time elapsed = now - statTime; - return elapsed(); + return elapsed; } Tick