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 #ifndef incl_HPHP_REQUEST_TRACING_INL_H_
18 #define incl_HPHP_REQUEST_TRACING_INL_H_
20 #include <folly/AtomicHashMap.h>
21 #include <folly/MapUtil.h>
22 #include <folly/portability/SysTime.h>
24 #include "hphp/util/assertions.h"
26 namespace HPHP
{ struct StringData
; }
28 namespace HPHP
{ namespace rqtrace
{
32 struct AtomicEventStats
{
34 AtomicEventStats() = default;
35 AtomicEventStats(Empty
) {}
37 operator EventStats() {
39 total_duration
.load(std::memory_order_relaxed
),
40 total_count
.load(std::memory_order_relaxed
)
44 std::atomic
<uint64_t> total_duration
;
45 std::atomic
<uint64_t> total_count
;
48 using AtomicEventMap
= folly::AtomicHashMap
<const StringData
*,AtomicEventStats
>;
49 extern AtomicEventMap g_events
;
51 inline int64_t to_micros(timespec t
) {
52 return (int64_t(t
.tv_sec
) * 1000000) + t
.tv_nsec
/ 1000;
55 inline int64_t CurrentMicroTime() {
58 return (int64_t(tv
.tv_sec
) * 1000000) + tv
.tv_usec
;
61 ////////////////////////////////////////////////////////////////////////////////
64 inline Event::Event(folly::StringPiece name
) : m_name(name
) {}
66 inline folly::StringPiece
Event::name() const {
70 inline uint64_t Event::startMicro() const {
75 inline uint64_t Event::stopMicro() const {
80 inline uint64_t Event::duration() const {
82 return m_stopMicro
- m_startMicro
;
85 inline const AnnotationMap
& Event::annotations() const {
89 inline bool Event::finished() const {
90 return m_stopMicro
&& m_stopMicro
;
93 inline void Event::begin(folly::Optional
<timespec
> t
) {
94 assertx(!m_startMicro
);
95 m_startMicro
= detail::CurrentMicroTime();
96 m_startMicro
= t
? detail::to_micros(*t
) : detail::CurrentMicroTime();
99 inline void Event::end(folly::Optional
<timespec
> t
) {
100 assertx(m_startMicro
&& !m_stopMicro
);
101 m_stopMicro
= t
? detail::to_micros(*t
) : detail::CurrentMicroTime();
104 inline void Event::annotate(folly::StringPiece key
, folly::StringPiece value
) {
105 m_annot
.emplace(key
, value
);
108 ////////////////////////////////////////////////////////////////////////////////
110 inline const std::vector
<Event
>& Scope::events() const {
111 return m_sortedEvents
;
114 inline void Scope::setEventPrefix(folly::StringPiece s
) {
115 assertx(m_prefix
.empty());
116 m_prefix
= std::string(s
);
119 inline void Scope::setEventSuffix(folly::StringPiece s
) {
120 assertx(m_suffix
.empty());
121 m_suffix
= std::string(s
);
124 inline Event
& Scope::appendEvent(Event
&& ev
) {
125 assertx(!finished());
126 assertx(ev
.finished());
128 m_sortedEvents
.empty() ||
129 m_sortedEvents
.back().startMicro() + m_sortedEvents
.back().duration()
132 ev
.m_name
.insert(ev
.m_name
.begin(), m_prefix
.begin(), m_prefix
.end());
133 ev
.m_name
.append(m_suffix
);
134 m_sortedEvents
.emplace_back(std::move(ev
));
135 return m_sortedEvents
.back();
138 ////////////////////////////////////////////////////////////////////////////////
140 inline Scope
& Trace::createScope(folly::StringPiece name
) {
141 assertx(m_sortedScopes
.empty() || m_sortedScopes
.back().finished());
142 m_sortedScopes
.emplace_back(name
);
143 return m_sortedScopes
.back();
146 inline void Trace::appendEvent(Event
&& e
) {
147 assertx(!m_sortedScopes
.empty());
148 auto& new_ev
= m_sortedScopes
.back().appendEvent(std::move(e
));
149 auto& info
= m_stats
[std::string(new_ev
.name())];
150 info
.total_duration
+= new_ev
.duration();
154 inline Scope
& Trace::scope() {
155 assertx(!m_sortedScopes
.empty());
156 assertx(!m_sortedScopes
.back().finished());
157 return m_sortedScopes
.back();
160 inline const Scope
& Trace::scope() const {
161 return const_cast<Trace
*>(this)->scope();
164 inline EventStats
Trace::stats_for(folly::StringPiece name
) const {
165 return folly::get_default(m_stats
, std::string(name
), EventStats
{});
168 inline const EventMap
& Trace::stats() const {
172 inline void Trace::finishScope() {
173 assertx(!m_sortedScopes
.empty());
174 assertx(m_sortedScopes
.back().finished());
176 auto& info
= m_stats
[std::string(m_sortedScopes
.back().name())];
177 info
.total_duration
+= m_sortedScopes
.back().duration();
181 inline bool Trace::hasActiveScope() const {
182 return !m_sortedScopes
.empty() && !m_sortedScopes
.back().finished();
185 ////////////////////////////////////////////////////////////////////////////////
187 inline EventGuard::EventGuard(
189 folly::StringPiece name
,
190 folly::Optional
<timespec
> ts
191 ) : m_trace(t
&& t
->hasActiveScope() ? t
: nullptr)
194 if (m_trace
) m_event
.begin(ts
);
197 inline EventGuard::~EventGuard() {
201 inline void EventGuard::annotate(
202 folly::StringPiece key
,
203 folly::StringPiece value
205 if (m_trace
) m_event
.annotate(key
, value
);
208 inline void EventGuard::finish(folly::Optional
<timespec
> t
) {
211 m_trace
->appendEvent(std::move(m_event
));
216 ////////////////////////////////////////////////////////////////////////////////
218 inline ScopeGuard::ScopeGuard(
220 folly::StringPiece name
,
221 folly::Optional
<timespec
> ts
223 , m_scope(t
? &t
->createScope(name
) : nullptr)
225 if (m_scope
) m_scope
->begin(ts
);
228 inline ScopeGuard::~ScopeGuard() {
232 inline void ScopeGuard::annotate(folly::StringPiece k
, folly::StringPiece v
) {
233 if (m_scope
) m_scope
->annotate(k
, v
);
236 inline void ScopeGuard::setEventPrefix(folly::StringPiece fx
) {
237 if (m_scope
) m_scope
->setEventPrefix(fx
);
240 inline void ScopeGuard::setEventSuffix(folly::StringPiece fx
) {
241 if (m_scope
) m_scope
->setEventSuffix(fx
);
244 inline void ScopeGuard::finish(folly::Optional
<timespec
> t
) {
247 m_trace
->finishScope();
253 ////////////////////////////////////////////////////////////////////////////////
256 folly::StringPiece name
,
262 , m_startMicro(start
)
267 assertx(m_startMicro
&& m_stopMicro
);
268 assertx(m_stopMicro
>= m_startMicro
);
269 assertx(!m_name
.empty());
272 inline folly::StringPiece
Range::name() const {
276 inline uint64_t Range::begin() const {
280 inline uint64_t Range::end() const {
284 inline uint64_t Range::duration() const {
285 return m_stopMicro
- m_startMicro
;
289 void Range::visitAnnotations(F
&& fun
) const {
290 for (auto& a
: m_scope
.annotations()) {
291 fun(a
.first
, a
.second
);
294 if ((Event
*)&m_scope
== &m_event
) return;
296 for (auto& a
: m_event
.annotations()) {
297 fun(a
.first
, a
.second
);
301 ////////////////////////////////////////////////////////////////////////////////
304 void visit_ranges(const Trace
& t
, F
&& fun
) {
305 for (auto& s
: t
.scopes()) {
306 if (s
.events().empty()) {
308 folly::sformat("{}_BEGIN to {}_END", s
.name(), s
.name()),
317 folly::sformat("{}_BEGIN to {}", s
.name(), s
.events().front().name()),
319 s
.events().front().startMicro(),
323 for (int i
= 0; i
< s
.events().size() - 1; ++i
) {
324 auto const& start
= s
.events()[i
];
325 auto const& end
= s
.events()[i
];
327 folly::sformat("{} to {}", start
.name(), end
.name()),
335 folly::sformat("{} to {}_END", s
.events().back().name(), s
.name()),
336 s
.events().back().startMicro(),
344 ////////////////////////////////////////////////////////////////////////////////
347 void visit_process_stats(F
&& fun
) {
348 for (auto& pair
: detail::g_events
) {
349 fun(pair
.first
, pair
.second
);
353 ////////////////////////////////////////////////////////////////////////////////