-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathProfiler.h
More file actions
143 lines (132 loc) · 3.61 KB
/
Profiler.h
File metadata and controls
143 lines (132 loc) · 3.61 KB
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
// vim: set noet ts=4 sts=4 sw=4:
#pragma once
#include <vector>
#include <ostream>
#include <iomanip>
#include <cstdio>
namespace profiler {
class single_profiler;
class profiler {
std::vector<const single_profiler *> profs;
int indent;
profiler() { }
const std::string format_time(double v) const {
char buf[1024];
if (v < 1e-6)
sprintf(buf, "%8.2lfns", 1e9 * v);
else if (v < 1e-3)
sprintf(buf, "%8.2lfus", 1e6 * v);
else if (v < 1)
sprintf(buf, "%8.2lfms", 1e3 * v);
else
sprintf(buf, "%8.2lfs ", v);
return std::string(buf);
}
public:
static profiler &getInstance() {
static profiler instance;
return instance;
}
void reg(const single_profiler *prof) {
profs.push_back(prof);
}
int enter() { return indent++; }
void leave() { indent--; }
std::ostream &print(std::ostream &o, int fnwidth) const;
profiler(const profiler &) = delete;
profiler(profiler &&) = delete;
profiler &operator=(const profiler &) = delete;
};
inline const profiler &getInstance() {
return profiler::getInstance();
}
class single_profiler {
timespec startmark;
int _calls;
double tottime;
int depth;
int indent;
void start() {
clock_gettime(CLOCK_MONOTONIC_RAW, &startmark);
}
double stop() {
timespec stopmark;
clock_gettime(CLOCK_MONOTONIC_RAW, &stopmark);
int nsec = stopmark.tv_nsec - startmark.tv_nsec;
int sec = stopmark.tv_sec - startmark.tv_sec;
return sec + 1e-9 * nsec;
}
const std::string _filename;
const std::string _pretty_function;
const int _line_number;
public:
single_profiler(const char *fn, const int line, const char *func)
: _calls(0), tottime(0), depth(0), _filename(fn)
, _pretty_function(func), _line_number(line)
{
profiler::getInstance().reg(this);
}
void enter() {
_calls++;
if (depth > 0)
tottime += stop(); // suspend
else
indent = profiler::getInstance().enter();
depth++;
start();
}
void leave() {
tottime += stop();
depth--;
if (depth > 0)
start(); // resume
else
profiler::getInstance().leave();
}
const std::string &filename() const { return _filename; }
int line_number() const { return _line_number; }
const std::string function() const { return std::string(indent, ' ') + _pretty_function; }
int calls() const { return _calls; }
double total_time() const { return tottime; }
};
template<typename T>
void profile_gate(const char *fn, const int line, const char *func, bool enter, T *) {
static single_profiler prof(fn, line, func);
if (enter)
prof.enter();
else
prof.leave();
}
inline std::ostream &profiler::print(std::ostream &o, int fnwidth) const {
o << "\n" << std::left << std::setw(fnwidth) << "function";
o << "line calls tottime avgtime\n\n";
for (const single_profiler *p : profs) {
o << std::left << std::setfill('.') << std::setw(fnwidth) << p->function() << std::setfill(' ')
<< " " << std::setw(8) << p->line_number()
<< " " << std::setw(8) << p->calls() << " "
<< format_time(p->total_time()) << " " << format_time(p->total_time() / p->calls()) << "\n";
}
return o;
}
inline std::ostream &operator<<(std::ostream &o, const profiler &prof) {
return prof.print(o, 120);
}
}
#define PROFILE_ME_AS(name) \
struct __prof_data { bool early_exit; \
__prof_data(const char *fn, const int line, const char *func) { \
early_exit = false; \
profiler::profile_gate(fn, line, func, true, this); \
} \
void stop() { \
early_exit = true; \
profiler::profile_gate(nullptr, -1, nullptr, false, this); \
} \
~__prof_data() { \
if (!early_exit) \
stop(); \
} \
} __helper_var(__FILE__, __LINE__, name)
#define PROFILE_ME PROFILE_ME_AS(__PRETTY_FUNCTION__)
#define PROFILE_END \
__helper_var.stop()