165371af2STobias Grosser //===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======//
265371af2STobias Grosser //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
665371af2STobias Grosser //
765371af2STobias Grosser //===----------------------------------------------------------------------===//
865371af2STobias Grosser //
965371af2STobias Grosser //===----------------------------------------------------------------------===//
1065371af2STobias Grosser 
1165371af2STobias Grosser #include "polly/CodeGen/PerfMonitor.h"
1265371af2STobias Grosser #include "polly/CodeGen/RuntimeDebugBuilder.h"
1307bee290SSiddharth Bhat #include "polly/ScopInfo.h"
1465371af2STobias Grosser #include "llvm/ADT/Triple.h"
150e93f3b0SMichael Kruse #include "llvm/ADT/Twine.h"
165368f35eSHeejin Ahn #include "llvm/IR/IntrinsicsX86.h"
1765371af2STobias Grosser 
1865371af2STobias Grosser using namespace llvm;
1965371af2STobias Grosser using namespace polly;
2065371af2STobias Grosser 
getAtExit()2165371af2STobias Grosser Function *PerfMonitor::getAtExit() {
2265371af2STobias Grosser   const char *Name = "atexit";
2365371af2STobias Grosser   Function *F = M->getFunction(Name);
2465371af2STobias Grosser 
2565371af2STobias Grosser   if (!F) {
2665371af2STobias Grosser     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
2765371af2STobias Grosser     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(),
2865371af2STobias Grosser                                          {Builder.getInt8PtrTy()}, false);
2965371af2STobias Grosser     F = Function::Create(Ty, Linkage, Name, M);
3065371af2STobias Grosser   }
3165371af2STobias Grosser 
3265371af2STobias Grosser   return F;
3365371af2STobias Grosser }
3465371af2STobias Grosser 
addToGlobalConstructors(Function * Fn)3565371af2STobias Grosser void PerfMonitor::addToGlobalConstructors(Function *Fn) {
3665371af2STobias Grosser   const char *Name = "llvm.global_ctors";
3765371af2STobias Grosser   GlobalVariable *GV = M->getGlobalVariable(Name);
3865371af2STobias Grosser   std::vector<Constant *> V;
3965371af2STobias Grosser 
4065371af2STobias Grosser   if (GV) {
4165371af2STobias Grosser     Constant *Array = GV->getInitializer();
4265371af2STobias Grosser     for (Value *X : Array->operand_values())
4365371af2STobias Grosser       V.push_back(cast<Constant>(X));
4465371af2STobias Grosser     GV->eraseFromParent();
4565371af2STobias Grosser   }
4665371af2STobias Grosser 
4765371af2STobias Grosser   StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(),
48d742e5efSChandler Carruth                                    Builder.getInt8PtrTy());
4965371af2STobias Grosser 
501a2e0e64STobias Grosser   V.push_back(
511a2e0e64STobias Grosser       ConstantStruct::get(ST, Builder.getInt32(10), Fn,
52d742e5efSChandler Carruth                           ConstantPointerNull::get(Builder.getInt8PtrTy())));
5365371af2STobias Grosser   ArrayType *Ty = ArrayType::get(ST, V.size());
5465371af2STobias Grosser 
5565371af2STobias Grosser   GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage,
5665371af2STobias Grosser                           ConstantArray::get(Ty, V), Name, nullptr,
5765371af2STobias Grosser                           GlobalVariable::NotThreadLocal);
5865371af2STobias Grosser }
5965371af2STobias Grosser 
getRDTSCP()6065371af2STobias Grosser Function *PerfMonitor::getRDTSCP() {
61637be04bSTobias Grosser   return Intrinsic::getDeclaration(M, Intrinsic::x86_rdtscp);
6265371af2STobias Grosser }
6365371af2STobias Grosser 
PerfMonitor(const Scop & S,Module * M)6407bee290SSiddharth Bhat PerfMonitor::PerfMonitor(const Scop &S, Module *M)
6507bee290SSiddharth Bhat     : M(M), Builder(M->getContext()), S(S) {
6665371af2STobias Grosser   if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64)
6765371af2STobias Grosser     Supported = true;
6865371af2STobias Grosser   else
6965371af2STobias Grosser     Supported = false;
7065371af2STobias Grosser }
7165371af2STobias Grosser 
TryRegisterGlobal(Module * M,const char * Name,Constant * InitialValue,Value ** Location)7207bee290SSiddharth Bhat static void TryRegisterGlobal(Module *M, const char *Name,
7307bee290SSiddharth Bhat                               Constant *InitialValue, Value **Location) {
7465371af2STobias Grosser   *Location = M->getGlobalVariable(Name);
7565371af2STobias Grosser 
7665371af2STobias Grosser   if (!*Location)
7765371af2STobias Grosser     *Location = new GlobalVariable(
7865371af2STobias Grosser         *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage,
7965371af2STobias Grosser         InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel);
80be194d4eSMichael Kruse }
8165371af2STobias Grosser 
8207bee290SSiddharth Bhat // Generate a unique name that is usable as a LLVM name for a scop to name its
8307bee290SSiddharth Bhat // performance counter.
GetScopUniqueVarname(const Scop & S)8407bee290SSiddharth Bhat static std::string GetScopUniqueVarname(const Scop &S) {
8507bee290SSiddharth Bhat   std::string EntryString, ExitString;
8607bee290SSiddharth Bhat   std::tie(EntryString, ExitString) = S.getEntryExitStr();
8707bee290SSiddharth Bhat 
880e93f3b0SMichael Kruse   return (Twine("__polly_perf_in_") + S.getFunction().getName() + "_from__" +
890e93f3b0SMichael Kruse           EntryString + "__to__" + ExitString)
900e93f3b0SMichael Kruse       .str();
9107bee290SSiddharth Bhat }
9207bee290SSiddharth Bhat 
addScopCounter()9307bee290SSiddharth Bhat void PerfMonitor::addScopCounter() {
9407bee290SSiddharth Bhat   const std::string varname = GetScopUniqueVarname(S);
95726c28f8SSiddharth Bhat   TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0),
9607bee290SSiddharth Bhat                     &CyclesInCurrentScopPtr);
97726c28f8SSiddharth Bhat 
98726c28f8SSiddharth Bhat   TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0),
99726c28f8SSiddharth Bhat                     &TripCountForCurrentScopPtr);
10007bee290SSiddharth Bhat }
10107bee290SSiddharth Bhat 
addGlobalVariables()10207bee290SSiddharth Bhat void PerfMonitor::addGlobalVariables() {
10307bee290SSiddharth Bhat   TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0),
10465371af2STobias Grosser                     &CyclesTotalStartPtr);
10565371af2STobias Grosser 
106*8afcfbfbSKazu Hirata   TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(false),
10765371af2STobias Grosser                     &AlreadyInitializedPtr);
10865371af2STobias Grosser 
10907bee290SSiddharth Bhat   TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0),
11065371af2STobias Grosser                     &CyclesInScopsPtr);
11165371af2STobias Grosser 
11207bee290SSiddharth Bhat   TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0),
11365371af2STobias Grosser                     &CyclesInScopStartPtr);
11465371af2STobias Grosser }
11565371af2STobias Grosser 
11665371af2STobias Grosser static const char *InitFunctionName = "__polly_perf_init";
11765371af2STobias Grosser static const char *FinalReportingFunctionName = "__polly_perf_final";
11865371af2STobias Grosser 
11907bee290SSiddharth Bhat static BasicBlock *FinalStartBB = nullptr;
12007bee290SSiddharth Bhat static ReturnInst *ReturnFromFinal = nullptr;
12107bee290SSiddharth Bhat 
insertFinalReporting()12265371af2STobias Grosser Function *PerfMonitor::insertFinalReporting() {
12365371af2STobias Grosser   // Create new function.
12465371af2STobias Grosser   GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
12565371af2STobias Grosser   FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
12665371af2STobias Grosser   Function *ExitFn =
12765371af2STobias Grosser       Function::Create(Ty, Linkage, FinalReportingFunctionName, M);
12807bee290SSiddharth Bhat   FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn);
12907bee290SSiddharth Bhat   Builder.SetInsertPoint(FinalStartBB);
13065371af2STobias Grosser 
13165371af2STobias Grosser   if (!Supported) {
13265371af2STobias Grosser     RuntimeDebugBuilder::createCPUPrinter(
13365371af2STobias Grosser         Builder, "Polly runtime information generation not supported\n");
13465371af2STobias Grosser     Builder.CreateRetVoid();
13565371af2STobias Grosser     return ExitFn;
13665371af2STobias Grosser   }
13765371af2STobias Grosser 
13865371af2STobias Grosser   // Measure current cycles and compute final timings.
13965371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
1404beb2f96STobias Grosser 
14146354bacSNikita Popov   Type *Int64Ty = Builder.getInt64Ty();
1424beb2f96STobias Grosser   Value *CurrentCycles =
1434beb2f96STobias Grosser       Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
14446354bacSNikita Popov   Value *CyclesStart = Builder.CreateLoad(Int64Ty, CyclesTotalStartPtr, true);
14565371af2STobias Grosser   Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart);
14646354bacSNikita Popov   Value *CyclesInScops = Builder.CreateLoad(Int64Ty, CyclesInScopsPtr, true);
14765371af2STobias Grosser 
14865371af2STobias Grosser   // Print the runtime information.
14965371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n");
15065371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n");
15165371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n");
15265371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops,
15365371af2STobias Grosser                                         "\n");
154a4dea6bbSSiddharth Bhat 
155a4dea6bbSSiddharth Bhat   // Print the preamble for per-scop information.
156a4dea6bbSSiddharth Bhat   RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
157a4dea6bbSSiddharth Bhat   RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n");
158a4dea6bbSSiddharth Bhat   RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n");
159a4dea6bbSSiddharth Bhat 
160a4dea6bbSSiddharth Bhat   RuntimeDebugBuilder::createCPUPrinter(
161a4dea6bbSSiddharth Bhat       Builder, "scop function, "
162726c28f8SSiddharth Bhat                "entry block name, exit block name, total time, trip count\n");
16307bee290SSiddharth Bhat   ReturnFromFinal = Builder.CreateRetVoid();
16465371af2STobias Grosser   return ExitFn;
16565371af2STobias Grosser }
16665371af2STobias Grosser 
AppendScopReporting()16707bee290SSiddharth Bhat void PerfMonitor::AppendScopReporting() {
168fee75f4bSSiddharth Bhat   if (!Supported)
169fee75f4bSSiddharth Bhat     return;
170fee75f4bSSiddharth Bhat 
171fee75f4bSSiddharth Bhat   assert(FinalStartBB && "Expected FinalStartBB to be initialized by "
172fee75f4bSSiddharth Bhat                          "PerfMonitor::insertFinalReporting.");
173fee75f4bSSiddharth Bhat   assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by "
174fee75f4bSSiddharth Bhat                             "PerfMonitor::insertFinalReporting.");
175fee75f4bSSiddharth Bhat 
17607bee290SSiddharth Bhat   Builder.SetInsertPoint(FinalStartBB);
17707bee290SSiddharth Bhat   ReturnFromFinal->eraseFromParent();
17807bee290SSiddharth Bhat 
17946354bacSNikita Popov   Type *Int64Ty = Builder.getInt64Ty();
18007bee290SSiddharth Bhat   Value *CyclesInCurrentScop =
18146354bacSNikita Popov       Builder.CreateLoad(Int64Ty, this->CyclesInCurrentScopPtr, true);
182726c28f8SSiddharth Bhat 
183726c28f8SSiddharth Bhat   Value *TripCountForCurrentScop =
18446354bacSNikita Popov       Builder.CreateLoad(Int64Ty, this->TripCountForCurrentScopPtr, true);
185726c28f8SSiddharth Bhat 
18607bee290SSiddharth Bhat   std::string EntryName, ExitName;
18707bee290SSiddharth Bhat   std::tie(EntryName, ExitName) = S.getEntryExitStr();
18807bee290SSiddharth Bhat 
189a4dea6bbSSiddharth Bhat   // print in CSV for easy parsing with other tools.
190726c28f8SSiddharth Bhat   RuntimeDebugBuilder::createCPUPrinter(
191726c28f8SSiddharth Bhat       Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ",
192726c28f8SSiddharth Bhat       CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n");
19307bee290SSiddharth Bhat 
19407bee290SSiddharth Bhat   ReturnFromFinal = Builder.CreateRetVoid();
19507bee290SSiddharth Bhat }
19607bee290SSiddharth Bhat 
19707bee290SSiddharth Bhat static Function *FinalReporting = nullptr;
19807bee290SSiddharth Bhat 
initialize()19965371af2STobias Grosser void PerfMonitor::initialize() {
20065371af2STobias Grosser   addGlobalVariables();
20107bee290SSiddharth Bhat   addScopCounter();
20265371af2STobias Grosser 
20307bee290SSiddharth Bhat   // Ensure that we only add the final reporting function once.
20407bee290SSiddharth Bhat   // On later invocations, append to the reporting function.
20507bee290SSiddharth Bhat   if (!FinalReporting) {
20607bee290SSiddharth Bhat     FinalReporting = insertFinalReporting();
20765371af2STobias Grosser 
20865371af2STobias Grosser     Function *InitFn = insertInitFunction(FinalReporting);
20965371af2STobias Grosser     addToGlobalConstructors(InitFn);
21065371af2STobias Grosser   }
21165371af2STobias Grosser 
21207bee290SSiddharth Bhat   AppendScopReporting();
21307bee290SSiddharth Bhat }
21407bee290SSiddharth Bhat 
insertInitFunction(Function * FinalReporting)21565371af2STobias Grosser Function *PerfMonitor::insertInitFunction(Function *FinalReporting) {
21665371af2STobias Grosser   // Insert function definition and BBs.
21765371af2STobias Grosser   GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
21865371af2STobias Grosser   FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
21965371af2STobias Grosser   Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M);
22065371af2STobias Grosser   BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn);
22165371af2STobias Grosser   BasicBlock *EarlyReturn =
22265371af2STobias Grosser       BasicBlock::Create(M->getContext(), "earlyreturn", InitFn);
22365371af2STobias Grosser   BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn);
22465371af2STobias Grosser 
22565371af2STobias Grosser   Builder.SetInsertPoint(Start);
22665371af2STobias Grosser 
22765371af2STobias Grosser   // Check if this function was already run. If yes, return.
22865371af2STobias Grosser   //
22965371af2STobias Grosser   // In case profiling has been enabled in multiple translation units, the
23065371af2STobias Grosser   // initializer function will be added to the global constructors list of
23165371af2STobias Grosser   // each translation unit. When merging translation units, the global
23265371af2STobias Grosser   // constructor lists are just appended, such that the initializer will appear
23365371af2STobias Grosser   // multiple times. To avoid initializations being run multiple times (and
23465371af2STobias Grosser   // especially to avoid that atExitFn is called more than once), we bail
235a6d48f59SMichael Kruse   // out if the initializer is run more than once.
23646354bacSNikita Popov   Value *HasRunBefore =
23746354bacSNikita Popov       Builder.CreateLoad(Builder.getInt1Ty(), AlreadyInitializedPtr);
23865371af2STobias Grosser   Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB);
23965371af2STobias Grosser   Builder.SetInsertPoint(EarlyReturn);
24065371af2STobias Grosser   Builder.CreateRetVoid();
24165371af2STobias Grosser 
24265371af2STobias Grosser   // Keep track that this function has been run once.
24365371af2STobias Grosser   Builder.SetInsertPoint(InitBB);
24465371af2STobias Grosser   Value *True = Builder.getInt1(true);
24565371af2STobias Grosser   Builder.CreateStore(True, AlreadyInitializedPtr);
24665371af2STobias Grosser 
24765371af2STobias Grosser   // Register the final reporting function with atexit().
24865371af2STobias Grosser   Value *FinalReportingPtr =
24965371af2STobias Grosser       Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy());
25065371af2STobias Grosser   Function *AtExitFn = getAtExit();
25165371af2STobias Grosser   Builder.CreateCall(AtExitFn, {FinalReportingPtr});
25265371af2STobias Grosser 
25365371af2STobias Grosser   if (Supported) {
25465371af2STobias Grosser     // Read the currently cycle counter and store the result for later.
25565371af2STobias Grosser     Function *RDTSCPFn = getRDTSCP();
2564beb2f96STobias Grosser     Value *CurrentCycles =
2574beb2f96STobias Grosser         Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
25865371af2STobias Grosser     Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true);
25965371af2STobias Grosser   }
26065371af2STobias Grosser   Builder.CreateRetVoid();
26165371af2STobias Grosser 
26265371af2STobias Grosser   return InitFn;
26365371af2STobias Grosser }
26465371af2STobias Grosser 
insertRegionStart(Instruction * InsertBefore)26565371af2STobias Grosser void PerfMonitor::insertRegionStart(Instruction *InsertBefore) {
26665371af2STobias Grosser   if (!Supported)
26765371af2STobias Grosser     return;
26865371af2STobias Grosser 
26965371af2STobias Grosser   Builder.SetInsertPoint(InsertBefore);
27065371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
2714beb2f96STobias Grosser   Value *CurrentCycles =
2724beb2f96STobias Grosser       Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
27365371af2STobias Grosser   Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true);
27465371af2STobias Grosser }
27565371af2STobias Grosser 
insertRegionEnd(Instruction * InsertBefore)27665371af2STobias Grosser void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) {
27765371af2STobias Grosser   if (!Supported)
27865371af2STobias Grosser     return;
27965371af2STobias Grosser 
28065371af2STobias Grosser   Builder.SetInsertPoint(InsertBefore);
28165371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
28246354bacSNikita Popov   Type *Int64Ty = Builder.getInt64Ty();
28346354bacSNikita Popov   LoadInst *CyclesStart =
28446354bacSNikita Popov       Builder.CreateLoad(Int64Ty, CyclesInScopStartPtr, true);
2854beb2f96STobias Grosser   Value *CurrentCycles =
2864beb2f96STobias Grosser       Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
28765371af2STobias Grosser   Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart);
28846354bacSNikita Popov   Value *CyclesInScops = Builder.CreateLoad(Int64Ty, CyclesInScopsPtr, true);
28965371af2STobias Grosser   CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop);
29065371af2STobias Grosser   Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true);
29107bee290SSiddharth Bhat 
29246354bacSNikita Popov   Value *CyclesInCurrentScop =
29346354bacSNikita Popov       Builder.CreateLoad(Int64Ty, CyclesInCurrentScopPtr, true);
29407bee290SSiddharth Bhat   CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop);
29507bee290SSiddharth Bhat   Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true);
296726c28f8SSiddharth Bhat 
297726c28f8SSiddharth Bhat   Value *TripCountForCurrentScop =
29846354bacSNikita Popov       Builder.CreateLoad(Int64Ty, TripCountForCurrentScopPtr, true);
299726c28f8SSiddharth Bhat   TripCountForCurrentScop =
300726c28f8SSiddharth Bhat       Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1));
301726c28f8SSiddharth Bhat   Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr,
302726c28f8SSiddharth Bhat                       true);
30365371af2STobias Grosser }
304