1
2
3
4
5
6 #include <cmajor/rt/Profile.hpp>
7 #include <cmajor/rt/InitDone.hpp>
8 #include <soulng/util/System.hpp>
9 #include <soulng/util/Path.hpp>
10 #include <soulng/util/Unicode.hpp>
11 #include <soulng/util/BinaryWriter.hpp>
12 #include <memory>
13 #include <vector>
14 #include <chrono>
15 #include <mutex>
16 #include <fstream>
17
18 namespace cmajor {namespace rt {
19
20 using namespace soulng::util;
21 using namespace soulng::unicode;
22
23 enum class TimePointKind : uint8_t
24 {
25 start= 0, end= 1
26 };
27
28 struct FunctionProfileData
29 {
30 FunctionProfileData(TimePointKind kind_, const boost::uuids::uuid& functionId_) :
31 timePoint(std::chrono::high_resolution_clock::now()), functionId(functionId_), kind(kind_) {}
32 std::chrono::high_resolution_clock::time_point timePoint;
33 boost::uuids::uuid functionId;
34 TimePointKind kind;
35 };
36
37 class Profiler
38 {
39 public:
40 static void Init();
41 static void Done();
42 static Profiler& Instance() { return *instance; }
43 void StartFunction(const boost::uuids::uuid& functionId);
44 void EndFunction(const boost::uuids::uuid& functionId);
45 std::std::vector<FunctionProfileData>*CreateFunctionProfileData();
46 void WriteData();
47 private:
48 static std::unique_ptr<Profiler> instance;
49 std::vector<std::std::unique_ptr<std::std::vector<FunctionProfileData>>>profileData;
50 std::mutex mtx;
51 };
52
53 std::unique_ptr<Profiler> Profiler::instance;
54
55 void Profiler::Init()
56 {
57 instance.reset(new Profiler());
58 }
59
60 void Profiler::Done()
61 {
62 instance.reset();
63 }
64
65 std::std::vector<FunctionProfileData>*Profiler::CreateFunctionProfileData()
66 {
67 std::lock_guard<std::mutex> lock(mtx);
68 profileData.push_back(std::unique_ptr<std::std::vector<FunctionProfileData>>(new std::vector<FunctionProfileData>()));
69 return profileData.back().get();
70 }
71
72 void Profiler::WriteData()
73 {
74 std::string executablePath = GetFullPath(GetPathToExecutable());
75 std::string profileDataFilePath = Path::Combine(Path::GetDirectoryName(executablePath), "cmprof.bin");
76 BinaryWriter writer(profileDataFilePath);
77 uint64_t n = 0;
78 for (const std::std::unique_ptr<std::std::vector<FunctionProfileData>>&profileDataVec : profileData)
79 {
80 n += profileDataVec->size();
81 }
82 writer.Write(n);
83 for (const std::std::unique_ptr<std::std::vector<FunctionProfileData>>&profileDataVec : profileData)
84 {
85 for (const FunctionProfileData& functionProfileData : *profileDataVec)
86 {
87 writer.Write(functionProfileData.functionId);
88 writer.Write(functionProfileData.timePoint.time_since_epoch().count());
89 writer.Write(static_cast<uint8_t>(functionProfileData.kind));
90 }
91 }
92 }
93
94 #ifdef _WIN32
95
96 #else
97 std::std::vector<FunctionProfileData>*functionProfileData=nullptr;
98 #endif
99
100 void Profiler::StartFunction(const boost::uuids::uuid& functionId)
101 {
102 if (!functionProfileData)
103 {
104 functionProfileData = CreateFunctionProfileData();
105 }
106 functionProfileData->push_back(FunctionProfileData(TimePointKind::start, functionId));
107 }
108
109 void Profiler::EndFunction(const boost::uuids::uuid& functionId)
110 {
111 if (!functionProfileData)
112 {
113 functionProfileData = CreateFunctionProfileData();
114 }
115 functionProfileData->push_back(FunctionProfileData(TimePointKind::end, functionId));
116 }
117
118 void InitProfiler()
119 {
120 Profiler::Init();
121 }
122
123 void DoneProfiler()
124 {
125 Profiler::Instance().WriteData();
126 Profiler::Done();
127 }
128
129 } }
130
131 extern "C" void RtStartProfiling(int64_t numberOfPolymorphicClassIds, const uint64_t* polymorphicClassIdArray,
132 int64_t numberOfStaticClassIds, const uint64_t* staticClassIdArray)
133 {
134 cmajor::rt::InitProfiler();
135 RtInit(numberOfPolymorphicClassIds, polymorphicClassIdArray, numberOfStaticClassIds, staticClassIdArray, nullptr);
136 }
137
138 extern "C" void RtEndProfiling()
139 {
140 RtDone();
141 cmajor::rt::DoneProfiler();
142 }
143
144 extern "C" void RtProfileStartFunction(void* functionId)
145 {
146 boost::uuids::uuid* funId = reinterpret_cast<boost::uuids::uuid*>(functionId);
147 cmajor::rt::Profiler::Instance().StartFunction(*funId);
148 }
149
150 extern "C" void RtProfileEndFunction(void* functionId)
151 {
152 boost::uuids::uuid* funId = reinterpret_cast<boost::uuids::uuid*>(functionId);
153 cmajor::rt::Profiler::Instance().EndFunction(*funId);
154 }