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" 140e93f3b0SMichael Kruse #include "llvm/ADT/Twine.h" 155368f35eSHeejin Ahn #include "llvm/IR/IntrinsicsX86.h" 1674deadf1SNikita Popov #include "llvm/IR/Module.h" 1762c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h" 1865371af2STobias Grosser 1965371af2STobias Grosser using namespace llvm; 2065371af2STobias Grosser using namespace polly; 2165371af2STobias Grosser 2265371af2STobias Grosser Function *PerfMonitor::getAtExit() { 2365371af2STobias Grosser const char *Name = "atexit"; 2465371af2STobias Grosser Function *F = M->getFunction(Name); 2565371af2STobias Grosser 2665371af2STobias Grosser if (!F) { 2765371af2STobias Grosser GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 28a3ef8589SFangrui Song FunctionType *Ty = 29a3ef8589SFangrui Song FunctionType::get(Builder.getInt32Ty(), {Builder.getPtrTy()}, false); 3065371af2STobias Grosser F = Function::Create(Ty, Linkage, Name, M); 3165371af2STobias Grosser } 3265371af2STobias Grosser 3365371af2STobias Grosser return F; 3465371af2STobias Grosser } 3565371af2STobias Grosser 3665371af2STobias Grosser void PerfMonitor::addToGlobalConstructors(Function *Fn) { 3765371af2STobias Grosser const char *Name = "llvm.global_ctors"; 3865371af2STobias Grosser GlobalVariable *GV = M->getGlobalVariable(Name); 3965371af2STobias Grosser std::vector<Constant *> V; 4065371af2STobias Grosser 4165371af2STobias Grosser if (GV) { 4265371af2STobias Grosser Constant *Array = GV->getInitializer(); 4365371af2STobias Grosser for (Value *X : Array->operand_values()) 4465371af2STobias Grosser V.push_back(cast<Constant>(X)); 4565371af2STobias Grosser GV->eraseFromParent(); 4665371af2STobias Grosser } 4765371af2STobias Grosser 48a3ef8589SFangrui Song StructType *ST = 49a3ef8589SFangrui Song StructType::get(Builder.getInt32Ty(), Fn->getType(), Builder.getPtrTy()); 5065371af2STobias Grosser 511a2e0e64STobias Grosser V.push_back( 521a2e0e64STobias Grosser ConstantStruct::get(ST, Builder.getInt32(10), Fn, 53a3ef8589SFangrui Song ConstantPointerNull::get(Builder.getPtrTy()))); 5465371af2STobias Grosser ArrayType *Ty = ArrayType::get(ST, V.size()); 5565371af2STobias Grosser 5665371af2STobias Grosser GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage, 5765371af2STobias Grosser ConstantArray::get(Ty, V), Name, nullptr, 5865371af2STobias Grosser GlobalVariable::NotThreadLocal); 5965371af2STobias Grosser } 6065371af2STobias Grosser 6165371af2STobias Grosser Function *PerfMonitor::getRDTSCP() { 62*fa789dffSRahul Joshi return Intrinsic::getOrInsertDeclaration(M, Intrinsic::x86_rdtscp); 6365371af2STobias Grosser } 6465371af2STobias Grosser 6507bee290SSiddharth Bhat PerfMonitor::PerfMonitor(const Scop &S, Module *M) 6607bee290SSiddharth Bhat : M(M), Builder(M->getContext()), S(S) { 6765371af2STobias Grosser if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64) 6865371af2STobias Grosser Supported = true; 6965371af2STobias Grosser else 7065371af2STobias Grosser Supported = false; 7165371af2STobias Grosser } 7265371af2STobias Grosser 7307bee290SSiddharth Bhat static void TryRegisterGlobal(Module *M, const char *Name, 7407bee290SSiddharth Bhat Constant *InitialValue, Value **Location) { 7565371af2STobias Grosser *Location = M->getGlobalVariable(Name); 7665371af2STobias Grosser 7765371af2STobias Grosser if (!*Location) 7865371af2STobias Grosser *Location = new GlobalVariable( 7965371af2STobias Grosser *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage, 8065371af2STobias Grosser InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel); 81be194d4eSMichael Kruse } 8265371af2STobias Grosser 8307bee290SSiddharth Bhat // Generate a unique name that is usable as a LLVM name for a scop to name its 8407bee290SSiddharth Bhat // performance counter. 8507bee290SSiddharth Bhat static std::string GetScopUniqueVarname(const Scop &S) { 8607bee290SSiddharth Bhat std::string EntryString, ExitString; 8707bee290SSiddharth Bhat std::tie(EntryString, ExitString) = S.getEntryExitStr(); 8807bee290SSiddharth Bhat 890e93f3b0SMichael Kruse return (Twine("__polly_perf_in_") + S.getFunction().getName() + "_from__" + 900e93f3b0SMichael Kruse EntryString + "__to__" + ExitString) 910e93f3b0SMichael Kruse .str(); 9207bee290SSiddharth Bhat } 9307bee290SSiddharth Bhat 9407bee290SSiddharth Bhat void PerfMonitor::addScopCounter() { 9507bee290SSiddharth Bhat const std::string varname = GetScopUniqueVarname(S); 96726c28f8SSiddharth Bhat TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0), 9707bee290SSiddharth Bhat &CyclesInCurrentScopPtr); 98726c28f8SSiddharth Bhat 99726c28f8SSiddharth Bhat TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0), 100726c28f8SSiddharth Bhat &TripCountForCurrentScopPtr); 10107bee290SSiddharth Bhat } 10207bee290SSiddharth Bhat 10307bee290SSiddharth Bhat void PerfMonitor::addGlobalVariables() { 10407bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0), 10565371af2STobias Grosser &CyclesTotalStartPtr); 10665371af2STobias Grosser 1078afcfbfbSKazu Hirata TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(false), 10865371af2STobias Grosser &AlreadyInitializedPtr); 10965371af2STobias Grosser 11007bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0), 11165371af2STobias Grosser &CyclesInScopsPtr); 11265371af2STobias Grosser 11307bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0), 11465371af2STobias Grosser &CyclesInScopStartPtr); 11565371af2STobias Grosser } 11665371af2STobias Grosser 11765371af2STobias Grosser static const char *InitFunctionName = "__polly_perf_init"; 11865371af2STobias Grosser static const char *FinalReportingFunctionName = "__polly_perf_final"; 11965371af2STobias Grosser 12007bee290SSiddharth Bhat static BasicBlock *FinalStartBB = nullptr; 12107bee290SSiddharth Bhat static ReturnInst *ReturnFromFinal = nullptr; 12207bee290SSiddharth Bhat 12365371af2STobias Grosser Function *PerfMonitor::insertFinalReporting() { 12465371af2STobias Grosser // Create new function. 12565371af2STobias Grosser GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; 12665371af2STobias Grosser FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); 12765371af2STobias Grosser Function *ExitFn = 12865371af2STobias Grosser Function::Create(Ty, Linkage, FinalReportingFunctionName, M); 12907bee290SSiddharth Bhat FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn); 13007bee290SSiddharth Bhat Builder.SetInsertPoint(FinalStartBB); 13165371af2STobias Grosser 13265371af2STobias Grosser if (!Supported) { 13365371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter( 13465371af2STobias Grosser Builder, "Polly runtime information generation not supported\n"); 13565371af2STobias Grosser Builder.CreateRetVoid(); 13665371af2STobias Grosser return ExitFn; 13765371af2STobias Grosser } 13865371af2STobias Grosser 13965371af2STobias Grosser // Measure current cycles and compute final timings. 14065371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 1414beb2f96STobias Grosser 14246354bacSNikita Popov Type *Int64Ty = Builder.getInt64Ty(); 1434beb2f96STobias Grosser Value *CurrentCycles = 1444beb2f96STobias Grosser Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); 14546354bacSNikita Popov Value *CyclesStart = Builder.CreateLoad(Int64Ty, CyclesTotalStartPtr, true); 14665371af2STobias Grosser Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart); 14746354bacSNikita Popov Value *CyclesInScops = Builder.CreateLoad(Int64Ty, CyclesInScopsPtr, true); 14865371af2STobias Grosser 14965371af2STobias Grosser // Print the runtime information. 15065371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n"); 15165371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n"); 15265371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n"); 15365371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops, 15465371af2STobias Grosser "\n"); 155a4dea6bbSSiddharth Bhat 156a4dea6bbSSiddharth Bhat // Print the preamble for per-scop information. 157a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "\n"); 158a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n"); 159a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n"); 160a4dea6bbSSiddharth Bhat 161a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter( 162a4dea6bbSSiddharth Bhat Builder, "scop function, " 163726c28f8SSiddharth Bhat "entry block name, exit block name, total time, trip count\n"); 16407bee290SSiddharth Bhat ReturnFromFinal = Builder.CreateRetVoid(); 16565371af2STobias Grosser return ExitFn; 16665371af2STobias Grosser } 16765371af2STobias Grosser 16807bee290SSiddharth Bhat void PerfMonitor::AppendScopReporting() { 169fee75f4bSSiddharth Bhat if (!Supported) 170fee75f4bSSiddharth Bhat return; 171fee75f4bSSiddharth Bhat 172fee75f4bSSiddharth Bhat assert(FinalStartBB && "Expected FinalStartBB to be initialized by " 173fee75f4bSSiddharth Bhat "PerfMonitor::insertFinalReporting."); 174fee75f4bSSiddharth Bhat assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by " 175fee75f4bSSiddharth Bhat "PerfMonitor::insertFinalReporting."); 176fee75f4bSSiddharth Bhat 17707bee290SSiddharth Bhat Builder.SetInsertPoint(FinalStartBB); 17807bee290SSiddharth Bhat ReturnFromFinal->eraseFromParent(); 17907bee290SSiddharth Bhat 18046354bacSNikita Popov Type *Int64Ty = Builder.getInt64Ty(); 18107bee290SSiddharth Bhat Value *CyclesInCurrentScop = 18246354bacSNikita Popov Builder.CreateLoad(Int64Ty, this->CyclesInCurrentScopPtr, true); 183726c28f8SSiddharth Bhat 184726c28f8SSiddharth Bhat Value *TripCountForCurrentScop = 18546354bacSNikita Popov Builder.CreateLoad(Int64Ty, this->TripCountForCurrentScopPtr, true); 186726c28f8SSiddharth Bhat 18707bee290SSiddharth Bhat std::string EntryName, ExitName; 18807bee290SSiddharth Bhat std::tie(EntryName, ExitName) = S.getEntryExitStr(); 18907bee290SSiddharth Bhat 190a4dea6bbSSiddharth Bhat // print in CSV for easy parsing with other tools. 191726c28f8SSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter( 192726c28f8SSiddharth Bhat Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ", 193726c28f8SSiddharth Bhat CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n"); 19407bee290SSiddharth Bhat 19507bee290SSiddharth Bhat ReturnFromFinal = Builder.CreateRetVoid(); 19607bee290SSiddharth Bhat } 19707bee290SSiddharth Bhat 19807bee290SSiddharth Bhat static Function *FinalReporting = nullptr; 19907bee290SSiddharth Bhat 20065371af2STobias Grosser void PerfMonitor::initialize() { 20165371af2STobias Grosser addGlobalVariables(); 20207bee290SSiddharth Bhat addScopCounter(); 20365371af2STobias Grosser 20407bee290SSiddharth Bhat // Ensure that we only add the final reporting function once. 20507bee290SSiddharth Bhat // On later invocations, append to the reporting function. 20607bee290SSiddharth Bhat if (!FinalReporting) { 20707bee290SSiddharth Bhat FinalReporting = insertFinalReporting(); 20865371af2STobias Grosser 20965371af2STobias Grosser Function *InitFn = insertInitFunction(FinalReporting); 21065371af2STobias Grosser addToGlobalConstructors(InitFn); 21165371af2STobias Grosser } 21265371af2STobias Grosser 21307bee290SSiddharth Bhat AppendScopReporting(); 21407bee290SSiddharth Bhat } 21507bee290SSiddharth Bhat 21665371af2STobias Grosser Function *PerfMonitor::insertInitFunction(Function *FinalReporting) { 21765371af2STobias Grosser // Insert function definition and BBs. 21865371af2STobias Grosser GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; 21965371af2STobias Grosser FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); 22065371af2STobias Grosser Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M); 22165371af2STobias Grosser BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn); 22265371af2STobias Grosser BasicBlock *EarlyReturn = 22365371af2STobias Grosser BasicBlock::Create(M->getContext(), "earlyreturn", InitFn); 22465371af2STobias Grosser BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn); 22565371af2STobias Grosser 22665371af2STobias Grosser Builder.SetInsertPoint(Start); 22765371af2STobias Grosser 22865371af2STobias Grosser // Check if this function was already run. If yes, return. 22965371af2STobias Grosser // 23065371af2STobias Grosser // In case profiling has been enabled in multiple translation units, the 23165371af2STobias Grosser // initializer function will be added to the global constructors list of 23265371af2STobias Grosser // each translation unit. When merging translation units, the global 23365371af2STobias Grosser // constructor lists are just appended, such that the initializer will appear 23465371af2STobias Grosser // multiple times. To avoid initializations being run multiple times (and 23565371af2STobias Grosser // especially to avoid that atExitFn is called more than once), we bail 236a6d48f59SMichael Kruse // out if the initializer is run more than once. 23746354bacSNikita Popov Value *HasRunBefore = 23846354bacSNikita Popov Builder.CreateLoad(Builder.getInt1Ty(), AlreadyInitializedPtr); 23965371af2STobias Grosser Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB); 24065371af2STobias Grosser Builder.SetInsertPoint(EarlyReturn); 24165371af2STobias Grosser Builder.CreateRetVoid(); 24265371af2STobias Grosser 24365371af2STobias Grosser // Keep track that this function has been run once. 24465371af2STobias Grosser Builder.SetInsertPoint(InitBB); 24565371af2STobias Grosser Value *True = Builder.getInt1(true); 24665371af2STobias Grosser Builder.CreateStore(True, AlreadyInitializedPtr); 24765371af2STobias Grosser 24865371af2STobias Grosser // Register the final reporting function with atexit(). 24965371af2STobias Grosser Value *FinalReportingPtr = 250a3ef8589SFangrui Song Builder.CreatePointerCast(FinalReporting, Builder.getPtrTy()); 25165371af2STobias Grosser Function *AtExitFn = getAtExit(); 25265371af2STobias Grosser Builder.CreateCall(AtExitFn, {FinalReportingPtr}); 25365371af2STobias Grosser 25465371af2STobias Grosser if (Supported) { 25565371af2STobias Grosser // Read the currently cycle counter and store the result for later. 25665371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 2574beb2f96STobias Grosser Value *CurrentCycles = 2584beb2f96STobias Grosser Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); 25965371af2STobias Grosser Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true); 26065371af2STobias Grosser } 26165371af2STobias Grosser Builder.CreateRetVoid(); 26265371af2STobias Grosser 26365371af2STobias Grosser return InitFn; 26465371af2STobias Grosser } 26565371af2STobias Grosser 26665371af2STobias Grosser void PerfMonitor::insertRegionStart(Instruction *InsertBefore) { 26765371af2STobias Grosser if (!Supported) 26865371af2STobias Grosser return; 26965371af2STobias Grosser 27065371af2STobias Grosser Builder.SetInsertPoint(InsertBefore); 27165371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 2724beb2f96STobias Grosser Value *CurrentCycles = 2734beb2f96STobias Grosser Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); 27465371af2STobias Grosser Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true); 27565371af2STobias Grosser } 27665371af2STobias Grosser 27765371af2STobias Grosser void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) { 27865371af2STobias Grosser if (!Supported) 27965371af2STobias Grosser return; 28065371af2STobias Grosser 28165371af2STobias Grosser Builder.SetInsertPoint(InsertBefore); 28265371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 28346354bacSNikita Popov Type *Int64Ty = Builder.getInt64Ty(); 28446354bacSNikita Popov LoadInst *CyclesStart = 28546354bacSNikita Popov Builder.CreateLoad(Int64Ty, CyclesInScopStartPtr, true); 2864beb2f96STobias Grosser Value *CurrentCycles = 2874beb2f96STobias Grosser Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0}); 28865371af2STobias Grosser Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart); 28946354bacSNikita Popov Value *CyclesInScops = Builder.CreateLoad(Int64Ty, CyclesInScopsPtr, true); 29065371af2STobias Grosser CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop); 29165371af2STobias Grosser Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true); 29207bee290SSiddharth Bhat 29346354bacSNikita Popov Value *CyclesInCurrentScop = 29446354bacSNikita Popov Builder.CreateLoad(Int64Ty, CyclesInCurrentScopPtr, true); 29507bee290SSiddharth Bhat CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop); 29607bee290SSiddharth Bhat Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true); 297726c28f8SSiddharth Bhat 298726c28f8SSiddharth Bhat Value *TripCountForCurrentScop = 29946354bacSNikita Popov Builder.CreateLoad(Int64Ty, TripCountForCurrentScopPtr, true); 300726c28f8SSiddharth Bhat TripCountForCurrentScop = 301726c28f8SSiddharth Bhat Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1)); 302726c28f8SSiddharth Bhat Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr, 303726c28f8SSiddharth Bhat true); 30465371af2STobias Grosser } 305