UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
profile_timer.cpp
Go to the documentation of this file.
1#ifdef BUILD_PROFILED
2
3#include <cstdlib>
4#include <cstring>
5#include "profile_timer.hpp"
6
7std::chrono::steady_clock::time_point Profiler::start_point;
8
9Profiler& Profiler::get_instance(){
10 static Profiler inst;
11 static std::mutex mut;
12 std::lock_guard<std::mutex> lock(mut);
13 if(inst.start_point.time_since_epoch() == std::chrono::steady_clock::duration::zero()){
14 inst.start_point = std::chrono::steady_clock::now();
15 }
16 return inst;
17}
18
19void Profiler::write_events(const std::vector<Profile_event>& events){
20 if(!active)
21 return;
22
23 std::lock_guard<std::mutex> lock(io_mut);
24 for(const auto& event : events){
25
26 auto ts = event.start;
27 auto end = event.end;
28 out_file << "{ \"name\": \"" << event.name << "\""
29 << ", \"cat\": \"function\""
30 << ", \"ph\": \"X\""
31 << ", \"pid\": \"" << pid << "\""
32 << ", \"tid\": \"" << event.thread_id << "\""
33 << ", \"ts\": \"" << ts << "\""
34 << ", \"dur\": \"" << end - ts << "\""
35 << ", \"dbg_end\": \"" << end << "\""
36 << "},\n ";
37 }
38}
39
40Profiler::Profiler(){
41 const char *env_p = std::getenv("UG_PROFILE");
42 active = env_p && env_p[0] != '\0';
43 if(!active){
44 return;
45 }
46
47 std::string filename = "ug_";
48 filename += env_p;
49 filename += ".json";
50
51 pid = std::this_thread::get_id();
52 out_file.open(filename);
53
54 out_file << "[ ";
55}
56
57Profiler_thread_inst::Profiler_thread_inst(Profiler& profiler) : profiler(profiler) {
58 thread_events.reserve(THREAD_EVENT_BUF_SIZE);
59 c_timers.reserve(20);
60}
61
62Profiler_thread_inst& Profiler_thread_inst::get_instance(){
63 static thread_local Profiler_thread_inst inst(Profiler::get_instance());
64 return inst;
65}
66
67Profiler_thread_inst::~Profiler_thread_inst(){
68 profiler.write_events(thread_events);
69}
70
71void Profiler_thread_inst::add_event(Profile_event&& event){
72 if(thread_events.size() == THREAD_EVENT_BUF_SIZE){
73 profiler.write_events(thread_events);
74 thread_events.clear();
75 }
76
77 thread_events.emplace_back(std::move(event));
78}
79
80void Profiler_thread_inst::push_timer(const char *name){
81 c_timers.emplace_back(std::ref(*this), std::string(name));
82}
83
84void Profiler_thread_inst::pop_timer(){
85 c_timers.pop_back();
86}
87
88Profile_timer::Profile_timer(Profiler_thread_inst& profiler, std::string name) :
89 profiler(profiler),
90 event(name, std::this_thread::get_id())
91{
92 auto ts = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - profiler.profiler.get_start_point()).count();
93
94 /* Chromium has problems if two events within the same thread have
95 * the same start time. To work around this we just add a microsecond
96 * if the start time would be the same as the previous one
97 */
98 if(ts <= profiler.last_ts){
99 ts = profiler.last_ts + 1;
100 }
101
102 event.start = ts;
103 profiler.last_ts = ts;
104}
105
106Profile_timer::Profile_timer(Profile_timer&& o) :
107 profiler(o.profiler)
108{
109 std::swap(event, o.event);
110}
111
112Profile_timer::~Profile_timer(){
113 commit();
114}
115
116Profile_timer& Profile_timer::operator=(Profile_timer&& rhs) {
117 std::swap(event, rhs.event);
118 std::swap(profiler, rhs.profiler);
119 return *this;
120}
121
122void Profile_timer::commit(){
123 if(event.name.empty())
124 return;
125
126 event.end = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - profiler.get().profiler.get_start_point()).count();
127 profiler.get().add_event(std::move(event));
128}
129
130void push_prof_timer(const char *name){
131 Profiler_thread_inst::get_instance().push_timer(name);
132}
133
134void pop_prof_timer(){
135 Profiler_thread_inst::get_instance().pop_timer();
136}
137
138#endif //BUILD_PROFILED
const char * name
Definition settings.cpp:193
uint32_t ts
Definition tfrc.c:101