/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/CodeGen/PerfMonitor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | //===----------------------------------------------------------------------===// |
10 | | |
11 | | #include "polly/CodeGen/PerfMonitor.h" |
12 | | #include "polly/CodeGen/RuntimeDebugBuilder.h" |
13 | | #include "polly/ScopInfo.h" |
14 | | #include "llvm/ADT/Triple.h" |
15 | | #include "llvm/IR/Intrinsics.h" |
16 | | #include <sstream> |
17 | | |
18 | | using namespace llvm; |
19 | | using namespace polly; |
20 | | |
21 | 3 | Function *PerfMonitor::getAtExit() { |
22 | 3 | const char *Name = "atexit"; |
23 | 3 | Function *F = M->getFunction(Name); |
24 | 3 | |
25 | 3 | if (!F) { |
26 | 3 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
27 | 3 | FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), |
28 | 3 | {Builder.getInt8PtrTy()}, false); |
29 | 3 | F = Function::Create(Ty, Linkage, Name, M); |
30 | 3 | } |
31 | 3 | |
32 | 3 | return F; |
33 | 3 | } |
34 | | |
35 | 3 | void PerfMonitor::addToGlobalConstructors(Function *Fn) { |
36 | 3 | const char *Name = "llvm.global_ctors"; |
37 | 3 | GlobalVariable *GV = M->getGlobalVariable(Name); |
38 | 3 | std::vector<Constant *> V; |
39 | 3 | |
40 | 3 | if (GV) { |
41 | 0 | Constant *Array = GV->getInitializer(); |
42 | 0 | for (Value *X : Array->operand_values()) |
43 | 0 | V.push_back(cast<Constant>(X)); |
44 | 0 | GV->eraseFromParent(); |
45 | 0 | } |
46 | 3 | |
47 | 3 | StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(), |
48 | 3 | Builder.getInt8PtrTy()); |
49 | 3 | |
50 | 3 | V.push_back( |
51 | 3 | ConstantStruct::get(ST, Builder.getInt32(10), Fn, |
52 | 3 | ConstantPointerNull::get(Builder.getInt8PtrTy()))); |
53 | 3 | ArrayType *Ty = ArrayType::get(ST, V.size()); |
54 | 3 | |
55 | 3 | GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage, |
56 | 3 | ConstantArray::get(Ty, V), Name, nullptr, |
57 | 3 | GlobalVariable::NotThreadLocal); |
58 | 3 | } |
59 | | |
60 | 16 | Function *PerfMonitor::getRDTSCP() { |
61 | 16 | return Intrinsic::getDeclaration(M, Intrinsic::x86_rdtscp); |
62 | 16 | } |
63 | | |
64 | | PerfMonitor::PerfMonitor(const Scop &S, Module *M) |
65 | 5 | : M(M), Builder(M->getContext()), S(S) { |
66 | 5 | if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64) |
67 | 5 | Supported = true; |
68 | 0 | else |
69 | 0 | Supported = false; |
70 | 5 | } |
71 | | |
72 | | static void TryRegisterGlobal(Module *M, const char *Name, |
73 | 30 | Constant *InitialValue, Value **Location) { |
74 | 30 | *Location = M->getGlobalVariable(Name); |
75 | 30 | |
76 | 30 | if (!*Location) |
77 | 22 | *Location = new GlobalVariable( |
78 | 22 | *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage, |
79 | 22 | InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel); |
80 | 30 | } |
81 | | |
82 | | // Generate a unique name that is usable as a LLVM name for a scop to name its |
83 | | // performance counter. |
84 | 5 | static std::string GetScopUniqueVarname(const Scop &S) { |
85 | 5 | std::stringstream Name; |
86 | 5 | std::string EntryString, ExitString; |
87 | 5 | std::tie(EntryString, ExitString) = S.getEntryExitStr(); |
88 | 5 | |
89 | 5 | Name << "__polly_perf_in_" << std::string(S.getFunction().getName()) |
90 | 5 | << "_from__" << EntryString << "__to__" << ExitString; |
91 | 5 | return Name.str(); |
92 | 5 | } |
93 | | |
94 | 5 | void PerfMonitor::addScopCounter() { |
95 | 5 | const std::string varname = GetScopUniqueVarname(S); |
96 | 5 | TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0), |
97 | 5 | &CyclesInCurrentScopPtr); |
98 | 5 | |
99 | 5 | TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0), |
100 | 5 | &TripCountForCurrentScopPtr); |
101 | 5 | } |
102 | | |
103 | 5 | void PerfMonitor::addGlobalVariables() { |
104 | 5 | TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0), |
105 | 5 | &CyclesTotalStartPtr); |
106 | 5 | |
107 | 5 | TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(0), |
108 | 5 | &AlreadyInitializedPtr); |
109 | 5 | |
110 | 5 | TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0), |
111 | 5 | &CyclesInScopsPtr); |
112 | 5 | |
113 | 5 | TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0), |
114 | 5 | &CyclesInScopStartPtr); |
115 | 5 | } |
116 | | |
117 | | static const char *InitFunctionName = "__polly_perf_init"; |
118 | | static const char *FinalReportingFunctionName = "__polly_perf_final"; |
119 | | |
120 | | static BasicBlock *FinalStartBB = nullptr; |
121 | | static ReturnInst *ReturnFromFinal = nullptr; |
122 | | |
123 | 3 | Function *PerfMonitor::insertFinalReporting() { |
124 | 3 | // Create new function. |
125 | 3 | GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; |
126 | 3 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); |
127 | 3 | Function *ExitFn = |
128 | 3 | Function::Create(Ty, Linkage, FinalReportingFunctionName, M); |
129 | 3 | FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn); |
130 | 3 | Builder.SetInsertPoint(FinalStartBB); |
131 | 3 | |
132 | 3 | if (!Supported) { |
133 | 0 | RuntimeDebugBuilder::createCPUPrinter( |
134 | 0 | Builder, "Polly runtime information generation not supported\n"); |
135 | 0 | Builder.CreateRetVoid(); |
136 | 0 | return ExitFn; |
137 | 0 | } |
138 | 3 | |
139 | 3 | // Measure current cycles and compute final timings. |
140 | 3 | Function *RDTSCPFn = getRDTSCP(); |
141 | 3 | |
142 | 3 | Value *CurrentCycles = |
143 | 3 | Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); |
144 | 3 | Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true); |
145 | 3 | Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart); |
146 | 3 | Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true); |
147 | 3 | |
148 | 3 | // Print the runtime information. |
149 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n"); |
150 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n"); |
151 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n"); |
152 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops, |
153 | 3 | "\n"); |
154 | 3 | |
155 | 3 | // Print the preamble for per-scop information. |
156 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "\n"); |
157 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n"); |
158 | 3 | RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n"); |
159 | 3 | |
160 | 3 | RuntimeDebugBuilder::createCPUPrinter( |
161 | 3 | Builder, "scop function, " |
162 | 3 | "entry block name, exit block name, total time, trip count\n"); |
163 | 3 | ReturnFromFinal = Builder.CreateRetVoid(); |
164 | 3 | return ExitFn; |
165 | 3 | } |
166 | | |
167 | 5 | void PerfMonitor::AppendScopReporting() { |
168 | 5 | if (!Supported) |
169 | 0 | return; |
170 | 5 | |
171 | 5 | assert(FinalStartBB && "Expected FinalStartBB to be initialized by " |
172 | 5 | "PerfMonitor::insertFinalReporting."); |
173 | 5 | assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by " |
174 | 5 | "PerfMonitor::insertFinalReporting."); |
175 | 5 | |
176 | 5 | Builder.SetInsertPoint(FinalStartBB); |
177 | 5 | ReturnFromFinal->eraseFromParent(); |
178 | 5 | |
179 | 5 | Value *CyclesInCurrentScop = |
180 | 5 | Builder.CreateLoad(this->CyclesInCurrentScopPtr, true); |
181 | 5 | |
182 | 5 | Value *TripCountForCurrentScop = |
183 | 5 | Builder.CreateLoad(this->TripCountForCurrentScopPtr, true); |
184 | 5 | |
185 | 5 | std::string EntryName, ExitName; |
186 | 5 | std::tie(EntryName, ExitName) = S.getEntryExitStr(); |
187 | 5 | |
188 | 5 | // print in CSV for easy parsing with other tools. |
189 | 5 | RuntimeDebugBuilder::createCPUPrinter( |
190 | 5 | Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ", |
191 | 5 | CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n"); |
192 | 5 | |
193 | 5 | ReturnFromFinal = Builder.CreateRetVoid(); |
194 | 5 | } |
195 | | |
196 | | static Function *FinalReporting = nullptr; |
197 | | |
198 | 5 | void PerfMonitor::initialize() { |
199 | 5 | addGlobalVariables(); |
200 | 5 | addScopCounter(); |
201 | 5 | |
202 | 5 | // Ensure that we only add the final reporting function once. |
203 | 5 | // On later invocations, append to the reporting function. |
204 | 5 | if (!FinalReporting) { |
205 | 3 | FinalReporting = insertFinalReporting(); |
206 | 3 | |
207 | 3 | Function *InitFn = insertInitFunction(FinalReporting); |
208 | 3 | addToGlobalConstructors(InitFn); |
209 | 3 | } |
210 | 5 | |
211 | 5 | AppendScopReporting(); |
212 | 5 | } |
213 | | |
214 | 3 | Function *PerfMonitor::insertInitFunction(Function *FinalReporting) { |
215 | 3 | // Insert function definition and BBs. |
216 | 3 | GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; |
217 | 3 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); |
218 | 3 | Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M); |
219 | 3 | BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn); |
220 | 3 | BasicBlock *EarlyReturn = |
221 | 3 | BasicBlock::Create(M->getContext(), "earlyreturn", InitFn); |
222 | 3 | BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn); |
223 | 3 | |
224 | 3 | Builder.SetInsertPoint(Start); |
225 | 3 | |
226 | 3 | // Check if this function was already run. If yes, return. |
227 | 3 | // |
228 | 3 | // In case profiling has been enabled in multiple translation units, the |
229 | 3 | // initializer function will be added to the global constructors list of |
230 | 3 | // each translation unit. When merging translation units, the global |
231 | 3 | // constructor lists are just appended, such that the initializer will appear |
232 | 3 | // multiple times. To avoid initializations being run multiple times (and |
233 | 3 | // especially to avoid that atExitFn is called more than once), we bail |
234 | 3 | // out if the initializer is run more than once. |
235 | 3 | Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr); |
236 | 3 | Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB); |
237 | 3 | Builder.SetInsertPoint(EarlyReturn); |
238 | 3 | Builder.CreateRetVoid(); |
239 | 3 | |
240 | 3 | // Keep track that this function has been run once. |
241 | 3 | Builder.SetInsertPoint(InitBB); |
242 | 3 | Value *True = Builder.getInt1(true); |
243 | 3 | Builder.CreateStore(True, AlreadyInitializedPtr); |
244 | 3 | |
245 | 3 | // Register the final reporting function with atexit(). |
246 | 3 | Value *FinalReportingPtr = |
247 | 3 | Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy()); |
248 | 3 | Function *AtExitFn = getAtExit(); |
249 | 3 | Builder.CreateCall(AtExitFn, {FinalReportingPtr}); |
250 | 3 | |
251 | 3 | if (Supported) { |
252 | 3 | // Read the currently cycle counter and store the result for later. |
253 | 3 | Function *RDTSCPFn = getRDTSCP(); |
254 | 3 | Value *CurrentCycles = |
255 | 3 | Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); |
256 | 3 | Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true); |
257 | 3 | } |
258 | 3 | Builder.CreateRetVoid(); |
259 | 3 | |
260 | 3 | return InitFn; |
261 | 3 | } |
262 | | |
263 | 5 | void PerfMonitor::insertRegionStart(Instruction *InsertBefore) { |
264 | 5 | if (!Supported) |
265 | 0 | return; |
266 | 5 | |
267 | 5 | Builder.SetInsertPoint(InsertBefore); |
268 | 5 | Function *RDTSCPFn = getRDTSCP(); |
269 | 5 | Value *CurrentCycles = |
270 | 5 | Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); |
271 | 5 | Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true); |
272 | 5 | } |
273 | | |
274 | 5 | void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) { |
275 | 5 | if (!Supported) |
276 | 0 | return; |
277 | 5 | |
278 | 5 | Builder.SetInsertPoint(InsertBefore); |
279 | 5 | Function *RDTSCPFn = getRDTSCP(); |
280 | 5 | LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true); |
281 | 5 | Value *CurrentCycles = |
282 | 5 | Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); |
283 | 5 | Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart); |
284 | 5 | Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true); |
285 | 5 | CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop); |
286 | 5 | Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true); |
287 | 5 | |
288 | 5 | Value *CyclesInCurrentScop = Builder.CreateLoad(CyclesInCurrentScopPtr, true); |
289 | 5 | CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop); |
290 | 5 | Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true); |
291 | 5 | |
292 | 5 | Value *TripCountForCurrentScop = |
293 | 5 | Builder.CreateLoad(TripCountForCurrentScopPtr, true); |
294 | 5 | TripCountForCurrentScop = |
295 | 5 | Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1)); |
296 | 5 | Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr, |
297 | 5 | true); |
298 | 5 | } |