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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/timer.h"
24 #include <folly/Format.h>
26 #include "hphp/runtime/base/execution-context.h"
27 #include "hphp/util/rds-local.h"
28 #include "hphp/util/struct-log.h"
29 #include "hphp/util/timer.h"
30 #include "hphp/util/trace.h"
32 TRACE_SET_MOD(jittime
);
34 namespace HPHP
{ namespace jit
{
38 //////////////////////////////////////////////////////////////////////
40 std::array
<Timer::Counter
,Timer::kNumTimers
> kCountersDefault
{};
41 using TimerType
= std::array
<Timer::Counter
,Timer::kNumTimers
>;
42 RDS_LOCAL_NO_CHECK(TimerType
, s_counters
)(kCountersDefault
);
44 struct TimerName
{ const char* str
; Timer::Name name
; };
45 const TimerName s_names
[] = {
46 # define TIMER_NAME(name) {#name, Timer::name},
51 int64_t getCPUTimeNanos() {
52 return RuntimeOption::EvalJitTimer
? HPHP::Timer::GetThreadCPUTimeNanos() :
56 int64_t getWallClockMicros() {
57 return RuntimeOption::EvalJitTimer
? HPHP::Timer::GetCurrentTimeMicros() :
61 //////////////////////////////////////////////////////////////////////
65 Timer::Timer(Name name
, StructuredLogEntry
* log_entry
)
68 , m_start(getCPUTimeNanos())
69 , m_start_wall(getWallClockMicros())
70 , m_log_entry(log_entry
)
75 if (!m_finished
) stop();
78 int64_t Timer::stop() {
79 if (!RuntimeOption::EvalJitTimer
) return 0;
82 auto const elapsed
= getCPUTimeNanos() - m_start
;
83 auto const elapsed_wall_clock
= getWallClockMicros() - m_start_wall
;
86 m_log_entry
->setInt(std::string(s_names
[(size_t)m_name
].str
) + "_micros",
90 auto& counter
= s_counters
[m_name
];
91 counter
.total
+= elapsed
;
93 counter
.max
= std::max(counter
.max
, elapsed
);
94 counter
.wall_time_elapsed
+= elapsed_wall_clock
;
99 Timer::CounterVec
Timer::Counters() {
101 ret
.reserve(std::size(s_names
));
102 for (const auto& pair
: s_names
) {
103 ret
.emplace_back(pair
.str
, s_counters
[pair
.name
]);
108 Timer::Counter
Timer::CounterValue(Timer::Name name
) {
109 return s_counters
[name
];
112 void Timer::RequestInit() {
113 memset(s_counters
.get(), 0, sizeof(Timer::Counter
[Timer::kNumTimers
]));
116 void Timer::RequestExit() {
121 if (!Trace::moduleEnabledRelease(Trace::jittime
)) return;
122 Trace::traceRelease("%s", Show().c_str());
125 std::string
Timer::Show() {
126 auto const header
= "{:<30} | {:>15} {:>15} {:>15} {:>15}\n";
127 auto const row
= "{:<30} | {:>15} {:>13,}us {:>13,}ns {:>13,}ns\n";
129 std::array
<TimerName
,kNumTimers
> names_copy
;
130 std::copy(s_names
, s_names
+ kNumTimers
, begin(names_copy
));
132 if (!getenv("HHVM_JIT_TIMER_NO_SORT")) {
133 auto totalSort
= [] (const TimerName
& a
, const TimerName
& b
) {
134 return s_counters
[a
.name
].total
> s_counters
[b
.name
].total
;
136 std::sort(begin(names_copy
), end(names_copy
), totalSort
);
140 for (auto const& pair
: names_copy
) {
141 auto const& counter
= s_counters
[pair
.name
];
142 if (counter
.total
== 0 && counter
.count
== 0) continue;
149 counter
.total
/ 1000,
155 if (rows
.empty()) return rows
;
158 auto const url
= g_context
->getRequestUrl(75);
159 folly::format(&ret
, "\nJIT timers for {}\n", url
);
160 folly::format(&ret
, header
, "name", "count", "total", "average", "max");
161 folly::format(&ret
, "{:-^30}-+{:-^64}\n{}\n", "", "", rows
);