Make comparison IR ops layout agnostic
[hiphop-php.git] / hphp / runtime / base / request-tracing-inl.h
blob25f9982ab0a71afe5776b3a1f6da99e20f98caac
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 {
30 namespace detail {
32 struct AtomicEventStats {
33 struct Empty{};
34 AtomicEventStats() = default;
35 AtomicEventStats(Empty) {}
37 operator EventStats() {
38 return {
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() {
56 timeval tv;
57 gettimeofday(&tv, 0);
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 {
67 return m_name;
70 inline uint64_t Event::startMicro() const {
71 assertx(finished());
72 return m_startMicro;
75 inline uint64_t Event::stopMicro() const {
76 assertx(finished());
77 return m_stopMicro;
80 inline uint64_t Event::duration() const {
81 assertx(finished());
82 return m_stopMicro - m_startMicro;
85 inline const AnnotationMap& Event::annotations() const {
86 return m_annot;
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());
127 assertx(
128 m_sortedEvents.empty() ||
129 m_sortedEvents.back().startMicro() + m_sortedEvents.back().duration()
130 <= ev.startMicro()
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();
151 info.total_count++;
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 {
169 return m_stats;
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();
178 info.total_count++;
181 inline bool Trace::hasActiveScope() const {
182 return !m_sortedScopes.empty() && !m_sortedScopes.back().finished();
185 ////////////////////////////////////////////////////////////////////////////////
187 inline EventGuard::EventGuard(
188 Trace* t,
189 folly::StringPiece name,
190 folly::Optional<timespec> ts
191 ) : m_trace(t && t->hasActiveScope() ? t : nullptr)
192 , m_event(name)
194 if (m_trace) m_event.begin(ts);
197 inline EventGuard::~EventGuard() {
198 finish();
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) {
209 if (m_trace) {
210 m_event.end(t);
211 m_trace->appendEvent(std::move(m_event));
212 m_trace = nullptr;
216 ////////////////////////////////////////////////////////////////////////////////
218 inline ScopeGuard::ScopeGuard(
219 Trace* t,
220 folly::StringPiece name,
221 folly::Optional<timespec> ts
222 ) : m_trace(t)
223 , m_scope(t ? &t->createScope(name) : nullptr)
225 if (m_scope) m_scope->begin(ts);
228 inline ScopeGuard::~ScopeGuard() {
229 finish();
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) {
245 if (m_scope) {
246 m_scope->end(t);
247 m_trace->finishScope();
248 m_trace = nullptr;
249 m_scope = nullptr;
253 ////////////////////////////////////////////////////////////////////////////////
255 inline Range::Range(
256 folly::StringPiece name,
257 uint64_t start,
258 uint64_t end,
259 const Scope& scope,
260 const Event& event
261 ) : m_name(name)
262 , m_startMicro(start)
263 , m_stopMicro(end)
264 , m_scope(scope)
265 , m_event(event)
267 assertx(m_startMicro && m_stopMicro);
268 assertx(m_stopMicro >= m_startMicro);
269 assertx(!m_name.empty());
272 inline folly::StringPiece Range::name() const {
273 return m_name;
276 inline uint64_t Range::begin() const {
277 return m_startMicro;
280 inline uint64_t Range::end() const {
281 return m_stopMicro;
284 inline uint64_t Range::duration() const {
285 return m_stopMicro - m_startMicro;
288 template<class F>
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 ////////////////////////////////////////////////////////////////////////////////
303 template<class F>
304 void visit_ranges(const Trace& t, F&& fun) {
305 for (auto& s : t.scopes()) {
306 if (s.events().empty()) {
307 fun(Range(
308 folly::sformat("{}_BEGIN to {}_END", s.name(), s.name()),
309 s.startMicro(),
310 s.stopMicro(),
314 continue;
316 fun(Range(
317 folly::sformat("{}_BEGIN to {}", s.name(), s.events().front().name()),
318 s.startMicro(),
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];
326 fun(Range(
327 folly::sformat("{} to {}", start.name(), end.name()),
328 start.startMicro(),
329 start.stopMicro(),
331 start
334 fun(
335 folly::sformat("{} to {}_END", s.events().back().name(), s.name()),
336 s.events().back().startMicro(),
337 s.stopMicro(),
339 s.events().back()
344 ////////////////////////////////////////////////////////////////////////////////
346 template<class F>
347 void visit_process_stats(F&& fun) {
348 for (auto& pair : detail::g_events) {
349 fun(pair.first, pair.second);
353 ////////////////////////////////////////////////////////////////////////////////
356 #endif