1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  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=  0end=  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::startfunctionId));
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::endfunctionId));
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 } }  // namespace cmajor::rt
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 }