165371af2STobias Grosser //===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======// 265371af2STobias Grosser // 365371af2STobias Grosser // The LLVM Compiler Infrastructure 465371af2STobias Grosser // 565371af2STobias Grosser // This file is distributed under the University of Illinois Open Source 665371af2STobias Grosser // License. See LICENSE.TXT for details. 765371af2STobias Grosser // 865371af2STobias Grosser //===----------------------------------------------------------------------===// 965371af2STobias Grosser // 1065371af2STobias Grosser //===----------------------------------------------------------------------===// 1165371af2STobias Grosser 1265371af2STobias Grosser #include "polly/CodeGen/PerfMonitor.h" 1365371af2STobias Grosser #include "polly/CodeGen/RuntimeDebugBuilder.h" 1407bee290SSiddharth Bhat #include "polly/ScopInfo.h" 1565371af2STobias Grosser #include "llvm/ADT/Triple.h" 16637be04bSTobias Grosser #include "llvm/IR/Intrinsics.h" 1707bee290SSiddharth Bhat #include <sstream> 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; 2865371af2STobias Grosser FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), 2965371af2STobias Grosser {Builder.getInt8PtrTy()}, 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 4865371af2STobias Grosser StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(), 49d742e5efSChandler Carruth Builder.getInt8PtrTy()); 5065371af2STobias Grosser 511a2e0e64STobias Grosser V.push_back( 521a2e0e64STobias Grosser ConstantStruct::get(ST, Builder.getInt32(10), Fn, 53d742e5efSChandler Carruth ConstantPointerNull::get(Builder.getInt8PtrTy()))); 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() { 62637be04bSTobias Grosser return Intrinsic::getDeclaration(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); 81*be194d4eSMichael 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::stringstream Name; 8707bee290SSiddharth Bhat std::string EntryString, ExitString; 8807bee290SSiddharth Bhat std::tie(EntryString, ExitString) = S.getEntryExitStr(); 8907bee290SSiddharth Bhat 90726c28f8SSiddharth Bhat Name << "__polly_perf_in_" << std::string(S.getFunction().getName()) 9107bee290SSiddharth Bhat << "_from__" << EntryString << "__to__" << ExitString; 9207bee290SSiddharth Bhat return Name.str(); 9307bee290SSiddharth Bhat } 9407bee290SSiddharth Bhat 9507bee290SSiddharth Bhat void PerfMonitor::addScopCounter() { 9607bee290SSiddharth Bhat const std::string varname = GetScopUniqueVarname(S); 97726c28f8SSiddharth Bhat TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0), 9807bee290SSiddharth Bhat &CyclesInCurrentScopPtr); 99726c28f8SSiddharth Bhat 100726c28f8SSiddharth Bhat TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0), 101726c28f8SSiddharth Bhat &TripCountForCurrentScopPtr); 10207bee290SSiddharth Bhat } 10307bee290SSiddharth Bhat 10407bee290SSiddharth Bhat void PerfMonitor::addGlobalVariables() { 10507bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0), 10665371af2STobias Grosser &CyclesTotalStartPtr); 10765371af2STobias Grosser 10807bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(0), 10965371af2STobias Grosser &AlreadyInitializedPtr); 11065371af2STobias Grosser 11107bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0), 11265371af2STobias Grosser &CyclesInScopsPtr); 11365371af2STobias Grosser 11407bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0), 11565371af2STobias Grosser &CyclesInScopStartPtr); 11665371af2STobias Grosser 11707bee290SSiddharth Bhat TryRegisterGlobal(M, "__polly_perf_write_loation", Builder.getInt32(0), 11865371af2STobias Grosser &RDTSCPWriteLocation); 11965371af2STobias Grosser } 12065371af2STobias Grosser 12165371af2STobias Grosser static const char *InitFunctionName = "__polly_perf_init"; 12265371af2STobias Grosser static const char *FinalReportingFunctionName = "__polly_perf_final"; 12365371af2STobias Grosser 12407bee290SSiddharth Bhat static BasicBlock *FinalStartBB = nullptr; 12507bee290SSiddharth Bhat static ReturnInst *ReturnFromFinal = nullptr; 12607bee290SSiddharth Bhat 12765371af2STobias Grosser Function *PerfMonitor::insertFinalReporting() { 12865371af2STobias Grosser // Create new function. 12965371af2STobias Grosser GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; 13065371af2STobias Grosser FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); 13165371af2STobias Grosser Function *ExitFn = 13265371af2STobias Grosser Function::Create(Ty, Linkage, FinalReportingFunctionName, M); 13307bee290SSiddharth Bhat FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn); 13407bee290SSiddharth Bhat Builder.SetInsertPoint(FinalStartBB); 13565371af2STobias Grosser 13665371af2STobias Grosser if (!Supported) { 13765371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter( 13865371af2STobias Grosser Builder, "Polly runtime information generation not supported\n"); 13965371af2STobias Grosser Builder.CreateRetVoid(); 14065371af2STobias Grosser return ExitFn; 14165371af2STobias Grosser } 14265371af2STobias Grosser 14365371af2STobias Grosser // Measure current cycles and compute final timings. 14465371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 14565371af2STobias Grosser Value *CurrentCycles = Builder.CreateCall( 14665371af2STobias Grosser RDTSCPFn, 14765371af2STobias Grosser Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy())); 14865371af2STobias Grosser Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true); 14965371af2STobias Grosser Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart); 15065371af2STobias Grosser Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true); 15165371af2STobias Grosser 15265371af2STobias Grosser // Print the runtime information. 15365371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n"); 15465371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n"); 15565371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n"); 15665371af2STobias Grosser RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops, 15765371af2STobias Grosser "\n"); 158a4dea6bbSSiddharth Bhat 159a4dea6bbSSiddharth Bhat // Print the preamble for per-scop information. 160a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "\n"); 161a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n"); 162a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n"); 163a4dea6bbSSiddharth Bhat 164a4dea6bbSSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter( 165a4dea6bbSSiddharth Bhat Builder, "scop function, " 166726c28f8SSiddharth Bhat "entry block name, exit block name, total time, trip count\n"); 16707bee290SSiddharth Bhat ReturnFromFinal = Builder.CreateRetVoid(); 16865371af2STobias Grosser return ExitFn; 16965371af2STobias Grosser } 17065371af2STobias Grosser 17107bee290SSiddharth Bhat void PerfMonitor::AppendScopReporting() { 172fee75f4bSSiddharth Bhat if (!Supported) 173fee75f4bSSiddharth Bhat return; 174fee75f4bSSiddharth Bhat 175fee75f4bSSiddharth Bhat assert(FinalStartBB && "Expected FinalStartBB to be initialized by " 176fee75f4bSSiddharth Bhat "PerfMonitor::insertFinalReporting."); 177fee75f4bSSiddharth Bhat assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by " 178fee75f4bSSiddharth Bhat "PerfMonitor::insertFinalReporting."); 179fee75f4bSSiddharth Bhat 18007bee290SSiddharth Bhat Builder.SetInsertPoint(FinalStartBB); 18107bee290SSiddharth Bhat ReturnFromFinal->eraseFromParent(); 18207bee290SSiddharth Bhat 18307bee290SSiddharth Bhat Value *CyclesInCurrentScop = 18407bee290SSiddharth Bhat Builder.CreateLoad(this->CyclesInCurrentScopPtr, true); 185726c28f8SSiddharth Bhat 186726c28f8SSiddharth Bhat Value *TripCountForCurrentScop = 187726c28f8SSiddharth Bhat Builder.CreateLoad(this->TripCountForCurrentScopPtr, true); 188726c28f8SSiddharth Bhat 18907bee290SSiddharth Bhat std::string EntryName, ExitName; 19007bee290SSiddharth Bhat std::tie(EntryName, ExitName) = S.getEntryExitStr(); 19107bee290SSiddharth Bhat 192a4dea6bbSSiddharth Bhat // print in CSV for easy parsing with other tools. 193726c28f8SSiddharth Bhat RuntimeDebugBuilder::createCPUPrinter( 194726c28f8SSiddharth Bhat Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ", 195726c28f8SSiddharth Bhat CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n"); 19607bee290SSiddharth Bhat 19707bee290SSiddharth Bhat ReturnFromFinal = Builder.CreateRetVoid(); 19807bee290SSiddharth Bhat } 19907bee290SSiddharth Bhat 20007bee290SSiddharth Bhat static Function *FinalReporting = nullptr; 20107bee290SSiddharth Bhat 20265371af2STobias Grosser void PerfMonitor::initialize() { 20365371af2STobias Grosser addGlobalVariables(); 20407bee290SSiddharth Bhat addScopCounter(); 20565371af2STobias Grosser 20607bee290SSiddharth Bhat // Ensure that we only add the final reporting function once. 20707bee290SSiddharth Bhat // On later invocations, append to the reporting function. 20807bee290SSiddharth Bhat if (!FinalReporting) { 20907bee290SSiddharth Bhat FinalReporting = insertFinalReporting(); 21065371af2STobias Grosser 21165371af2STobias Grosser Function *InitFn = insertInitFunction(FinalReporting); 21265371af2STobias Grosser addToGlobalConstructors(InitFn); 21365371af2STobias Grosser } 21465371af2STobias Grosser 21507bee290SSiddharth Bhat AppendScopReporting(); 21607bee290SSiddharth Bhat } 21707bee290SSiddharth Bhat 21865371af2STobias Grosser Function *PerfMonitor::insertInitFunction(Function *FinalReporting) { 21965371af2STobias Grosser // Insert function definition and BBs. 22065371af2STobias Grosser GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage; 22165371af2STobias Grosser FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false); 22265371af2STobias Grosser Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M); 22365371af2STobias Grosser BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn); 22465371af2STobias Grosser BasicBlock *EarlyReturn = 22565371af2STobias Grosser BasicBlock::Create(M->getContext(), "earlyreturn", InitFn); 22665371af2STobias Grosser BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn); 22765371af2STobias Grosser 22865371af2STobias Grosser Builder.SetInsertPoint(Start); 22965371af2STobias Grosser 23065371af2STobias Grosser // Check if this function was already run. If yes, return. 23165371af2STobias Grosser // 23265371af2STobias Grosser // In case profiling has been enabled in multiple translation units, the 23365371af2STobias Grosser // initializer function will be added to the global constructors list of 23465371af2STobias Grosser // each translation unit. When merging translation units, the global 23565371af2STobias Grosser // constructor lists are just appended, such that the initializer will appear 23665371af2STobias Grosser // multiple times. To avoid initializations being run multiple times (and 23765371af2STobias Grosser // especially to avoid that atExitFn is called more than once), we bail 23865371af2STobias Grosser // out if the intializer is run more than once. 23965371af2STobias Grosser Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr); 24065371af2STobias Grosser Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB); 24165371af2STobias Grosser Builder.SetInsertPoint(EarlyReturn); 24265371af2STobias Grosser Builder.CreateRetVoid(); 24365371af2STobias Grosser 24465371af2STobias Grosser // Keep track that this function has been run once. 24565371af2STobias Grosser Builder.SetInsertPoint(InitBB); 24665371af2STobias Grosser Value *True = Builder.getInt1(true); 24765371af2STobias Grosser Builder.CreateStore(True, AlreadyInitializedPtr); 24865371af2STobias Grosser 24965371af2STobias Grosser // Register the final reporting function with atexit(). 25065371af2STobias Grosser Value *FinalReportingPtr = 25165371af2STobias Grosser Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy()); 25265371af2STobias Grosser Function *AtExitFn = getAtExit(); 25365371af2STobias Grosser Builder.CreateCall(AtExitFn, {FinalReportingPtr}); 25465371af2STobias Grosser 25565371af2STobias Grosser if (Supported) { 25665371af2STobias Grosser // Read the currently cycle counter and store the result for later. 25765371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 25865371af2STobias Grosser Value *CurrentCycles = Builder.CreateCall( 25965371af2STobias Grosser RDTSCPFn, 26065371af2STobias Grosser Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy())); 26165371af2STobias Grosser Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true); 26265371af2STobias Grosser } 26365371af2STobias Grosser Builder.CreateRetVoid(); 26465371af2STobias Grosser 26565371af2STobias Grosser return InitFn; 26665371af2STobias Grosser } 26765371af2STobias Grosser 26865371af2STobias Grosser void PerfMonitor::insertRegionStart(Instruction *InsertBefore) { 26965371af2STobias Grosser if (!Supported) 27065371af2STobias Grosser return; 27165371af2STobias Grosser 27265371af2STobias Grosser Builder.SetInsertPoint(InsertBefore); 27365371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 27465371af2STobias Grosser Value *CurrentCycles = Builder.CreateCall( 27565371af2STobias Grosser RDTSCPFn, 27665371af2STobias Grosser Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy())); 27765371af2STobias Grosser Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true); 27865371af2STobias Grosser } 27965371af2STobias Grosser 28065371af2STobias Grosser void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) { 28165371af2STobias Grosser if (!Supported) 28265371af2STobias Grosser return; 28365371af2STobias Grosser 28465371af2STobias Grosser Builder.SetInsertPoint(InsertBefore); 28565371af2STobias Grosser Function *RDTSCPFn = getRDTSCP(); 28665371af2STobias Grosser LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true); 28765371af2STobias Grosser Value *CurrentCycles = Builder.CreateCall( 28865371af2STobias Grosser RDTSCPFn, 28965371af2STobias Grosser Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy())); 29065371af2STobias Grosser Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart); 29165371af2STobias Grosser Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true); 29265371af2STobias Grosser CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop); 29365371af2STobias Grosser Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true); 29407bee290SSiddharth Bhat 29507bee290SSiddharth Bhat Value *CyclesInCurrentScop = Builder.CreateLoad(CyclesInCurrentScopPtr, true); 29607bee290SSiddharth Bhat CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop); 29707bee290SSiddharth Bhat Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true); 298726c28f8SSiddharth Bhat 299726c28f8SSiddharth Bhat Value *TripCountForCurrentScop = 300726c28f8SSiddharth Bhat Builder.CreateLoad(TripCountForCurrentScopPtr, true); 301726c28f8SSiddharth Bhat TripCountForCurrentScop = 302726c28f8SSiddharth Bhat Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1)); 303726c28f8SSiddharth Bhat Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr, 304726c28f8SSiddharth Bhat true); 30565371af2STobias Grosser } 306