Proteus
Programmable JIT compilation and optimization for C/C++ using LLVM
Loading...
Searching...
No Matches
CompilerAsync.hpp
Go to the documentation of this file.
1#ifndef PROTEUS_ASYNC_COMPILER_HPP
2#define PROTEUS_ASYNC_COMPILER_HPP
3
4#include <condition_variable>
5#include <deque>
6#include <thread>
7
9#include "proteus/Debug.h"
10#include "proteus/Hashing.hpp"
11
12namespace proteus {
13
14using namespace llvm;
15
17public:
18 explicit CompilationResult() : IsReadyFlag{false} {}
19
22
23 CompilationResult(CompilationResult &&) noexcept = delete;
24 CompilationResult &operator=(CompilationResult &&) noexcept = delete;
25
26 bool isReady() { return IsReadyFlag; }
27
28 void set(std::unique_ptr<MemoryBuffer> ObjBuf) {
29 ResultObjBuf = std::move(ObjBuf);
30 IsReadyFlag = true;
31 }
32
33 void wait() {
34 // Busy wait until it's ready.
35 while (!IsReadyFlag) {
36 std::this_thread::yield();
37 }
38 }
39
40 std::unique_ptr<MemoryBuffer> take() { return std::move(ResultObjBuf); }
41
42private:
43 std::atomic<bool> IsReadyFlag;
44 std::unique_ptr<MemoryBuffer> ResultObjBuf;
45};
46
48public:
49 static CompilerAsync &instance(int NumThreads) {
50 static CompilerAsync Singleton{NumThreads};
51 return Singleton;
52 }
53
55 std::unique_lock Lock{Mutex};
56 Worklist.emplace_back(std::move(CT));
57 CompilationResultMap.emplace(CT.getHashValue(),
58 std::make_unique<CompilationResult>());
59 CondVar.notify_one();
60 }
61
62 void run() {
63 [[maybe_unused]] int Count = 0;
64 while (Active) {
65 std::unique_lock Lock(Mutex);
66 CondVar.wait(Lock, [this] { return !Worklist.empty() || !Active; });
67 if (!Active)
68 break;
69 if (Worklist.empty())
70 PROTEUS_FATAL_ERROR("Expected non-empty Worklist");
71 CompilationTask CT = std::move(Worklist.front());
72 Worklist.pop_front();
73 Lock.unlock();
74
75 Count++;
76 std::unique_ptr<MemoryBuffer> ObjBuf = CT.compile();
77 Lock.lock();
78 CompilationResultMap.at(CT.getHashValue())->set(std::move(ObjBuf));
79 Lock.unlock();
80 }
81
82 PROTEUS_DBG(Logger::logs("proteus")
83 << "Thread exiting! Compiled " + std::to_string(Count) + "\n");
84 }
85
87 Active = false;
88 CondVar.notify_all();
89
90 for (auto &Thread : Threads)
91 Thread.join();
92
93 Threads.clear();
94 }
95
96 bool isCompilationPending(HashT HashValue) {
97 std::unique_lock Lock{Mutex};
98 return !(CompilationResultMap.find(HashValue) ==
99 CompilationResultMap.end());
100 }
101
102 std::unique_ptr<MemoryBuffer> takeCompilationResult(HashT HashValue,
103 bool BlockingWait) {
104 std::unique_lock Lock{Mutex};
105 auto It = CompilationResultMap.find(HashValue);
106 if (It == CompilationResultMap.end())
107 return nullptr;
108
109 std::unique_ptr<CompilationResult> &CRes = It->second;
110 Lock.unlock();
111
112 if (BlockingWait)
113 CRes->wait();
114 else {
115 if (!CRes->isReady())
116 return nullptr;
117 }
118
119 // If compilation result is ready, take ownership of the buffer, erase it
120 // from the compilation results map and move the buffer to the caller.
121 std::unique_ptr<MemoryBuffer> ObjBuf = CRes->take();
122 Lock.lock();
123 // Use the HashValue key as the iterator may have been invalidated by
124 // insert/emplace from another thread.
125 CompilationResultMap.erase(HashValue);
126 Lock.unlock();
127 return ObjBuf;
128 }
129
130private:
131 std::atomic<bool> Active;
132 std::mutex Mutex;
133 std::condition_variable CondVar;
134 std::unordered_map<HashT, std::unique_ptr<CompilationResult>>
135 CompilationResultMap;
136 std::deque<CompilationTask> Worklist;
137 std::vector<std::thread> Threads;
138
139 CompilerAsync(int NumThreads) {
140 Active = true;
141 for (int I = 0; I < NumThreads; ++I)
142 Threads.emplace_back(&CompilerAsync::run, this);
143 }
144
145 ~CompilerAsync() {
146 if (Threads.size() > 0)
148 }
149};
150
151} // namespace proteus
152
153#endif
#define PROTEUS_DBG(x)
Definition Debug.h:7
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:4
Definition CompilerAsync.hpp:16
CompilationResult(CompilationResult &&) noexcept=delete
void set(std::unique_ptr< MemoryBuffer > ObjBuf)
Definition CompilerAsync.hpp:28
bool isReady()
Definition CompilerAsync.hpp:26
CompilationResult(const CompilationResult &)=delete
CompilationResult & operator=(const CompilationResult &)=delete
std::unique_ptr< MemoryBuffer > take()
Definition CompilerAsync.hpp:40
void wait()
Definition CompilerAsync.hpp:33
CompilationResult()
Definition CompilerAsync.hpp:18
Definition CompilationTask.hpp:17
HashT getHashValue() const
Definition CompilationTask.hpp:82
std::unique_ptr< MemoryBuffer > compile()
Definition CompilationTask.hpp:84
Definition CompilerAsync.hpp:47
bool isCompilationPending(HashT HashValue)
Definition CompilerAsync.hpp:96
static CompilerAsync & instance(int NumThreads)
Definition CompilerAsync.hpp:49
void compile(CompilationTask &&CT)
Definition CompilerAsync.hpp:54
std::unique_ptr< MemoryBuffer > takeCompilationResult(HashT HashValue, bool BlockingWait)
Definition CompilerAsync.hpp:102
void joinAllThreads()
Definition CompilerAsync.hpp:86
void run()
Definition CompilerAsync.hpp:62
Definition Hashing.hpp:19
static llvm::raw_ostream & logs(const std::string &Name)
Definition Logger.hpp:18
Definition JitEngine.cpp:20