From: Justin Bogner Date: Fri, 18 Apr 2014 21:52:00 +0000 (+0000) Subject: CodeGen: Use LLVM's InstrProfReader in -fprofile-instr-use= X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2a840244b1b655e5863a05bd2e860c31853eacd2;p=clang CodeGen: Use LLVM's InstrProfReader in -fprofile-instr-use= Update clang to use the InstrProfReader from LLVM to read instrumentation based profile data. This also switches us from the naive text format to the binary format, since that's what's implemented in the reader. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206658 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 12cb1ab255..0d49a0951c 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS Linker MC ObjCARCOpts + ProfileData ScalarOpts Support Target diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d4daaa55c7..69a9092e1c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -47,6 +47,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" @@ -78,7 +79,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0), TheTargetCodeGenInfo(0), Types(*this), VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0), - NoObjCARCExceptionsMetadata(0), RRData(0), PGOData(0), + NoObjCARCExceptionsMetadata(0), RRData(0), PGOReader(nullptr), CFConstantStringClassRef(0), ConstantStringClassRef(0), NSConstantStringType(0), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0), @@ -134,8 +135,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, ARCData = new ARCEntrypoints(); RRData = new RREntrypoints(); - if (!CodeGenOpts.InstrProfileInput.empty()) - PGOData = new PGOProfileData(*this, CodeGenOpts.InstrProfileInput); + if (!CodeGenOpts.InstrProfileInput.empty()) { + if (llvm::error_code EC = llvm::IndexedInstrProfReader::create( + CodeGenOpts.InstrProfileInput, PGOReader)) { + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "Could not read profile: %0"); + getDiags().Report(DiagID) << EC.message(); + } + } } CodeGenModule::~CodeGenModule() { @@ -286,7 +293,7 @@ void CodeGenModule::Release() { if (getCodeGenOpts().ProfileInstrGenerate) if (llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this)) AddGlobalCtor(PGOInit, 0); - if (PGOData && PGOStats.isOutOfDate()) + if (PGOReader && PGOStats.isOutOfDate()) getDiags().Report(diag::warn_profile_data_out_of_date) << PGOStats.Visited << PGOStats.Missing << PGOStats.Mismatched; EmitCtorList(GlobalCtors, "llvm.global_ctors"); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index f6614dd44b..0fd325b083 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -42,6 +42,7 @@ namespace llvm { class DataLayout; class FunctionType; class LLVMContext; + class IndexedInstrProfReader; } namespace clang { @@ -85,7 +86,6 @@ namespace CodeGen { class CGCUDARuntime; class BlockFieldFlags; class FunctionArgList; - class PGOProfileData; struct OrderGlobalInits { unsigned int priority; @@ -266,7 +266,7 @@ class CodeGenModule : public CodeGenTypeCache { ARCEntrypoints *ARCData; llvm::MDNode *NoObjCARCExceptionsMetadata; RREntrypoints *RRData; - PGOProfileData *PGOData; + std::unique_ptr PGOReader; InstrProfStats PGOStats; // WeakRefReferences - A set of references that have only been seen via @@ -493,13 +493,8 @@ public: return *RRData; } - InstrProfStats &getPGOStats() { - return PGOStats; - } - - PGOProfileData *getPGOData() const { - return PGOData; - } + InstrProfStats &getPGOStats() { return PGOStats; } + llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); } llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) { return StaticLocalDeclMap[D]; diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp index 28e9c0b046..aaeafd1a64 100644 --- a/lib/CodeGen/CodeGenPGO.cpp +++ b/lib/CodeGen/CodeGenPGO.cpp @@ -17,6 +17,7 @@ #include "clang/AST/StmtVisitor.h" #include "llvm/Config/config.h" // for strtoull()/strtoul() define #include "llvm/IR/MDBuilder.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" @@ -24,136 +25,6 @@ using namespace clang; using namespace CodeGen; -static void ReportBadPGOData(CodeGenModule &CGM, const char *Message) { - DiagnosticsEngine &Diags = CGM.getDiags(); - unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"); - Diags.Report(diagID) << Message; -} - -PGOProfileData::PGOProfileData(CodeGenModule &CGM, std::string Path) - : CGM(CGM) { - if (llvm::MemoryBuffer::getFile(Path, DataBuffer)) { - ReportBadPGOData(CGM, "failed to open pgo data file"); - return; - } - - if (DataBuffer->getBufferSize() > std::numeric_limits::max()) { - ReportBadPGOData(CGM, "pgo data file too big"); - return; - } - - // Scan through the data file and map each function to the corresponding - // file offset where its counts are stored. - const char *BufferStart = DataBuffer->getBufferStart(); - const char *BufferEnd = DataBuffer->getBufferEnd(); - const char *CurPtr = BufferStart; - uint64_t MaxCount = 0; - while (CurPtr < BufferEnd) { - // Read the function name. - const char *FuncStart = CurPtr; - // For Objective-C methods, the name may include whitespace, so search - // backward from the end of the line to find the space that separates the - // name from the number of counters. (This is a temporary hack since we are - // going to completely replace this file format in the near future.) - CurPtr = strchr(CurPtr, '\n'); - if (!CurPtr) { - ReportBadPGOData(CGM, "pgo data file has malformed function entry"); - return; - } - StringRef FuncName(FuncStart, CurPtr - FuncStart); - - // Skip over the function hash. - CurPtr = strchr(++CurPtr, '\n'); - if (!CurPtr) { - ReportBadPGOData(CGM, "pgo data file is missing the function hash"); - return; - } - - // Read the number of counters. - char *EndPtr; - unsigned NumCounters = strtoul(++CurPtr, &EndPtr, 10); - if (EndPtr == CurPtr || *EndPtr != '\n' || NumCounters <= 0) { - ReportBadPGOData(CGM, "pgo data file has unexpected number of counters"); - return; - } - CurPtr = EndPtr; - - // Read function count. - uint64_t Count = strtoull(CurPtr, &EndPtr, 10); - if (EndPtr == CurPtr || *EndPtr != '\n') { - ReportBadPGOData(CGM, "pgo-data file has bad count value"); - return; - } - CurPtr = EndPtr; // Point to '\n'. - FunctionCounts[FuncName] = Count; - MaxCount = Count > MaxCount ? Count : MaxCount; - - // There is one line for each counter; skip over those lines. - // Since function count is already read, we start the loop from 1. - for (unsigned N = 1; N < NumCounters; ++N) { - CurPtr = strchr(++CurPtr, '\n'); - if (!CurPtr) { - ReportBadPGOData(CGM, "pgo data file is missing some counter info"); - return; - } - } - - // Skip over the blank line separating functions. - CurPtr += 2; - - DataOffsets[FuncName] = FuncStart - BufferStart; - } - MaxFunctionCount = MaxCount; -} - -bool PGOProfileData::getFunctionCounts(StringRef FuncName, uint64_t &FuncHash, - std::vector &Counts) { - // Find the relevant section of the pgo-data file. - llvm::StringMap::const_iterator OffsetIter = - DataOffsets.find(FuncName); - if (OffsetIter == DataOffsets.end()) - return true; - const char *CurPtr = DataBuffer->getBufferStart() + OffsetIter->getValue(); - - // Skip over the function name. - CurPtr = strchr(CurPtr, '\n'); - assert(CurPtr && "pgo-data has corrupted function entry"); - - char *EndPtr; - // Read the function hash. - FuncHash = strtoull(++CurPtr, &EndPtr, 10); - assert(EndPtr != CurPtr && *EndPtr == '\n' && - "pgo-data file has corrupted function hash"); - CurPtr = EndPtr; - - // Read the number of counters. - unsigned NumCounters = strtoul(++CurPtr, &EndPtr, 10); - assert(EndPtr != CurPtr && *EndPtr == '\n' && NumCounters > 0 && - "pgo-data file has corrupted number of counters"); - CurPtr = EndPtr; - - Counts.reserve(NumCounters); - - for (unsigned N = 0; N < NumCounters; ++N) { - // Read the count value. - uint64_t Count = strtoull(CurPtr, &EndPtr, 10); - if (EndPtr == CurPtr || *EndPtr != '\n') { - ReportBadPGOData(CGM, "pgo-data file has bad count value"); - return true; - } - Counts.push_back(Count); - CurPtr = EndPtr + 1; - } - - // Make sure the number of counters matches up. - if (Counts.size() != NumCounters) { - ReportBadPGOData(CGM, "pgo-data file has inconsistent counters"); - return true; - } - - return false; -} - void CodeGenPGO::setFuncName(llvm::Function *Fn) { RawFuncName = Fn->getName(); @@ -930,8 +801,8 @@ static void emitRuntimeHook(CodeGenModule &CGM) { void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) { bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate; - PGOProfileData *PGOData = CGM.getPGOData(); - if (!InstrumentRegions && !PGOData) + llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); + if (!InstrumentRegions && !PGOReader) return; if (!D) return; @@ -957,10 +828,10 @@ void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) { emitRuntimeHook(CGM); emitCounterVariables(); } - if (PGOData) { - loadRegionCounts(PGOData); + if (PGOReader) { + loadRegionCounts(PGOReader); computeRegionCounts(D); - applyFunctionAttributes(PGOData, Fn); + applyFunctionAttributes(PGOReader, Fn); } } @@ -992,12 +863,13 @@ void CodeGenPGO::computeRegionCounts(const Decl *D) { Walker.VisitCapturedDecl(const_cast(CD)); } -void CodeGenPGO::applyFunctionAttributes(PGOProfileData *PGOData, - llvm::Function *Fn) { +void +CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader, + llvm::Function *Fn) { if (!haveRegionCounts()) return; - uint64_t MaxFunctionCount = PGOData->getMaximumFunctionCount(); + uint64_t MaxFunctionCount = PGOReader->getMaximumFunctionCount(); uint64_t FunctionCount = getRegionCount(0); if (FunctionCount >= (uint64_t)(0.3 * (double)MaxFunctionCount)) // Turn on InlineHint attribute for hot functions. @@ -1031,11 +903,11 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter) { Builder.CreateStore(Count, Addr); } -void CodeGenPGO::loadRegionCounts(PGOProfileData *PGOData) { +void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader) { CGM.getPGOStats().Visited++; RegionCounts.reset(new std::vector); uint64_t Hash; - if (PGOData->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) { + if (PGOReader->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) { CGM.getPGOStats().Missing++; RegionCounts.reset(); } else if (Hash != FunctionHash || diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h index c59a58e3f8..98e5b1fd1a 100644 --- a/lib/CodeGen/CodeGenPGO.h +++ b/lib/CodeGen/CodeGenPGO.h @@ -26,28 +26,6 @@ namespace clang { namespace CodeGen { class RegionCounter; -/// The raw counter data from an instrumented PGO binary -class PGOProfileData { -private: - /// The PGO data - std::unique_ptr DataBuffer; - /// Offsets into DataBuffer for each function's counters - llvm::StringMap DataOffsets; - /// Execution counts for each function. - llvm::StringMap FunctionCounts; - /// The maximal execution count among all functions. - uint64_t MaxFunctionCount; - CodeGenModule &CGM; -public: - PGOProfileData(CodeGenModule &CGM, std::string Path); - /// Fill Counts with the profile data for the given function name. Returns - /// false on success. - bool getFunctionCounts(StringRef FuncName, uint64_t &FuncHash, - std::vector &Counts); - /// Return the maximum of all known function counts. - uint64_t getMaximumFunctionCount() { return MaxFunctionCount; } -}; - /// Per-function PGO state. This class should generally not be used directly, /// but instead through the CodeGenFunction and RegionCounter types. class CodeGenPGO { @@ -138,8 +116,9 @@ private: void setFuncName(llvm::Function *Fn); void mapRegionCounters(const Decl *D); void computeRegionCounts(const Decl *D); - void applyFunctionAttributes(PGOProfileData *PGOData, llvm::Function *Fn); - void loadRegionCounts(PGOProfileData *PGOData); + void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader, + llvm::Function *Fn); + void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader); void emitCounterVariables(); llvm::GlobalVariable *buildDataVar(); diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index f60162f5e1..67d2115b84 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -10,6 +10,7 @@ set( LLVM_LINK_COMPONENTS MCParser ObjCARCOpts Option + ProfileData ScalarOpts Support TransformUtils diff --git a/tools/driver/Makefile b/tools/driver/Makefile index d75b19cf2a..7404496875 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -33,7 +33,7 @@ endif LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \ instrumentation ipo irreader linker objcarcopts option \ - selectiondag + profiledata selectiondag USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a