-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathInstrumentorTimer.h
164 lines (132 loc) · 4.48 KB
/
InstrumentorTimer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//
// Basic instrumentation profiler by Cherno
// ------------------------
// Modified by Gavin
// 1. Make 'WriteProfile' thread-safe by add 'std::mutex' and 'std::lock_guard'
// 2. Remove the 'InstrumentationSession' which is no significance
// 3. Add destructor for 'Instrumentor'
// 4. Change the Constructor of 'Instrumentor' to private
// ------------------------
// Usage: include this header file somewhere in your code (e.g. precompiled header), and then use like:
//
// Instrumentor::Get().BeginSession("Session Name"); // Begin session
// {
// InstrumentationTimer timer("Profiled Scope Name"); // Place code like this in scopes you'd like to include in profiling
// // Code
// }
// Instrumentor::Get().EndSession(); // End Session
//
// You will probably want to macro-fy this, to switch on/off easily and use things like __FUNCSIG__ for the profile name.
//
#pragma once
#include <string>
#include <chrono>
#include <fstream>
#include <thread>
#include <mutex>
#include <algorithm>
struct ProfileResult {
std::string Name;
long long Start, End;
uint64_t ThreadID;
};
class Instrumentor {
private:
std::string m_SessionName;
std::ofstream m_OutputStream;
int m_ProfileCount;
std::mutex m_Lock;
bool m_ActiveSession;
public:
~Instrumentor() {
EndSession();
}
Instrumentor(const Instrumentor &) = delete;
static void BeginSession(const std::string &name, const std::string &filepath = "Results.json") {
GetInstance().BeginSessionImpl(name, filepath);
}
static void EndSession() {
GetInstance().EndSessionImpl();
}
static void WriteProfile(const ProfileResult &result) {
GetInstance().WriteProfileImlp(result);
}
private:
Instrumentor()
: m_SessionName("None"), m_ProfileCount(0), m_ActiveSession(false) {
;
}
static Instrumentor &GetInstance() {
static Instrumentor instance;
return instance;
}
void BeginSessionImpl(const std::string &name, const std::string &filepath = "Results.json") {
if (m_ActiveSession) {
EndSession();
}
m_ActiveSession = true;
m_SessionName = name;
m_OutputStream.open(m_SessionName + std::string("_") + filepath);
WriteHeader();
}
void EndSessionImpl() {
if (!m_ActiveSession) {
return;
}
m_ActiveSession = false;
m_ProfileCount = 0;
WriteFooter();
m_OutputStream.close();
}
void WriteHeader() {
m_OutputStream << "{\"otherData\": {},\"traceEvents\":[";
m_OutputStream.flush();
}
void WriteFooter() {
m_OutputStream << "]}";
m_OutputStream.flush();
}
void WriteProfileImlp(const ProfileResult &result) {
std::lock_guard<std::mutex> lockGuard(m_Lock);
if (m_ProfileCount++ > 0)
m_OutputStream << ",";
std::string name = result.Name;
std::replace(name.begin(), name.end(), '"', '\'');
m_OutputStream << "{";
m_OutputStream << "\"cat\":\"function\",";
m_OutputStream << "\"dur\":" << (result.End - result.Start) << ',';
m_OutputStream << "\"name\":\"" << name << "\",";
m_OutputStream << "\"ph\":\"X\",";
m_OutputStream << "\"pid\":\"" << m_SessionName << "\",";
m_OutputStream << "\"tid\":" << result.ThreadID << ",";
m_OutputStream << "\"ts\":" << result.Start;
m_OutputStream << "}";
m_OutputStream.flush();
}
};
class InstrumentationTimer {
private:
const char *m_Name;
std::chrono::time_point<std::chrono::high_resolution_clock> m_StartTimepoint;
bool m_Stopped;
public:
explicit InstrumentationTimer(const char *name)
: m_Name(name), m_Stopped(false) {
m_StartTimepoint = std::chrono::high_resolution_clock::now();
}
~InstrumentationTimer() {
if (!m_Stopped) {
Stop();
}
}
void Stop() {
auto endTimepoint = std::chrono::high_resolution_clock::now();
long long start = std::chrono::time_point_cast<std::chrono::microseconds>(
m_StartTimepoint).time_since_epoch().count();
long long end = std::chrono::time_point_cast<std::chrono::microseconds>(
endTimepoint).time_since_epoch().count();
uint64_t threadID = std::hash<std::thread::id>{}(std::this_thread::get_id());
Instrumentor::WriteProfile({m_Name, start, end, threadID});
m_Stopped = true;
}
};