-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Profiler.hpp
160 lines (132 loc) · 3.81 KB
/
Profiler.hpp
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
// ******************************
//
// Copyright CosmoEngine (C) 2024 CyberKoala LLC
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// ******************************
//
// #include <Profiler.hpp>
//
// int anyFunc()
// {
// PROFILE_FUNCTION();
// // Any scope
// {
// PROFILE_SCOPE("This is scope for file loading");
// }
// }
//
// Then run .exe file
// Drag and drop results.json into edge://tracing/
// Happy profiling!
#pragma once
#include <fstream>
#include <chrono>
#include <mutex>
#include <map>
#include <string>
#include <algorithm>
#include <thread>
// Comment this on Production Shipping
#define PROFILING 1
#ifdef PROFILING
#define PROFILE_SCOPE(name) \
ProfileTimer timer##__LINE__(name)
#define PROFILE_FUNCTION() \
PROFILE_SCOPE(__FUNCTION__)
#else
#define PROFILE_SCOPE(name)
#define PROFILE_FUNCTION()
#endif
struct ProfileResult
{
const std::string name = "Default";
long long start = 0;
long long end = 0;
size_t threadId = 0;
};
class Profiler
{
std::string m_outputFile = "results.json";
size_t m_profileCount = 0;
std::ofstream m_outputStream;
std::mutex m_lock;
Profiler()
{
m_outputStream = std::ofstream(m_outputFile);
writeHeader();
}
void writeHeader() { m_outputStream << "{\"otherData\": {},\"traceEvents\":["; }
void writeFooter() { m_outputStream << "]}"; }
public:
static Profiler& Instance()
{
static Profiler instance;
return instance;
}
void writeProfile(const ProfileResult & result)
{
std::lock_guard<std::mutex> lock(m_lock);
if (m_profileCount++ > 0) { m_outputStream << ","; }
std::string name = result.name;
std::replace(name.begin(), name.end(), '"', '\'');
m_outputStream << "\n{";
m_outputStream << "\"cat\":\"function\",";
m_outputStream << "\"dur\":" << (result.end - result.start) << ',';
m_outputStream << "\"name\":\"" << name << "\",";
m_outputStream << "\"ph\":\"X\",";
m_outputStream << "\"pid\":0,";
m_outputStream << "\"tid\":" << result.threadId << ",";
m_outputStream << "\"ts\":" << result.start;
m_outputStream << "}";
}
~Profiler()
{
writeFooter();
}
};
class ProfileTimer
{
typedef std::chrono::time_point<std::chrono::high_resolution_clock> ClockType;
ClockType m_startTimepoint;
ProfileResult m_result;
bool m_stopped = false;
public:
ProfileTimer(const std::string& name)
:m_result({name, 0,0,0})
{
start();
}
~ProfileTimer() { stop(); }
// This function is used to set the start time
// It adds 1 time unit if its the same start time as the previous start time
// this solves a display issue in edge://tracing chrome://tracing for identical start times
// this is a 2/10 on the janky fix scale but it has worked
void start()
{
// a static var to store the last time recorded
static long long lastStartTime = 0;
// Grab the actual start time using chrono
m_startTimepoint = std::chrono::high_resolution_clock::now();
m_result.start = std::chrono::time_point_cast<std::chrono::microseconds>(m_startTimepoint).time_since_epoch().count();
// if its the same as prev start time, add 1 to it
m_result.start += (m_result.start == lastStartTime ? 1 : 0);
// record the fixed time as the previous start time
lastStartTime = m_result.start;
m_stopped = false;
}
void stop()
{
if (m_stopped) { return; }
m_stopped = false;
auto endTimepoint = std::chrono::high_resolution_clock::now();
m_result.end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint).time_since_epoch().count();
m_result.threadId = std::hash<std::thread::id>{}(std::this_thread::get_id());
Profiler::Instance().writeProfile(m_result);
m_stopped = true;
}
};