-
Notifications
You must be signed in to change notification settings - Fork 2
/
Profile.h
142 lines (116 loc) · 3.81 KB
/
Profile.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
/**
* @file Profile.h
* @author Jeff Kiah
*/
#pragma once
#ifndef GRIFFIN_PROFILE_H
#define GRIFFIN_PROFILE_H
#include <cstdint>
#include <string>
#include <utility/auto_lister.h>
#include "ProfileAggregate.h"
#include <utility/concurrency.h>
#include <boost/container/flat_map.hpp>
using boost::container::flat_map;
using namespace std;
// Macros
#if defined(GRIFFIN_PROFILE) && (GRIFFIN_PROFILE == 1)
#define PROFILE_BLOCK(name, frame, thread) griffin::Profile<thread> profile_(frame, name, __FILE__, __LINE__);
#else
#define PROFILE_BLOCK(...)
#endif
namespace griffin {
typedef flat_map<intptr_t, ProfileAggregate> ProfileAggregateMap;
extern monitor<ProfileAggregateMap> g_aggregates;
/**
* @class Profile
* Profile is an RAII-type container meant to be placed on the stack and will time from
* creation to destruction.
*
* Profile must be thread safe but should not introduce locks that increase contention of the
* normally running program. For this reason, unique storage is required for each thread that
* is profiled, including a separate stack of Profiles and a separate ProfileAggregate. A
* master index of references to all thread-specific lists is kept. This can be problematic for
* thread pools when the same task can be picked up by any worker thread at random. The
* information for one task will be spread over several lists, but you would actually want to
* see it combined into one aggregated entry. A post processing step could look at all of the
* thread lists and combine split profiles by name, and also indicate how many unique threads
* the profile was run on over its lifetime.
*
* std::this_thread::get_id().hash() is used to index each thread in the master map
*/
template <int Th>
struct Profile : auto_stacker<Profile<Th>> {
int64_t m_frame; //!< frame the code block is called on
int64_t m_startCounts; //!< counts at start of profiling block
const char* m_name; //!< name of this profile
const char* m_file; //!< source file (from macro)
int m_line; //!< line number of profile start (from macro)
/**
* Constructor
* @param frame frame number of profiling step
* @param name unique name of this profile block
* @param file source file of the profile block
* @param line line number of the profile block start
*/
Profile(int64_t frame, const char* name, const char* file, int line);
/**
* Destructor
*/
~Profile();
/**
*
*/
const char* getParentName() const;
/**
* get the full path of nested profile blocks
*/
std::string getPath() const;
};
// TEMP
template <int Th>
Profile<Th>::Profile(int64_t frame, const char* name, const char* file, int line) :
m_frame{ frame },
m_name{ name },
m_file{ file },
m_line{ line }
{
m_startCounts = Timer::queryCounts();
}
template <int Th>
Profile<Th>::~Profile() {
auto countsPassed = Timer::countsSince(m_startCounts);
//auto threadIdHash = this_thread::get_id().hash();
//auto& threadAggregates = getThreadAggregates(threadIdHash);
g_aggregates([=](ProfileAggregateMap& aggMap) {
// thread safe function
auto size = aggMap.size();
auto& agg = aggMap[reinterpret_cast<intptr_t>(m_name)]; // get or create the block aggregate
if (aggMap.size() == size + 1) { // if newly created
agg.init(m_name, getParentName(), getPath());
}
agg.invoke(countsPassed, m_frame);
});
}
template <int Th>
const char* Profile<Th>::getParentName() const {
const char* parentName = nullptr;
auto s = stack().size();
if (s > 1) {
auto parent = stack()[s - 2];
parentName = parent->m_name;
}
return parentName;
}
template <int Th>
string Profile<Th>::getPath() const {
string path;
path.reserve(100);
for (auto p : stack()) {
path.append(p->m_name);
if (p != this) { path.append("/"); }
}
return std::move(path);
}
}
#endif