FE 0.13.1
Header-only C++ frontend library
Loading...
Searching...
No Matches
profile.h
Go to the documentation of this file.
1#pragma once
2
3#include <chrono>
4#include <cstdint>
5
6#include <limits>
7#include <ostream>
8#include <string>
9#include <string_view>
10#include <utility>
11#include <vector>
12
13namespace fe {
14
15/// Records wall-clock timings for (possibly nested) named Profiler::Span%s and reports them in various formats.
16/// Span%s nest like a stack, so each one remembers its parent.
17/// From these Span%s the Profiler can derive
18/// - a flat Profiler::summary aggregated by name,
19/// - a hierarchical Profiler::tree that shows the runtimes in context, and
20/// - a [Chrome Trace Event](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU)
21/// JSON dump (Profiler::chrome_trace) that can be loaded into `chrome://tracing`, Perfetto, or speedscope.
22/// @see Profiler::start, Profiler::stop
23class Profiler {
24public:
25 using Clock = std::chrono::steady_clock;
26 using Duration = Clock::duration;
27
28 static constexpr size_t No_Parent = std::numeric_limits<size_t>::max();
29
30 /// A single run.
31 struct Span {
32 std::string name;
33 Clock::time_point start;
34 Clock::time_point stop;
35 size_t depth; ///< Nesting level; a root Span has depth 0.
36 size_t parent; ///< Index of the enclosing Span in Profiler::spans, or Profiler::No_Parent for a root.
37 std::vector<std::pair<std::string, uint64_t>> counters; ///< Custom counters (insertion order).
38
39 Duration elapsed() const { return stop - start; }
40 };
41
42 /// @name Getters
43 ///@{
44 bool empty() const { return spans_.empty(); }
45 const auto& spans() const { return spans_; }
46 ///@}
47
48 /// @name Recording
49 /// Bracket a run with Profiler::start / Profiler::stop; the calls must nest like a stack.
50 ///@{
51 /// Marks the start of a run named @p name.
52 void start(std::string_view name) {
53 auto parent = stack_.empty() ? No_Parent : stack_.back();
54 stack_.emplace_back(spans_.size());
55 spans_.emplace_back(std::string(name), Clock::now(), Clock::time_point{}, stack_.size() - 1, parent);
56 }
57
58 /// Marks the end of the most recently started run; no-op if no Span is running.
59 void stop() {
60 if (stack_.empty()) return;
61 auto id = stack_.back();
62 stack_.pop_back();
63 spans_[id].stop = Clock::now();
64 }
65
66 /// Adds @p n to counter @p key of the currently running Span; no-op if no Span is running or @p n is `0`.
67 void count(std::string_view key, uint64_t n = 1) {
68 if (stack_.empty() || n == 0) return;
69 auto& counters = spans_[stack_.back()].counters;
70 for (auto& [k, v] : counters) {
71 if (k == key) {
72 v += n;
73 return;
74 }
75 }
76 counters.emplace_back(std::string(key), n);
77 }
78 ///@}
79
80 /// @name Reporting
81 ///@{
82 /// Prints a flat table aggregated by name, sorted by total time, descending.
83 void summary(std::ostream&) const;
84 /// Prints the Span%s as an indented tree, preserving the order in which they ran.
85 void tree(std::ostream&) const;
86 /// Dumps all Span%s as Chrome Trace Event Format JSON.
87 void chrome_trace(std::ostream&) const;
88 ///@}
89
90private:
91 /// Per-Span time spent in *direct* children; `self = elapsed - children`.
92 std::vector<Duration> children_durations() const;
93
94 std::vector<size_t> stack_;
95 std::vector<Span> spans_;
96};
97
98} // namespace fe
Records wall-clock timings for (possibly nested) named Profiler::Spans and reports them in various fo...
Definition profile.h:23
void tree(std::ostream &) const
Prints the Spans as an indented tree, preserving the order in which they ran.
const auto & spans() const
Definition profile.h:45
void count(std::string_view key, uint64_t n=1)
Adds n to counter key of the currently running Span; no-op if no Span is running or n is 0.
Definition profile.h:67
Clock::duration Duration
Definition profile.h:26
bool empty() const
Definition profile.h:44
void start(std::string_view name)
Definition profile.h:52
void stop()
Marks the end of the most recently started run; no-op if no Span is running.
Definition profile.h:59
void chrome_trace(std::ostream &) const
Dumps all Spans as Chrome Trace Event Format JSON.
static constexpr size_t No_Parent
Definition profile.h:28
std::chrono::steady_clock Clock
Definition profile.h:25
void summary(std::ostream &) const
Definition algo.h:17
A single run.
Definition profile.h:31
Clock::time_point start
Definition profile.h:33
size_t depth
Nesting level; a root Span has depth 0.
Definition profile.h:35
Duration elapsed() const
Definition profile.h:39
size_t parent
Index of the enclosing Span in Profiler::spans, or Profiler::No_Parent for a root.
Definition profile.h:36
std::vector< std::pair< std::string, uint64_t > > counters
Custom counters (insertion order).
Definition profile.h:37
std::string name
Definition profile.h:32
Clock::time_point stop
Definition profile.h:34