123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- // Copyright (c) 2018 Google LLC.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // Contains utils for getting resource utilization
- #ifndef SOURCE_UTIL_TIMER_H_
- #define SOURCE_UTIL_TIMER_H_
- #if defined(SPIRV_TIMER_ENABLED)
- #include <sys/resource.h>
- #include <cassert>
- #include <iostream>
- // A macro to call spvtools::utils::PrintTimerDescription(std::ostream*, bool).
- // The first argument must be given as std::ostream*. If it is NULL, the
- // function does nothing. Otherwise, it prints resource types measured by Timer
- // class. The second is optional and if it is true, the function also prints
- // resource type fields related to memory. Otherwise, it does not print memory
- // related fields. Its default is false. In usual, this must be placed before
- // calling Timer::Report() to inform what those fields printed by
- // Timer::Report() indicate (or spvtools::utils::PrintTimerDescription() must be
- // used instead).
- #define SPIRV_TIMER_DESCRIPTION(...) \
- spvtools::utils::PrintTimerDescription(__VA_ARGS__)
- // Creates an object of ScopedTimer to measure the resource utilization for the
- // scope surrounding it as the following example:
- //
- // { // <-- beginning of this scope
- //
- // /* ... code out of interest ... */
- //
- // SPIRV_TIMER_SCOPED(std::cout, tag);
- //
- // /* ... lines of code that we want to know its resource usage ... */
- //
- // } // <-- end of this scope. The destructor of ScopedTimer prints tag and
- // the resource utilization to std::cout.
- #define SPIRV_TIMER_SCOPED(...) \
- spvtools::utils::ScopedTimer<spvtools::utils::Timer> timer##__LINE__( \
- __VA_ARGS__)
- namespace spvtools {
- namespace utils {
- // Prints the description of resource types measured by Timer class. If |out| is
- // NULL, it does nothing. Otherwise, it prints resource types. The second is
- // optional and if it is true, the function also prints resource type fields
- // related to memory. Its default is false. In usual, this must be placed before
- // calling Timer::Report() to inform what those fields printed by
- // Timer::Report() indicate.
- void PrintTimerDescription(std::ostream*, bool = false);
- // Status of Timer. kGetrusageFailed means it failed in calling getrusage().
- // kClockGettimeWalltimeFailed means it failed in getting wall time when calling
- // clock_gettime(). kClockGettimeCPUtimeFailed means it failed in getting CPU
- // time when calling clock_gettime().
- enum UsageStatus {
- kSucceeded = 0,
- kGetrusageFailed = 1 << 0,
- kClockGettimeWalltimeFailed = 1 << 1,
- kClockGettimeCPUtimeFailed = 1 << 2,
- };
- // Timer measures the resource utilization for a range of code. The resource
- // utilization consists of CPU time (i.e., process time), WALL time (elapsed
- // time), USR time, SYS time, RSS delta, and the delta of the number of page
- // faults. RSS delta and the delta of the number of page faults are measured
- // only when |measure_mem_usage| given to the constructor is true. This class
- // should be used as the following example:
- //
- // spvtools::utils::Timer timer(std::cout);
- // timer.Start(); // <-- set |usage_before_|, |wall_before_|,
- // and |cpu_before_|
- //
- // /* ... lines of code that we want to know its resource usage ... */
- //
- // timer.Stop(); // <-- set |cpu_after_|, |wall_after_|, and
- // |usage_after_|
- // timer.Report(tag); // <-- print tag and the resource utilization to
- // std::cout.
- class Timer {
- public:
- Timer(std::ostream* out, bool measure_mem_usage = false)
- : report_stream_(out),
- usage_status_(kSucceeded),
- measure_mem_usage_(measure_mem_usage) {}
- // Sets |usage_before_|, |wall_before_|, and |cpu_before_| as results of
- // getrusage(), clock_gettime() for the wall time, and clock_gettime() for the
- // CPU time respectively. Note that this method erases all previous state of
- // |usage_before_|, |wall_before_|, |cpu_before_|.
- virtual void Start();
- // Sets |cpu_after_|, |wall_after_|, and |usage_after_| as results of
- // clock_gettime() for the wall time, and clock_gettime() for the CPU time,
- // getrusage() respectively. Note that this method erases all previous state
- // of |cpu_after_|, |wall_after_|, |usage_after_|.
- virtual void Stop();
- // If |report_stream_| is NULL, it does nothing. Otherwise, it prints the
- // resource utilization (i.e., CPU/WALL/USR/SYS time, RSS delta) between the
- // time of calling Timer::Start() and the time of calling Timer::Stop(). If we
- // cannot get a resource usage because of failures, it prints "Failed" instead
- // for the resource.
- void Report(const char* tag);
- // Returns the measured CPU Time (i.e., process time) for a range of code
- // execution. If kClockGettimeCPUtimeFailed is set by the failure of calling
- // clock_gettime(), it returns -1.
- virtual double CPUTime() {
- if (usage_status_ & kClockGettimeCPUtimeFailed) return -1;
- return TimeDifference(cpu_before_, cpu_after_);
- }
- // Returns the measured Wall Time (i.e., elapsed time) for a range of code
- // execution. If kClockGettimeWalltimeFailed is set by the failure of
- // calling clock_gettime(), it returns -1.
- virtual double WallTime() {
- if (usage_status_ & kClockGettimeWalltimeFailed) return -1;
- return TimeDifference(wall_before_, wall_after_);
- }
- // Returns the measured USR Time for a range of code execution. If
- // kGetrusageFailed is set because of the failure of calling getrusage(), it
- // returns -1.
- virtual double UserTime() {
- if (usage_status_ & kGetrusageFailed) return -1;
- return TimeDifference(usage_before_.ru_utime, usage_after_.ru_utime);
- }
- // Returns the measured SYS Time for a range of code execution. If
- // kGetrusageFailed is set because of the failure of calling getrusage(), it
- // returns -1.
- virtual double SystemTime() {
- if (usage_status_ & kGetrusageFailed) return -1;
- return TimeDifference(usage_before_.ru_stime, usage_after_.ru_stime);
- }
- // Returns the measured RSS delta for a range of code execution. If
- // kGetrusageFailed is set because of the failure of calling getrusage(), it
- // returns -1.
- virtual long RSS() const {
- if (usage_status_ & kGetrusageFailed) return -1;
- return usage_after_.ru_maxrss - usage_before_.ru_maxrss;
- }
- // Returns the measured the delta of the number of page faults for a range of
- // code execution. If kGetrusageFailed is set because of the failure of
- // calling getrusage(), it returns -1.
- virtual long PageFault() const {
- if (usage_status_ & kGetrusageFailed) return -1;
- return (usage_after_.ru_minflt - usage_before_.ru_minflt) +
- (usage_after_.ru_majflt - usage_before_.ru_majflt);
- }
- virtual ~Timer() {}
- private:
- // Returns the time gap between |from| and |to| in seconds.
- static double TimeDifference(const timeval& from, const timeval& to) {
- assert((to.tv_sec > from.tv_sec) ||
- (to.tv_sec == from.tv_sec && to.tv_usec >= from.tv_usec));
- return static_cast<double>(to.tv_sec - from.tv_sec) +
- static_cast<double>(to.tv_usec - from.tv_usec) * .000001;
- }
- // Returns the time gap between |from| and |to| in seconds.
- static double TimeDifference(const timespec& from, const timespec& to) {
- assert((to.tv_sec > from.tv_sec) ||
- (to.tv_sec == from.tv_sec && to.tv_nsec >= from.tv_nsec));
- return static_cast<double>(to.tv_sec - from.tv_sec) +
- static_cast<double>(to.tv_nsec - from.tv_nsec) * .000000001;
- }
- // Output stream to print out the resource utilization. If it is NULL,
- // Report() does nothing.
- std::ostream* report_stream_;
- // Status to stop measurement if a system call returns an error.
- unsigned usage_status_;
- // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
- // Timer::Start() is called. It is used as the base status of CPU time.
- timespec cpu_before_;
- // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
- // Timer::Start() is called. It is used as the base status of WALL time.
- timespec wall_before_;
- // Variable to save the result of getrusage() when Timer::Start() is called.
- // It is used as the base status of USR time, SYS time, and RSS.
- rusage usage_before_;
- // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when
- // Timer::Stop() is called. It is used as the last status of CPU time. The
- // resouce usage is measured by subtracting |cpu_before_| from it.
- timespec cpu_after_;
- // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when
- // Timer::Stop() is called. It is used as the last status of WALL time. The
- // resouce usage is measured by subtracting |wall_before_| from it.
- timespec wall_after_;
- // Variable to save the result of getrusage() when Timer::Stop() is called. It
- // is used as the last status of USR time, SYS time, and RSS. Those resouce
- // usages are measured by subtracting |usage_before_| from it.
- rusage usage_after_;
- // If true, Timer reports the memory usage information too. Otherwise, Timer
- // reports only USR time, WALL time, SYS time.
- bool measure_mem_usage_;
- };
- // The purpose of ScopedTimer is to measure the resource utilization for a
- // scope. Simply creating a local variable of ScopedTimer will call
- // Timer::Start() and it calls Timer::Stop() and Timer::Report() at the end of
- // the scope by its destructor. When we use this class, we must choose the
- // proper Timer class (for class TimerType template) in advance. This class
- // should be used as the following example:
- //
- // { // <-- beginning of this scope
- //
- // /* ... code out of interest ... */
- //
- // spvtools::utils::ScopedTimer<spvtools::utils::Timer>
- // scopedtimer(std::cout, tag);
- //
- // /* ... lines of code that we want to know its resource usage ... */
- //
- // } // <-- end of this scope. The destructor of ScopedTimer prints tag and
- // the resource utilization to std::cout.
- //
- // The template<class TimerType> is used to choose a Timer class. Currently,
- // only options for the Timer class are Timer and MockTimer in the unit test.
- template <class TimerType>
- class ScopedTimer {
- public:
- ScopedTimer(std::ostream* out, const char* tag,
- bool measure_mem_usage = false)
- : timer(new TimerType(out, measure_mem_usage)), tag_(tag) {
- timer->Start();
- }
- // At the end of the scope surrounding the instance of this class, this
- // destructor saves the last status of resource usage and reports it.
- virtual ~ScopedTimer() {
- timer->Stop();
- timer->Report(tag_);
- delete timer;
- }
- private:
- // Actual timer that measures the resource utilization. It must be an instance
- // of Timer class if there is no special reason to use other class.
- TimerType* timer;
- // A tag that will be printed in front of the trace reported by Timer class.
- const char* tag_;
- };
- // CumulativeTimer is the same as Timer class, but it supports a cumulative
- // measurement as the following example:
- //
- // CumulativeTimer *ctimer = new CumulativeTimer(std::cout);
- // ctimer->Start();
- //
- // /* ... lines of code that we want to know its resource usage ... */
- //
- // ctimer->Stop();
- //
- // /* ... code out of interest ... */
- //
- // ctimer->Start();
- //
- // /* ... lines of code that we want to know its resource usage ... */
- //
- // ctimer->Stop();
- // ctimer->Report(tag);
- // delete ctimer;
- //
- class CumulativeTimer : public Timer {
- public:
- CumulativeTimer(std::ostream* out, bool measure_mem_usage = false)
- : Timer(out, measure_mem_usage),
- cpu_time_(0),
- wall_time_(0),
- usr_time_(0),
- sys_time_(0),
- rss_(0),
- pgfaults_(0) {}
- // If we cannot get a resource usage because of failures, it sets -1 for the
- // resource usage.
- void Stop() override {
- Timer::Stop();
- if (cpu_time_ >= 0 && Timer::CPUTime() >= 0)
- cpu_time_ += Timer::CPUTime();
- else
- cpu_time_ = -1;
- if (wall_time_ >= 0 && Timer::WallTime() >= 0)
- wall_time_ += Timer::WallTime();
- else
- wall_time_ = -1;
- if (usr_time_ >= 0 && Timer::UserTime() >= 0)
- usr_time_ += Timer::UserTime();
- else
- usr_time_ = -1;
- if (sys_time_ >= 0 && Timer::SystemTime() >= 0)
- sys_time_ += Timer::SystemTime();
- else
- sys_time_ = -1;
- if (rss_ >= 0 && Timer::RSS() >= 0)
- rss_ += Timer::RSS();
- else
- rss_ = -1;
- if (pgfaults_ >= 0 && Timer::PageFault() >= 0)
- pgfaults_ += Timer::PageFault();
- else
- pgfaults_ = -1;
- }
- // Returns the cumulative CPU Time (i.e., process time) for a range of code
- // execution.
- double CPUTime() override { return cpu_time_; }
- // Returns the cumulative Wall Time (i.e., elapsed time) for a range of code
- // execution.
- double WallTime() override { return wall_time_; }
- // Returns the cumulative USR Time for a range of code execution.
- double UserTime() override { return usr_time_; }
- // Returns the cumulative SYS Time for a range of code execution.
- double SystemTime() override { return sys_time_; }
- // Returns the cumulative RSS delta for a range of code execution.
- long RSS() const override { return rss_; }
- // Returns the cumulative delta of number of page faults for a range of code
- // execution.
- long PageFault() const override { return pgfaults_; }
- private:
- // Variable to save the cumulative CPU time (i.e., process time).
- double cpu_time_;
- // Variable to save the cumulative wall time (i.e., elapsed time).
- double wall_time_;
- // Variable to save the cumulative user time.
- double usr_time_;
- // Variable to save the cumulative system time.
- double sys_time_;
- // Variable to save the cumulative RSS delta.
- long rss_;
- // Variable to save the cumulative delta of the number of page faults.
- long pgfaults_;
- };
- } // namespace utils
- } // namespace spvtools
- #else // defined(SPIRV_TIMER_ENABLED)
- #define SPIRV_TIMER_DESCRIPTION(...)
- #define SPIRV_TIMER_SCOPED(...)
- #endif // defined(SPIRV_TIMER_ENABLED)
- #endif // SOURCE_UTIL_TIMER_H_
|