2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/timer.h"
20 #include <folly/ClockGettimeWrappers.h>
21 #include <folly/portability/SysResource.h>
22 #include <folly/portability/SysTime.h>
24 #include "hphp/util/logger.h"
25 #include "hphp/util/trace.h"
28 #include "common/time/ClockGettimeNS.h" // nolint
32 ///////////////////////////////////////////////////////////////////////////////
34 __thread
int64_t s_extra_request_nanoseconds
;
37 ///////////////////////////////////////////////////////////////////////////////
39 #define PRINT_MSG(...) \
42 Logger::Info(__VA_ARGS__); \
45 fprintf(stderr, __VA_ARGS__); \
48 Trace::traceRelease(__VA_ARGS__); \
50 default: not_reached(); \
53 ///////////////////////////////////////////////////////////////////////////////
56 Timer::Timer(Type type
, const char *name
/* = NULL */, ReportType r
)
57 : m_type(type
), m_report(r
) {
60 PRINT_MSG("%s...", name
);
66 if (!m_name
.empty()) {
71 int64_t Timer::getMicroSeconds() const {
72 return measure() - m_start
;
75 void Timer::report() const {
76 int64_t ms
= getMicroSeconds();
77 int seconds
= ms
/ 1000000;
78 PRINT_MSG("%s took %d'%02d\" (%" PRId64
" us) %s", m_name
.c_str(),
79 seconds
/ 60, seconds
% 60, ms
, getName());
82 void Timer::GetMonotonicTime(timespec
&ts
) {
83 gettime(CLOCK_MONOTONIC
, &ts
);
86 void Timer::GetRealtimeTime(timespec
&ts
) {
87 gettime(CLOCK_REALTIME
, &ts
);
90 static int64_t to_usec(const timeval
& tv
) {
91 return (int64_t(tv
.tv_sec
) * 1000000) + tv
.tv_usec
;
94 int64_t Timer::GetCurrentTimeMicros() {
100 int64_t Timer::GetRusageMicros(Type t
, Who who
) {
101 assert(t
!= WallTime
);
104 memset(&ru
, 0, sizeof(ru
));
105 auto DEBUG_ONLY ret
= getrusage(who
, &ru
);
109 case SystemCPU
: return to_usec(ru
.ru_stime
);
110 case UserCPU
: return to_usec(ru
.ru_utime
);
111 case TotalCPU
: return to_usec(ru
.ru_stime
) + to_usec(ru
.ru_utime
);
112 default: always_assert(false);
116 int64_t Timer::GetThreadCPUTimeNanos() {
117 return gettime_ns(CLOCK_THREAD_CPUTIME_ID
);
120 int64_t Timer::measure() const {
121 if (m_type
== WallTime
) {
122 return GetCurrentTimeMicros();
125 return GetRusageMicros(m_type
, Timer::Self
);
128 const char *Timer::getName() const {
130 case WallTime
: return "wall time";
131 case SystemCPU
: return "system cpu";
132 case UserCPU
: return "user cpu";
133 case TotalCPU
: return "total cpu";
135 always_assert(false);
138 ///////////////////////////////////////////////////////////////////////////////
140 SlowTimer::SlowTimer(int64_t msThreshold
, const char *location
, const char *info
)
141 : m_timer(Timer::WallTime
), m_msThreshold(msThreshold
) {
142 if (location
) m_location
= location
;
143 if (info
) m_info
= info
;
146 SlowTimer::~SlowTimer() {
147 int64_t msec
= getTime();
148 if (msec
>= m_msThreshold
&& m_msThreshold
!= 0) {
149 Logger::Error("SlowTimer [%" PRId64
"ms] at %s: %s",
150 msec
, m_location
.c_str(), m_info
.c_str());
154 int64_t SlowTimer::getTime() const {
155 return m_timer
.getMicroSeconds() / 1000;
158 ///////////////////////////////////////////////////////////////////////////////
160 int gettime(clockid_t clock
, timespec
* ts
) {
161 if (clock
!= CLOCK_THREAD_CPUTIME_ID
) {
162 return folly::chrono::clock_gettime(clock
, ts
);
165 constexpr uint64_t sec_to_ns
= 1000000000;
169 if (!fb_perf_get_thread_cputime_ns(&time
)) {
170 time
+= s_extra_request_nanoseconds
;
171 ts
->tv_sec
= time
/ sec_to_ns
;
172 ts
->tv_nsec
= time
% sec_to_ns
;
177 auto const ret
= folly::chrono::clock_gettime(clock
, ts
);
178 always_assert(ts
->tv_nsec
< sec_to_ns
);
180 ts
->tv_sec
+= s_extra_request_nanoseconds
/ sec_to_ns
;
181 auto res
= ts
->tv_nsec
+ s_extra_request_nanoseconds
% sec_to_ns
;
182 if (res
> sec_to_ns
) {
191 int64_t gettime_ns(clockid_t clock
) {
192 if (clock
!= CLOCK_THREAD_CPUTIME_ID
) {
193 return folly::chrono::clock_gettime_ns(clock
);
198 if (!fb_perf_get_thread_cputime_ns(&time
)) {
199 return time
+ s_extra_request_nanoseconds
;
203 return folly::chrono::clock_gettime_ns(clock
) + s_extra_request_nanoseconds
;
206 int64_t gettime_diff_us(const timespec
& start
, const timespec
& end
) {
207 int64_t dsec
= end
.tv_sec
- start
.tv_sec
;
208 int64_t dnsec
= end
.tv_nsec
- start
.tv_nsec
;
209 return dsec
* 1000000 + dnsec
/ 1000;
212 ///////////////////////////////////////////////////////////////////////////////