Path: blob/main/contrib/llvm-project/llvm/lib/ProfileData/InstrProf.cpp
35233 views
//===- InstrProf.cpp - Instrumented profiling format support --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains support for clang's instrumentation based PGO and9// coverage.10//11//===----------------------------------------------------------------------===//1213#include "llvm/ProfileData/InstrProf.h"14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Config/config.h"19#include "llvm/IR/Constant.h"20#include "llvm/IR/Constants.h"21#include "llvm/IR/Function.h"22#include "llvm/IR/GlobalValue.h"23#include "llvm/IR/GlobalVariable.h"24#include "llvm/IR/Instruction.h"25#include "llvm/IR/LLVMContext.h"26#include "llvm/IR/MDBuilder.h"27#include "llvm/IR/Metadata.h"28#include "llvm/IR/Module.h"29#include "llvm/IR/Type.h"30#include "llvm/ProfileData/InstrProfReader.h"31#include "llvm/Support/Casting.h"32#include "llvm/Support/CommandLine.h"33#include "llvm/Support/Compiler.h"34#include "llvm/Support/Compression.h"35#include "llvm/Support/Debug.h"36#include "llvm/Support/Endian.h"37#include "llvm/Support/Error.h"38#include "llvm/Support/ErrorHandling.h"39#include "llvm/Support/LEB128.h"40#include "llvm/Support/MathExtras.h"41#include "llvm/Support/Path.h"42#include "llvm/Support/SwapByteOrder.h"43#include "llvm/Support/VirtualFileSystem.h"44#include "llvm/TargetParser/Triple.h"45#include <algorithm>46#include <cassert>47#include <cstddef>48#include <cstdint>49#include <cstring>50#include <memory>51#include <string>52#include <system_error>53#include <type_traits>54#include <utility>55#include <vector>5657using namespace llvm;5859#define DEBUG_TYPE "instrprof"6061static cl::opt<bool> StaticFuncFullModulePrefix(62"static-func-full-module-prefix", cl::init(true), cl::Hidden,63cl::desc("Use full module build paths in the profile counter names for "64"static functions."));6566// This option is tailored to users that have different top-level directory in67// profile-gen and profile-use compilation. Users need to specific the number68// of levels to strip. A value larger than the number of directories in the69// source file will strip all the directory names and only leave the basename.70//71// Note current ThinLTO module importing for the indirect-calls assumes72// the source directory name not being stripped. A non-zero option value here73// can potentially prevent some inter-module indirect-call-promotions.74static cl::opt<unsigned> StaticFuncStripDirNamePrefix(75"static-func-strip-dirname-prefix", cl::init(0), cl::Hidden,76cl::desc("Strip specified level of directory name from source path in "77"the profile counter name for static functions."));7879static std::string getInstrProfErrString(instrprof_error Err,80const std::string &ErrMsg = "") {81std::string Msg;82raw_string_ostream OS(Msg);8384switch (Err) {85case instrprof_error::success:86OS << "success";87break;88case instrprof_error::eof:89OS << "end of File";90break;91case instrprof_error::unrecognized_format:92OS << "unrecognized instrumentation profile encoding format";93break;94case instrprof_error::bad_magic:95OS << "invalid instrumentation profile data (bad magic)";96break;97case instrprof_error::bad_header:98OS << "invalid instrumentation profile data (file header is corrupt)";99break;100case instrprof_error::unsupported_version:101OS << "unsupported instrumentation profile format version";102break;103case instrprof_error::unsupported_hash_type:104OS << "unsupported instrumentation profile hash type";105break;106case instrprof_error::too_large:107OS << "too much profile data";108break;109case instrprof_error::truncated:110OS << "truncated profile data";111break;112case instrprof_error::malformed:113OS << "malformed instrumentation profile data";114break;115case instrprof_error::missing_correlation_info:116OS << "debug info/binary for correlation is required";117break;118case instrprof_error::unexpected_correlation_info:119OS << "debug info/binary for correlation is not necessary";120break;121case instrprof_error::unable_to_correlate_profile:122OS << "unable to correlate profile";123break;124case instrprof_error::invalid_prof:125OS << "invalid profile created. Please file a bug "126"at: " BUG_REPORT_URL127" and include the profraw files that caused this error.";128break;129case instrprof_error::unknown_function:130OS << "no profile data available for function";131break;132case instrprof_error::hash_mismatch:133OS << "function control flow change detected (hash mismatch)";134break;135case instrprof_error::count_mismatch:136OS << "function basic block count change detected (counter mismatch)";137break;138case instrprof_error::bitmap_mismatch:139OS << "function bitmap size change detected (bitmap size mismatch)";140break;141case instrprof_error::counter_overflow:142OS << "counter overflow";143break;144case instrprof_error::value_site_count_mismatch:145OS << "function value site count change detected (counter mismatch)";146break;147case instrprof_error::compress_failed:148OS << "failed to compress data (zlib)";149break;150case instrprof_error::uncompress_failed:151OS << "failed to uncompress data (zlib)";152break;153case instrprof_error::empty_raw_profile:154OS << "empty raw profile file";155break;156case instrprof_error::zlib_unavailable:157OS << "profile uses zlib compression but the profile reader was built "158"without zlib support";159break;160case instrprof_error::raw_profile_version_mismatch:161OS << "raw profile version mismatch";162break;163case instrprof_error::counter_value_too_large:164OS << "excessively large counter value suggests corrupted profile data";165break;166}167168// If optional error message is not empty, append it to the message.169if (!ErrMsg.empty())170OS << ": " << ErrMsg;171172return OS.str();173}174175namespace {176177// FIXME: This class is only here to support the transition to llvm::Error. It178// will be removed once this transition is complete. Clients should prefer to179// deal with the Error value directly, rather than converting to error_code.180class InstrProfErrorCategoryType : public std::error_category {181const char *name() const noexcept override { return "llvm.instrprof"; }182183std::string message(int IE) const override {184return getInstrProfErrString(static_cast<instrprof_error>(IE));185}186};187188} // end anonymous namespace189190const std::error_category &llvm::instrprof_category() {191static InstrProfErrorCategoryType ErrorCategory;192return ErrorCategory;193}194195namespace {196197const char *InstrProfSectNameCommon[] = {198#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \199SectNameCommon,200#include "llvm/ProfileData/InstrProfData.inc"201};202203const char *InstrProfSectNameCoff[] = {204#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \205SectNameCoff,206#include "llvm/ProfileData/InstrProfData.inc"207};208209const char *InstrProfSectNamePrefix[] = {210#define INSTR_PROF_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \211Prefix,212#include "llvm/ProfileData/InstrProfData.inc"213};214215} // namespace216217namespace llvm {218219cl::opt<bool> DoInstrProfNameCompression(220"enable-name-compression",221cl::desc("Enable name/filename string compression"), cl::init(true));222223cl::opt<bool> EnableVTableValueProfiling(224"enable-vtable-value-profiling", cl::init(false),225cl::desc("If true, the virtual table address will be instrumented to know "226"the types of a C++ pointer. The information is used in indirect "227"call promotion to do selective vtable-based comparison."));228229cl::opt<bool> EnableVTableProfileUse(230"enable-vtable-profile-use", cl::init(false),231cl::desc("If ThinLTO and WPD is enabled and this option is true, vtable "232"profiles will be used by ICP pass for more efficient indirect "233"call sequence. If false, type profiles won't be used."));234235std::string getInstrProfSectionName(InstrProfSectKind IPSK,236Triple::ObjectFormatType OF,237bool AddSegmentInfo) {238std::string SectName;239240if (OF == Triple::MachO && AddSegmentInfo)241SectName = InstrProfSectNamePrefix[IPSK];242243if (OF == Triple::COFF)244SectName += InstrProfSectNameCoff[IPSK];245else246SectName += InstrProfSectNameCommon[IPSK];247248if (OF == Triple::MachO && IPSK == IPSK_data && AddSegmentInfo)249SectName += ",regular,live_support";250251return SectName;252}253254std::string InstrProfError::message() const {255return getInstrProfErrString(Err, Msg);256}257258char InstrProfError::ID = 0;259260std::string getPGOFuncName(StringRef Name, GlobalValue::LinkageTypes Linkage,261StringRef FileName,262uint64_t Version LLVM_ATTRIBUTE_UNUSED) {263// Value names may be prefixed with a binary '1' to indicate264// that the backend should not modify the symbols due to any platform265// naming convention. Do not include that '1' in the PGO profile name.266if (Name[0] == '\1')267Name = Name.substr(1);268269std::string NewName = std::string(Name);270if (llvm::GlobalValue::isLocalLinkage(Linkage)) {271// For local symbols, prepend the main file name to distinguish them.272// Do not include the full path in the file name since there's no guarantee273// that it will stay the same, e.g., if the files are checked out from274// version control in different locations.275if (FileName.empty())276NewName = NewName.insert(0, "<unknown>:");277else278NewName = NewName.insert(0, FileName.str() + ":");279}280return NewName;281}282283// Strip NumPrefix level of directory name from PathNameStr. If the number of284// directory separators is less than NumPrefix, strip all the directories and285// leave base file name only.286static StringRef stripDirPrefix(StringRef PathNameStr, uint32_t NumPrefix) {287uint32_t Count = NumPrefix;288uint32_t Pos = 0, LastPos = 0;289for (const auto &CI : PathNameStr) {290++Pos;291if (llvm::sys::path::is_separator(CI)) {292LastPos = Pos;293--Count;294}295if (Count == 0)296break;297}298return PathNameStr.substr(LastPos);299}300301static StringRef getStrippedSourceFileName(const GlobalObject &GO) {302StringRef FileName(GO.getParent()->getSourceFileName());303uint32_t StripLevel = StaticFuncFullModulePrefix ? 0 : (uint32_t)-1;304if (StripLevel < StaticFuncStripDirNamePrefix)305StripLevel = StaticFuncStripDirNamePrefix;306if (StripLevel)307FileName = stripDirPrefix(FileName, StripLevel);308return FileName;309}310311// The PGO name has the format [<filepath>;]<mangled-name> where <filepath>; is312// provided if linkage is local and is used to discriminate possibly identical313// mangled names. ";" is used because it is unlikely to be found in either314// <filepath> or <mangled-name>.315//316// Older compilers used getPGOFuncName() which has the format317// [<filepath>:]<mangled-name>. This caused trouble for Objective-C functions318// which commonly have :'s in their names. We still need to compute this name to319// lookup functions from profiles built by older compilers.320static std::string321getIRPGONameForGlobalObject(const GlobalObject &GO,322GlobalValue::LinkageTypes Linkage,323StringRef FileName) {324return GlobalValue::getGlobalIdentifier(GO.getName(), Linkage, FileName);325}326327static std::optional<std::string> lookupPGONameFromMetadata(MDNode *MD) {328if (MD != nullptr) {329StringRef S = cast<MDString>(MD->getOperand(0))->getString();330return S.str();331}332return {};333}334335// Returns the PGO object name. This function has some special handling336// when called in LTO optimization. The following only applies when calling in337// LTO passes (when \c InLTO is true): LTO's internalization privatizes many338// global linkage symbols. This happens after value profile annotation, but339// those internal linkage functions should not have a source prefix.340// Additionally, for ThinLTO mode, exported internal functions are promoted341// and renamed. We need to ensure that the original internal PGO name is342// used when computing the GUID that is compared against the profiled GUIDs.343// To differentiate compiler generated internal symbols from original ones,344// PGOFuncName meta data are created and attached to the original internal345// symbols in the value profile annotation step346// (PGOUseFunc::annotateIndirectCallSites). If a symbol does not have the meta347// data, its original linkage must be non-internal.348static std::string getIRPGOObjectName(const GlobalObject &GO, bool InLTO,349MDNode *PGONameMetadata) {350if (!InLTO) {351auto FileName = getStrippedSourceFileName(GO);352return getIRPGONameForGlobalObject(GO, GO.getLinkage(), FileName);353}354355// In LTO mode (when InLTO is true), first check if there is a meta data.356if (auto IRPGOFuncName = lookupPGONameFromMetadata(PGONameMetadata))357return *IRPGOFuncName;358359// If there is no meta data, the function must be a global before the value360// profile annotation pass. Its current linkage may be internal if it is361// internalized in LTO mode.362return getIRPGONameForGlobalObject(GO, GlobalValue::ExternalLinkage, "");363}364365// Returns the IRPGO function name and does special handling when called366// in LTO optimization. See the comments of `getIRPGOObjectName` for details.367std::string getIRPGOFuncName(const Function &F, bool InLTO) {368return getIRPGOObjectName(F, InLTO, getPGOFuncNameMetadata(F));369}370371// Please use getIRPGOFuncName for LLVM IR instrumentation. This function is372// for front-end (Clang, etc) instrumentation.373// The implementation is kept for profile matching from older profiles.374// This is similar to `getIRPGOFuncName` except that this function calls375// 'getPGOFuncName' to get a name and `getIRPGOFuncName` calls376// 'getIRPGONameForGlobalObject'. See the difference between two callees in the377// comments of `getIRPGONameForGlobalObject`.378std::string getPGOFuncName(const Function &F, bool InLTO, uint64_t Version) {379if (!InLTO) {380auto FileName = getStrippedSourceFileName(F);381return getPGOFuncName(F.getName(), F.getLinkage(), FileName, Version);382}383384// In LTO mode (when InLTO is true), first check if there is a meta data.385if (auto PGOFuncName = lookupPGONameFromMetadata(getPGOFuncNameMetadata(F)))386return *PGOFuncName;387388// If there is no meta data, the function must be a global before the value389// profile annotation pass. Its current linkage may be internal if it is390// internalized in LTO mode.391return getPGOFuncName(F.getName(), GlobalValue::ExternalLinkage, "");392}393394std::string getPGOName(const GlobalVariable &V, bool InLTO) {395// PGONameMetadata should be set by compiler at profile use time396// and read by symtab creation to look up symbols corresponding to397// a MD5 hash.398return getIRPGOObjectName(V, InLTO, V.getMetadata(getPGONameMetadataName()));399}400401// See getIRPGOObjectName() for a discription of the format.402std::pair<StringRef, StringRef> getParsedIRPGOName(StringRef IRPGOName) {403auto [FileName, MangledName] = IRPGOName.split(GlobalIdentifierDelimiter);404if (MangledName.empty())405return std::make_pair(StringRef(), IRPGOName);406return std::make_pair(FileName, MangledName);407}408409StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName) {410if (FileName.empty())411return PGOFuncName;412// Drop the file name including ':' or ';'. See getIRPGONameForGlobalObject as413// well.414if (PGOFuncName.starts_with(FileName))415PGOFuncName = PGOFuncName.drop_front(FileName.size() + 1);416return PGOFuncName;417}418419// \p FuncName is the string used as profile lookup key for the function. A420// symbol is created to hold the name. Return the legalized symbol name.421std::string getPGOFuncNameVarName(StringRef FuncName,422GlobalValue::LinkageTypes Linkage) {423std::string VarName = std::string(getInstrProfNameVarPrefix());424VarName += FuncName;425426if (!GlobalValue::isLocalLinkage(Linkage))427return VarName;428429// Now fix up illegal chars in local VarName that may upset the assembler.430const char InvalidChars[] = "-:;<>/\"'";431size_t FoundPos = VarName.find_first_of(InvalidChars);432while (FoundPos != std::string::npos) {433VarName[FoundPos] = '_';434FoundPos = VarName.find_first_of(InvalidChars, FoundPos + 1);435}436return VarName;437}438439GlobalVariable *createPGOFuncNameVar(Module &M,440GlobalValue::LinkageTypes Linkage,441StringRef PGOFuncName) {442// We generally want to match the function's linkage, but available_externally443// and extern_weak both have the wrong semantics, and anything that doesn't444// need to link across compilation units doesn't need to be visible at all.445if (Linkage == GlobalValue::ExternalWeakLinkage)446Linkage = GlobalValue::LinkOnceAnyLinkage;447else if (Linkage == GlobalValue::AvailableExternallyLinkage)448Linkage = GlobalValue::LinkOnceODRLinkage;449else if (Linkage == GlobalValue::InternalLinkage ||450Linkage == GlobalValue::ExternalLinkage)451Linkage = GlobalValue::PrivateLinkage;452453auto *Value =454ConstantDataArray::getString(M.getContext(), PGOFuncName, false);455auto *FuncNameVar =456new GlobalVariable(M, Value->getType(), true, Linkage, Value,457getPGOFuncNameVarName(PGOFuncName, Linkage));458459// Hide the symbol so that we correctly get a copy for each executable.460if (!GlobalValue::isLocalLinkage(FuncNameVar->getLinkage()))461FuncNameVar->setVisibility(GlobalValue::HiddenVisibility);462463return FuncNameVar;464}465466GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName) {467return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), PGOFuncName);468}469470Error InstrProfSymtab::create(Module &M, bool InLTO) {471for (Function &F : M) {472// Function may not have a name: like using asm("") to overwrite the name.473// Ignore in this case.474if (!F.hasName())475continue;476if (Error E = addFuncWithName(F, getIRPGOFuncName(F, InLTO)))477return E;478// Also use getPGOFuncName() so that we can find records from older profiles479if (Error E = addFuncWithName(F, getPGOFuncName(F, InLTO)))480return E;481}482483SmallVector<MDNode *, 2> Types;484for (GlobalVariable &G : M.globals()) {485if (!G.hasName() || !G.hasMetadata(LLVMContext::MD_type))486continue;487if (Error E = addVTableWithName(G, getPGOName(G, InLTO)))488return E;489}490491Sorted = false;492finalizeSymtab();493return Error::success();494}495496Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,497StringRef VTablePGOName) {498auto NameToGUIDMap = [&](StringRef Name) -> Error {499if (Error E = addSymbolName(Name))500return E;501502bool Inserted = true;503std::tie(std::ignore, Inserted) =504MD5VTableMap.try_emplace(GlobalValue::getGUID(Name), &VTable);505if (!Inserted)506LLVM_DEBUG(dbgs() << "GUID conflict within one module");507return Error::success();508};509if (Error E = NameToGUIDMap(VTablePGOName))510return E;511512StringRef CanonicalName = getCanonicalName(VTablePGOName);513if (CanonicalName != VTablePGOName)514return NameToGUIDMap(CanonicalName);515516return Error::success();517}518519/// \c NameStrings is a string composed of one of more possibly encoded520/// sub-strings. The substrings are separated by 0 or more zero bytes. This521/// method decodes the string and calls `NameCallback` for each substring.522static Error523readAndDecodeStrings(StringRef NameStrings,524std::function<Error(StringRef)> NameCallback) {525const uint8_t *P = NameStrings.bytes_begin();526const uint8_t *EndP = NameStrings.bytes_end();527while (P < EndP) {528uint32_t N;529uint64_t UncompressedSize = decodeULEB128(P, &N);530P += N;531uint64_t CompressedSize = decodeULEB128(P, &N);532P += N;533const bool IsCompressed = (CompressedSize != 0);534SmallVector<uint8_t, 128> UncompressedNameStrings;535StringRef NameStrings;536if (IsCompressed) {537if (!llvm::compression::zlib::isAvailable())538return make_error<InstrProfError>(instrprof_error::zlib_unavailable);539540if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize),541UncompressedNameStrings,542UncompressedSize)) {543consumeError(std::move(E));544return make_error<InstrProfError>(instrprof_error::uncompress_failed);545}546P += CompressedSize;547NameStrings = toStringRef(UncompressedNameStrings);548} else {549NameStrings =550StringRef(reinterpret_cast<const char *>(P), UncompressedSize);551P += UncompressedSize;552}553// Now parse the name strings.554SmallVector<StringRef, 0> Names;555NameStrings.split(Names, getInstrProfNameSeparator());556for (StringRef &Name : Names)557if (Error E = NameCallback(Name))558return E;559560while (P < EndP && *P == 0)561P++;562}563return Error::success();564}565566Error InstrProfSymtab::create(StringRef NameStrings) {567return readAndDecodeStrings(568NameStrings,569std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1));570}571572Error InstrProfSymtab::create(StringRef FuncNameStrings,573StringRef VTableNameStrings) {574if (Error E = readAndDecodeStrings(FuncNameStrings,575std::bind(&InstrProfSymtab::addFuncName,576this, std::placeholders::_1)))577return E;578579return readAndDecodeStrings(580VTableNameStrings,581std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1));582}583584Error InstrProfSymtab::initVTableNamesFromCompressedStrings(585StringRef CompressedVTableStrings) {586return readAndDecodeStrings(587CompressedVTableStrings,588std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1));589}590591StringRef InstrProfSymtab::getCanonicalName(StringRef PGOName) {592// In ThinLTO, local function may have been promoted to global and have593// suffix ".llvm." added to the function name. We need to add the594// stripped function name to the symbol table so that we can find a match595// from profile.596//597// ".__uniq." suffix is used to differentiate internal linkage functions in598// different modules and should be kept. This is the only suffix with the599// pattern ".xxx" which is kept before matching, other suffixes similar as600// ".llvm." will be stripped.601const std::string UniqSuffix = ".__uniq.";602size_t Pos = PGOName.find(UniqSuffix);603if (Pos != StringRef::npos)604Pos += UniqSuffix.length();605else606Pos = 0;607608// Search '.' after ".__uniq." if ".__uniq." exists, otherwise search '.' from609// the beginning.610Pos = PGOName.find('.', Pos);611if (Pos != StringRef::npos && Pos != 0)612return PGOName.substr(0, Pos);613614return PGOName;615}616617Error InstrProfSymtab::addFuncWithName(Function &F, StringRef PGOFuncName) {618auto NameToGUIDMap = [&](StringRef Name) -> Error {619if (Error E = addFuncName(Name))620return E;621MD5FuncMap.emplace_back(Function::getGUID(Name), &F);622return Error::success();623};624if (Error E = NameToGUIDMap(PGOFuncName))625return E;626627StringRef CanonicalFuncName = getCanonicalName(PGOFuncName);628if (CanonicalFuncName != PGOFuncName)629return NameToGUIDMap(CanonicalFuncName);630631return Error::success();632}633634uint64_t InstrProfSymtab::getVTableHashFromAddress(uint64_t Address) {635// Given a runtime address, look up the hash value in the interval map, and636// fallback to value 0 if a hash value is not found.637return VTableAddrMap.lookup(Address, 0);638}639640uint64_t InstrProfSymtab::getFunctionHashFromAddress(uint64_t Address) {641finalizeSymtab();642auto It = partition_point(AddrToMD5Map, [=](std::pair<uint64_t, uint64_t> A) {643return A.first < Address;644});645// Raw function pointer collected by value profiler may be from646// external functions that are not instrumented. They won't have647// mapping data to be used by the deserializer. Force the value to648// be 0 in this case.649if (It != AddrToMD5Map.end() && It->first == Address)650return (uint64_t)It->second;651return 0;652}653654void InstrProfSymtab::dumpNames(raw_ostream &OS) const {655SmallVector<StringRef, 0> Sorted(NameTab.keys());656llvm::sort(Sorted);657for (StringRef S : Sorted)658OS << S << '\n';659}660661Error collectGlobalObjectNameStrings(ArrayRef<std::string> NameStrs,662bool DoCompression, std::string &Result) {663assert(!NameStrs.empty() && "No name data to emit");664665uint8_t Header[20], *P = Header;666std::string UncompressedNameStrings =667join(NameStrs.begin(), NameStrs.end(), getInstrProfNameSeparator());668669assert(StringRef(UncompressedNameStrings)670.count(getInstrProfNameSeparator()) == (NameStrs.size() - 1) &&671"PGO name is invalid (contains separator token)");672673unsigned EncLen = encodeULEB128(UncompressedNameStrings.length(), P);674P += EncLen;675676auto WriteStringToResult = [&](size_t CompressedLen, StringRef InputStr) {677EncLen = encodeULEB128(CompressedLen, P);678P += EncLen;679char *HeaderStr = reinterpret_cast<char *>(&Header[0]);680unsigned HeaderLen = P - &Header[0];681Result.append(HeaderStr, HeaderLen);682Result += InputStr;683return Error::success();684};685686if (!DoCompression) {687return WriteStringToResult(0, UncompressedNameStrings);688}689690SmallVector<uint8_t, 128> CompressedNameStrings;691compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings),692CompressedNameStrings,693compression::zlib::BestSizeCompression);694695return WriteStringToResult(CompressedNameStrings.size(),696toStringRef(CompressedNameStrings));697}698699StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar) {700auto *Arr = cast<ConstantDataArray>(NameVar->getInitializer());701StringRef NameStr =702Arr->isCString() ? Arr->getAsCString() : Arr->getAsString();703return NameStr;704}705706Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars,707std::string &Result, bool DoCompression) {708std::vector<std::string> NameStrs;709for (auto *NameVar : NameVars) {710NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar)));711}712return collectGlobalObjectNameStrings(713NameStrs, compression::zlib::isAvailable() && DoCompression, Result);714}715716Error collectVTableStrings(ArrayRef<GlobalVariable *> VTables,717std::string &Result, bool DoCompression) {718std::vector<std::string> VTableNameStrs;719for (auto *VTable : VTables)720VTableNameStrs.push_back(getPGOName(*VTable));721return collectGlobalObjectNameStrings(722VTableNameStrs, compression::zlib::isAvailable() && DoCompression,723Result);724}725726void InstrProfRecord::accumulateCounts(CountSumOrPercent &Sum) const {727uint64_t FuncSum = 0;728Sum.NumEntries += Counts.size();729for (uint64_t Count : Counts)730FuncSum += Count;731Sum.CountSum += FuncSum;732733for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) {734uint64_t KindSum = 0;735uint32_t NumValueSites = getNumValueSites(VK);736for (size_t I = 0; I < NumValueSites; ++I) {737for (const auto &V : getValueArrayForSite(VK, I))738KindSum += V.Count;739}740Sum.ValueCounts[VK] += KindSum;741}742}743744void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input,745uint32_t ValueKind,746OverlapStats &Overlap,747OverlapStats &FuncLevelOverlap) {748this->sortByTargetValues();749Input.sortByTargetValues();750double Score = 0.0f, FuncLevelScore = 0.0f;751auto I = ValueData.begin();752auto IE = ValueData.end();753auto J = Input.ValueData.begin();754auto JE = Input.ValueData.end();755while (I != IE && J != JE) {756if (I->Value == J->Value) {757Score += OverlapStats::score(I->Count, J->Count,758Overlap.Base.ValueCounts[ValueKind],759Overlap.Test.ValueCounts[ValueKind]);760FuncLevelScore += OverlapStats::score(761I->Count, J->Count, FuncLevelOverlap.Base.ValueCounts[ValueKind],762FuncLevelOverlap.Test.ValueCounts[ValueKind]);763++I;764} else if (I->Value < J->Value) {765++I;766continue;767}768++J;769}770Overlap.Overlap.ValueCounts[ValueKind] += Score;771FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore;772}773774// Return false on mismatch.775void InstrProfRecord::overlapValueProfData(uint32_t ValueKind,776InstrProfRecord &Other,777OverlapStats &Overlap,778OverlapStats &FuncLevelOverlap) {779uint32_t ThisNumValueSites = getNumValueSites(ValueKind);780assert(ThisNumValueSites == Other.getNumValueSites(ValueKind));781if (!ThisNumValueSites)782return;783784std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =785getOrCreateValueSitesForKind(ValueKind);786MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords =787Other.getValueSitesForKind(ValueKind);788for (uint32_t I = 0; I < ThisNumValueSites; I++)789ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap,790FuncLevelOverlap);791}792793void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap,794OverlapStats &FuncLevelOverlap,795uint64_t ValueCutoff) {796// FuncLevel CountSum for other should already computed and nonzero.797assert(FuncLevelOverlap.Test.CountSum >= 1.0f);798accumulateCounts(FuncLevelOverlap.Base);799bool Mismatch = (Counts.size() != Other.Counts.size());800801// Check if the value profiles mismatch.802if (!Mismatch) {803for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {804uint32_t ThisNumValueSites = getNumValueSites(Kind);805uint32_t OtherNumValueSites = Other.getNumValueSites(Kind);806if (ThisNumValueSites != OtherNumValueSites) {807Mismatch = true;808break;809}810}811}812if (Mismatch) {813Overlap.addOneMismatch(FuncLevelOverlap.Test);814return;815}816817// Compute overlap for value counts.818for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)819overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap);820821double Score = 0.0;822uint64_t MaxCount = 0;823// Compute overlap for edge counts.824for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {825Score += OverlapStats::score(Counts[I], Other.Counts[I],826Overlap.Base.CountSum, Overlap.Test.CountSum);827MaxCount = std::max(Other.Counts[I], MaxCount);828}829Overlap.Overlap.CountSum += Score;830Overlap.Overlap.NumEntries += 1;831832if (MaxCount >= ValueCutoff) {833double FuncScore = 0.0;834for (size_t I = 0, E = Other.Counts.size(); I < E; ++I)835FuncScore += OverlapStats::score(Counts[I], Other.Counts[I],836FuncLevelOverlap.Base.CountSum,837FuncLevelOverlap.Test.CountSum);838FuncLevelOverlap.Overlap.CountSum = FuncScore;839FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size();840FuncLevelOverlap.Valid = true;841}842}843844void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input,845uint64_t Weight,846function_ref<void(instrprof_error)> Warn) {847this->sortByTargetValues();848Input.sortByTargetValues();849auto I = ValueData.begin();850auto IE = ValueData.end();851std::vector<InstrProfValueData> Merged;852Merged.reserve(std::max(ValueData.size(), Input.ValueData.size()));853for (const InstrProfValueData &J : Input.ValueData) {854while (I != IE && I->Value < J.Value) {855Merged.push_back(*I);856++I;857}858if (I != IE && I->Value == J.Value) {859bool Overflowed;860I->Count = SaturatingMultiplyAdd(J.Count, Weight, I->Count, &Overflowed);861if (Overflowed)862Warn(instrprof_error::counter_overflow);863Merged.push_back(*I);864++I;865continue;866}867Merged.push_back(J);868}869Merged.insert(Merged.end(), I, IE);870ValueData = std::move(Merged);871}872873void InstrProfValueSiteRecord::scale(uint64_t N, uint64_t D,874function_ref<void(instrprof_error)> Warn) {875for (InstrProfValueData &I : ValueData) {876bool Overflowed;877I.Count = SaturatingMultiply(I.Count, N, &Overflowed) / D;878if (Overflowed)879Warn(instrprof_error::counter_overflow);880}881}882883// Merge Value Profile data from Src record to this record for ValueKind.884// Scale merged value counts by \p Weight.885void InstrProfRecord::mergeValueProfData(886uint32_t ValueKind, InstrProfRecord &Src, uint64_t Weight,887function_ref<void(instrprof_error)> Warn) {888uint32_t ThisNumValueSites = getNumValueSites(ValueKind);889uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind);890if (ThisNumValueSites != OtherNumValueSites) {891Warn(instrprof_error::value_site_count_mismatch);892return;893}894if (!ThisNumValueSites)895return;896std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =897getOrCreateValueSitesForKind(ValueKind);898MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords =899Src.getValueSitesForKind(ValueKind);900for (uint32_t I = 0; I < ThisNumValueSites; I++)901ThisSiteRecords[I].merge(OtherSiteRecords[I], Weight, Warn);902}903904void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight,905function_ref<void(instrprof_error)> Warn) {906// If the number of counters doesn't match we either have bad data907// or a hash collision.908if (Counts.size() != Other.Counts.size()) {909Warn(instrprof_error::count_mismatch);910return;911}912913// Special handling of the first count as the PseudoCount.914CountPseudoKind OtherKind = Other.getCountPseudoKind();915CountPseudoKind ThisKind = getCountPseudoKind();916if (OtherKind != NotPseudo || ThisKind != NotPseudo) {917// We don't allow the merge of a profile with pseudo counts and918// a normal profile (i.e. without pesudo counts).919// Profile supplimenation should be done after the profile merge.920if (OtherKind == NotPseudo || ThisKind == NotPseudo) {921Warn(instrprof_error::count_mismatch);922return;923}924if (OtherKind == PseudoHot || ThisKind == PseudoHot)925setPseudoCount(PseudoHot);926else927setPseudoCount(PseudoWarm);928return;929}930931for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {932bool Overflowed;933uint64_t Value =934SaturatingMultiplyAdd(Other.Counts[I], Weight, Counts[I], &Overflowed);935if (Value > getInstrMaxCountValue()) {936Value = getInstrMaxCountValue();937Overflowed = true;938}939Counts[I] = Value;940if (Overflowed)941Warn(instrprof_error::counter_overflow);942}943944// If the number of bitmap bytes doesn't match we either have bad data945// or a hash collision.946if (BitmapBytes.size() != Other.BitmapBytes.size()) {947Warn(instrprof_error::bitmap_mismatch);948return;949}950951// Bitmap bytes are merged by simply ORing them together.952for (size_t I = 0, E = Other.BitmapBytes.size(); I < E; ++I) {953BitmapBytes[I] = Other.BitmapBytes[I] | BitmapBytes[I];954}955956for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)957mergeValueProfData(Kind, Other, Weight, Warn);958}959960void InstrProfRecord::scaleValueProfData(961uint32_t ValueKind, uint64_t N, uint64_t D,962function_ref<void(instrprof_error)> Warn) {963for (auto &R : getValueSitesForKind(ValueKind))964R.scale(N, D, Warn);965}966967void InstrProfRecord::scale(uint64_t N, uint64_t D,968function_ref<void(instrprof_error)> Warn) {969assert(D != 0 && "D cannot be 0");970for (auto &Count : this->Counts) {971bool Overflowed;972Count = SaturatingMultiply(Count, N, &Overflowed) / D;973if (Count > getInstrMaxCountValue()) {974Count = getInstrMaxCountValue();975Overflowed = true;976}977if (Overflowed)978Warn(instrprof_error::counter_overflow);979}980for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)981scaleValueProfData(Kind, N, D, Warn);982}983984// Map indirect call target name hash to name string.985uint64_t InstrProfRecord::remapValue(uint64_t Value, uint32_t ValueKind,986InstrProfSymtab *SymTab) {987if (!SymTab)988return Value;989990if (ValueKind == IPVK_IndirectCallTarget)991return SymTab->getFunctionHashFromAddress(Value);992993if (ValueKind == IPVK_VTableTarget)994return SymTab->getVTableHashFromAddress(Value);995996return Value;997}998999void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site,1000ArrayRef<InstrProfValueData> VData,1001InstrProfSymtab *ValueMap) {1002// Remap values.1003std::vector<InstrProfValueData> RemappedVD;1004RemappedVD.reserve(VData.size());1005for (const auto &V : VData) {1006uint64_t NewValue = remapValue(V.Value, ValueKind, ValueMap);1007RemappedVD.push_back({NewValue, V.Count});1008}10091010std::vector<InstrProfValueSiteRecord> &ValueSites =1011getOrCreateValueSitesForKind(ValueKind);1012assert(ValueSites.size() == Site);10131014// Add a new value site with remapped value profiling data.1015ValueSites.emplace_back(std::move(RemappedVD));1016}10171018void TemporalProfTraceTy::createBPFunctionNodes(1019ArrayRef<TemporalProfTraceTy> Traces, std::vector<BPFunctionNode> &Nodes,1020bool RemoveOutlierUNs) {1021using IDT = BPFunctionNode::IDT;1022using UtilityNodeT = BPFunctionNode::UtilityNodeT;1023UtilityNodeT MaxUN = 0;1024DenseMap<IDT, size_t> IdToFirstTimestamp;1025DenseMap<IDT, UtilityNodeT> IdToFirstUN;1026DenseMap<IDT, SmallVector<UtilityNodeT>> IdToUNs;1027// TODO: We need to use the Trace.Weight field to give more weight to more1028// important utilities1029for (auto &Trace : Traces) {1030size_t CutoffTimestamp = 1;1031for (size_t Timestamp = 0; Timestamp < Trace.FunctionNameRefs.size();1032Timestamp++) {1033IDT Id = Trace.FunctionNameRefs[Timestamp];1034auto [It, WasInserted] = IdToFirstTimestamp.try_emplace(Id, Timestamp);1035if (!WasInserted)1036It->getSecond() = std::min<size_t>(It->getSecond(), Timestamp);1037if (Timestamp >= CutoffTimestamp) {1038++MaxUN;1039CutoffTimestamp = 2 * Timestamp;1040}1041IdToFirstUN.try_emplace(Id, MaxUN);1042}1043for (auto &[Id, FirstUN] : IdToFirstUN)1044for (auto UN = FirstUN; UN <= MaxUN; ++UN)1045IdToUNs[Id].push_back(UN);1046++MaxUN;1047IdToFirstUN.clear();1048}10491050if (RemoveOutlierUNs) {1051DenseMap<UtilityNodeT, unsigned> UNFrequency;1052for (auto &[Id, UNs] : IdToUNs)1053for (auto &UN : UNs)1054++UNFrequency[UN];1055// Filter out utility nodes that are too infrequent or too prevalent to make1056// BalancedPartitioning more effective.1057for (auto &[Id, UNs] : IdToUNs)1058llvm::erase_if(UNs, [&](auto &UN) {1059return UNFrequency[UN] <= 1 || 2 * UNFrequency[UN] > IdToUNs.size();1060});1061}10621063for (auto &[Id, UNs] : IdToUNs)1064Nodes.emplace_back(Id, UNs);10651066// Since BalancedPartitioning is sensitive to the initial order, we explicitly1067// order nodes by their earliest timestamp.1068llvm::sort(Nodes, [&](auto &L, auto &R) {1069return std::make_pair(IdToFirstTimestamp[L.Id], L.Id) <1070std::make_pair(IdToFirstTimestamp[R.Id], R.Id);1071});1072}10731074#define INSTR_PROF_COMMON_API_IMPL1075#include "llvm/ProfileData/InstrProfData.inc"10761077/*!1078* ValueProfRecordClosure Interface implementation for InstrProfRecord1079* class. These C wrappers are used as adaptors so that C++ code can be1080* invoked as callbacks.1081*/1082uint32_t getNumValueKindsInstrProf(const void *Record) {1083return reinterpret_cast<const InstrProfRecord *>(Record)->getNumValueKinds();1084}10851086uint32_t getNumValueSitesInstrProf(const void *Record, uint32_t VKind) {1087return reinterpret_cast<const InstrProfRecord *>(Record)1088->getNumValueSites(VKind);1089}10901091uint32_t getNumValueDataInstrProf(const void *Record, uint32_t VKind) {1092return reinterpret_cast<const InstrProfRecord *>(Record)1093->getNumValueData(VKind);1094}10951096uint32_t getNumValueDataForSiteInstrProf(const void *R, uint32_t VK,1097uint32_t S) {1098const auto *IPR = reinterpret_cast<const InstrProfRecord *>(R);1099return IPR->getValueArrayForSite(VK, S).size();1100}11011102void getValueForSiteInstrProf(const void *R, InstrProfValueData *Dst,1103uint32_t K, uint32_t S) {1104const auto *IPR = reinterpret_cast<const InstrProfRecord *>(R);1105llvm::copy(IPR->getValueArrayForSite(K, S), Dst);1106}11071108ValueProfData *allocValueProfDataInstrProf(size_t TotalSizeInBytes) {1109ValueProfData *VD =1110(ValueProfData *)(new (::operator new(TotalSizeInBytes)) ValueProfData());1111memset(VD, 0, TotalSizeInBytes);1112return VD;1113}11141115static ValueProfRecordClosure InstrProfRecordClosure = {1116nullptr,1117getNumValueKindsInstrProf,1118getNumValueSitesInstrProf,1119getNumValueDataInstrProf,1120getNumValueDataForSiteInstrProf,1121nullptr,1122getValueForSiteInstrProf,1123allocValueProfDataInstrProf};11241125// Wrapper implementation using the closure mechanism.1126uint32_t ValueProfData::getSize(const InstrProfRecord &Record) {1127auto Closure = InstrProfRecordClosure;1128Closure.Record = &Record;1129return getValueProfDataSize(&Closure);1130}11311132// Wrapper implementation using the closure mechanism.1133std::unique_ptr<ValueProfData>1134ValueProfData::serializeFrom(const InstrProfRecord &Record) {1135InstrProfRecordClosure.Record = &Record;11361137std::unique_ptr<ValueProfData> VPD(1138serializeValueProfDataFrom(&InstrProfRecordClosure, nullptr));1139return VPD;1140}11411142void ValueProfRecord::deserializeTo(InstrProfRecord &Record,1143InstrProfSymtab *SymTab) {1144Record.reserveSites(Kind, NumValueSites);11451146InstrProfValueData *ValueData = getValueProfRecordValueData(this);1147for (uint64_t VSite = 0; VSite < NumValueSites; ++VSite) {1148uint8_t ValueDataCount = this->SiteCountArray[VSite];1149ArrayRef<InstrProfValueData> VDs(ValueData, ValueDataCount);1150Record.addValueData(Kind, VSite, VDs, SymTab);1151ValueData += ValueDataCount;1152}1153}11541155// For writing/serializing, Old is the host endianness, and New is1156// byte order intended on disk. For Reading/deserialization, Old1157// is the on-disk source endianness, and New is the host endianness.1158void ValueProfRecord::swapBytes(llvm::endianness Old, llvm::endianness New) {1159using namespace support;11601161if (Old == New)1162return;11631164if (llvm::endianness::native != Old) {1165sys::swapByteOrder<uint32_t>(NumValueSites);1166sys::swapByteOrder<uint32_t>(Kind);1167}1168uint32_t ND = getValueProfRecordNumValueData(this);1169InstrProfValueData *VD = getValueProfRecordValueData(this);11701171// No need to swap byte array: SiteCountArrray.1172for (uint32_t I = 0; I < ND; I++) {1173sys::swapByteOrder<uint64_t>(VD[I].Value);1174sys::swapByteOrder<uint64_t>(VD[I].Count);1175}1176if (llvm::endianness::native == Old) {1177sys::swapByteOrder<uint32_t>(NumValueSites);1178sys::swapByteOrder<uint32_t>(Kind);1179}1180}11811182void ValueProfData::deserializeTo(InstrProfRecord &Record,1183InstrProfSymtab *SymTab) {1184if (NumValueKinds == 0)1185return;11861187ValueProfRecord *VR = getFirstValueProfRecord(this);1188for (uint32_t K = 0; K < NumValueKinds; K++) {1189VR->deserializeTo(Record, SymTab);1190VR = getValueProfRecordNext(VR);1191}1192}11931194static std::unique_ptr<ValueProfData> allocValueProfData(uint32_t TotalSize) {1195return std::unique_ptr<ValueProfData>(new (::operator new(TotalSize))1196ValueProfData());1197}11981199Error ValueProfData::checkIntegrity() {1200if (NumValueKinds > IPVK_Last + 1)1201return make_error<InstrProfError>(1202instrprof_error::malformed, "number of value profile kinds is invalid");1203// Total size needs to be multiple of quadword size.1204if (TotalSize % sizeof(uint64_t))1205return make_error<InstrProfError>(1206instrprof_error::malformed, "total size is not multiples of quardword");12071208ValueProfRecord *VR = getFirstValueProfRecord(this);1209for (uint32_t K = 0; K < this->NumValueKinds; K++) {1210if (VR->Kind > IPVK_Last)1211return make_error<InstrProfError>(instrprof_error::malformed,1212"value kind is invalid");1213VR = getValueProfRecordNext(VR);1214if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize)1215return make_error<InstrProfError>(1216instrprof_error::malformed,1217"value profile address is greater than total size");1218}1219return Error::success();1220}12211222Expected<std::unique_ptr<ValueProfData>>1223ValueProfData::getValueProfData(const unsigned char *D,1224const unsigned char *const BufferEnd,1225llvm::endianness Endianness) {1226using namespace support;12271228if (D + sizeof(ValueProfData) > BufferEnd)1229return make_error<InstrProfError>(instrprof_error::truncated);12301231const unsigned char *Header = D;1232uint32_t TotalSize = endian::readNext<uint32_t>(Header, Endianness);12331234if (D + TotalSize > BufferEnd)1235return make_error<InstrProfError>(instrprof_error::too_large);12361237std::unique_ptr<ValueProfData> VPD = allocValueProfData(TotalSize);1238memcpy(VPD.get(), D, TotalSize);1239// Byte swap.1240VPD->swapBytesToHost(Endianness);12411242Error E = VPD->checkIntegrity();1243if (E)1244return std::move(E);12451246return std::move(VPD);1247}12481249void ValueProfData::swapBytesToHost(llvm::endianness Endianness) {1250using namespace support;12511252if (Endianness == llvm::endianness::native)1253return;12541255sys::swapByteOrder<uint32_t>(TotalSize);1256sys::swapByteOrder<uint32_t>(NumValueKinds);12571258ValueProfRecord *VR = getFirstValueProfRecord(this);1259for (uint32_t K = 0; K < NumValueKinds; K++) {1260VR->swapBytes(Endianness, llvm::endianness::native);1261VR = getValueProfRecordNext(VR);1262}1263}12641265void ValueProfData::swapBytesFromHost(llvm::endianness Endianness) {1266using namespace support;12671268if (Endianness == llvm::endianness::native)1269return;12701271ValueProfRecord *VR = getFirstValueProfRecord(this);1272for (uint32_t K = 0; K < NumValueKinds; K++) {1273ValueProfRecord *NVR = getValueProfRecordNext(VR);1274VR->swapBytes(llvm::endianness::native, Endianness);1275VR = NVR;1276}1277sys::swapByteOrder<uint32_t>(TotalSize);1278sys::swapByteOrder<uint32_t>(NumValueKinds);1279}12801281void annotateValueSite(Module &M, Instruction &Inst,1282const InstrProfRecord &InstrProfR,1283InstrProfValueKind ValueKind, uint32_t SiteIdx,1284uint32_t MaxMDCount) {1285auto VDs = InstrProfR.getValueArrayForSite(ValueKind, SiteIdx);1286if (VDs.empty())1287return;1288uint64_t Sum = 0;1289for (const InstrProfValueData &V : VDs)1290Sum = SaturatingAdd(Sum, V.Count);1291annotateValueSite(M, Inst, VDs, Sum, ValueKind, MaxMDCount);1292}12931294void annotateValueSite(Module &M, Instruction &Inst,1295ArrayRef<InstrProfValueData> VDs,1296uint64_t Sum, InstrProfValueKind ValueKind,1297uint32_t MaxMDCount) {1298if (VDs.empty())1299return;1300LLVMContext &Ctx = M.getContext();1301MDBuilder MDHelper(Ctx);1302SmallVector<Metadata *, 3> Vals;1303// Tag1304Vals.push_back(MDHelper.createString("VP"));1305// Value Kind1306Vals.push_back(MDHelper.createConstant(1307ConstantInt::get(Type::getInt32Ty(Ctx), ValueKind)));1308// Total Count1309Vals.push_back(1310MDHelper.createConstant(ConstantInt::get(Type::getInt64Ty(Ctx), Sum)));13111312// Value Profile Data1313uint32_t MDCount = MaxMDCount;1314for (const auto &VD : VDs) {1315Vals.push_back(MDHelper.createConstant(1316ConstantInt::get(Type::getInt64Ty(Ctx), VD.Value)));1317Vals.push_back(MDHelper.createConstant(1318ConstantInt::get(Type::getInt64Ty(Ctx), VD.Count)));1319if (--MDCount == 0)1320break;1321}1322Inst.setMetadata(LLVMContext::MD_prof, MDNode::get(Ctx, Vals));1323}13241325MDNode *mayHaveValueProfileOfKind(const Instruction &Inst,1326InstrProfValueKind ValueKind) {1327MDNode *MD = Inst.getMetadata(LLVMContext::MD_prof);1328if (!MD)1329return nullptr;13301331if (MD->getNumOperands() < 5)1332return nullptr;13331334MDString *Tag = cast<MDString>(MD->getOperand(0));1335if (!Tag || Tag->getString() != "VP")1336return nullptr;13371338// Now check kind:1339ConstantInt *KindInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(1));1340if (!KindInt)1341return nullptr;1342if (KindInt->getZExtValue() != ValueKind)1343return nullptr;13441345return MD;1346}13471348SmallVector<InstrProfValueData, 4>1349getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind,1350uint32_t MaxNumValueData, uint64_t &TotalC,1351bool GetNoICPValue) {1352// Four inline elements seem to work well in practice. With MaxNumValueData,1353// this array won't grow very big anyway.1354SmallVector<InstrProfValueData, 4> ValueData;1355MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind);1356if (!MD)1357return ValueData;1358const unsigned NOps = MD->getNumOperands();1359// Get total count1360ConstantInt *TotalCInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(2));1361if (!TotalCInt)1362return ValueData;1363TotalC = TotalCInt->getZExtValue();13641365ValueData.reserve((NOps - 3) / 2);1366for (unsigned I = 3; I < NOps; I += 2) {1367if (ValueData.size() >= MaxNumValueData)1368break;1369ConstantInt *Value = mdconst::dyn_extract<ConstantInt>(MD->getOperand(I));1370ConstantInt *Count =1371mdconst::dyn_extract<ConstantInt>(MD->getOperand(I + 1));1372if (!Value || !Count) {1373ValueData.clear();1374return ValueData;1375}1376uint64_t CntValue = Count->getZExtValue();1377if (!GetNoICPValue && (CntValue == NOMORE_ICP_MAGICNUM))1378continue;1379InstrProfValueData V;1380V.Value = Value->getZExtValue();1381V.Count = CntValue;1382ValueData.push_back(V);1383}1384return ValueData;1385}13861387MDNode *getPGOFuncNameMetadata(const Function &F) {1388return F.getMetadata(getPGOFuncNameMetadataName());1389}13901391static void createPGONameMetadata(GlobalObject &GO, StringRef MetadataName,1392StringRef PGOName) {1393// Only for internal linkage functions or global variables. The name is not1394// the same as PGO name for these global objects.1395if (GO.getName() == PGOName)1396return;13971398// Don't create duplicated metadata.1399if (GO.getMetadata(MetadataName))1400return;14011402LLVMContext &C = GO.getContext();1403MDNode *N = MDNode::get(C, MDString::get(C, PGOName));1404GO.setMetadata(MetadataName, N);1405}14061407void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName) {1408return createPGONameMetadata(F, getPGOFuncNameMetadataName(), PGOFuncName);1409}14101411void createPGONameMetadata(GlobalObject &GO, StringRef PGOName) {1412return createPGONameMetadata(GO, getPGONameMetadataName(), PGOName);1413}14141415bool needsComdatForCounter(const GlobalObject &GO, const Module &M) {1416if (GO.hasComdat())1417return true;14181419if (!Triple(M.getTargetTriple()).supportsCOMDAT())1420return false;14211422// See createPGOFuncNameVar for more details. To avoid link errors, profile1423// counters for function with available_externally linkage needs to be changed1424// to linkonce linkage. On ELF based systems, this leads to weak symbols to be1425// created. Without using comdat, duplicate entries won't be removed by the1426// linker leading to increased data segement size and raw profile size. Even1427// worse, since the referenced counter from profile per-function data object1428// will be resolved to the common strong definition, the profile counts for1429// available_externally functions will end up being duplicated in raw profile1430// data. This can result in distorted profile as the counts of those dups1431// will be accumulated by the profile merger.1432GlobalValue::LinkageTypes Linkage = GO.getLinkage();1433if (Linkage != GlobalValue::ExternalWeakLinkage &&1434Linkage != GlobalValue::AvailableExternallyLinkage)1435return false;14361437return true;1438}14391440// Check if INSTR_PROF_RAW_VERSION_VAR is defined.1441bool isIRPGOFlagSet(const Module *M) {1442const GlobalVariable *IRInstrVar =1443M->getNamedGlobal(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR));1444if (!IRInstrVar || IRInstrVar->hasLocalLinkage())1445return false;14461447// For CSPGO+LTO, this variable might be marked as non-prevailing and we only1448// have the decl.1449if (IRInstrVar->isDeclaration())1450return true;14511452// Check if the flag is set.1453if (!IRInstrVar->hasInitializer())1454return false;14551456auto *InitVal = dyn_cast_or_null<ConstantInt>(IRInstrVar->getInitializer());1457if (!InitVal)1458return false;1459return (InitVal->getZExtValue() & VARIANT_MASK_IR_PROF) != 0;1460}14611462// Check if we can safely rename this Comdat function.1463bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken) {1464if (F.getName().empty())1465return false;1466if (!needsComdatForCounter(F, *(F.getParent())))1467return false;1468// Unsafe to rename the address-taken function (which can be used in1469// function comparison).1470if (CheckAddressTaken && F.hasAddressTaken())1471return false;1472// Only safe to do if this function may be discarded if it is not used1473// in the compilation unit.1474if (!GlobalValue::isDiscardableIfUnused(F.getLinkage()))1475return false;14761477// For AvailableExternallyLinkage functions.1478if (!F.hasComdat()) {1479assert(F.getLinkage() == GlobalValue::AvailableExternallyLinkage);1480return true;1481}1482return true;1483}14841485// Create the variable for the profile file name.1486void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput) {1487if (InstrProfileOutput.empty())1488return;1489Constant *ProfileNameConst =1490ConstantDataArray::getString(M.getContext(), InstrProfileOutput, true);1491GlobalVariable *ProfileNameVar = new GlobalVariable(1492M, ProfileNameConst->getType(), true, GlobalValue::WeakAnyLinkage,1493ProfileNameConst, INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR));1494ProfileNameVar->setVisibility(GlobalValue::HiddenVisibility);1495Triple TT(M.getTargetTriple());1496if (TT.supportsCOMDAT()) {1497ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);1498ProfileNameVar->setComdat(M.getOrInsertComdat(1499StringRef(INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_NAME_VAR))));1500}1501}15021503Error OverlapStats::accumulateCounts(const std::string &BaseFilename,1504const std::string &TestFilename,1505bool IsCS) {1506auto GetProfileSum = [IsCS](const std::string &Filename,1507CountSumOrPercent &Sum) -> Error {1508// This function is only used from llvm-profdata that doesn't use any kind1509// of VFS. Just create a default RealFileSystem to read profiles.1510auto FS = vfs::getRealFileSystem();1511auto ReaderOrErr = InstrProfReader::create(Filename, *FS);1512if (Error E = ReaderOrErr.takeError()) {1513return E;1514}1515auto Reader = std::move(ReaderOrErr.get());1516Reader->accumulateCounts(Sum, IsCS);1517return Error::success();1518};1519auto Ret = GetProfileSum(BaseFilename, Base);1520if (Ret)1521return Ret;1522Ret = GetProfileSum(TestFilename, Test);1523if (Ret)1524return Ret;1525this->BaseFilename = &BaseFilename;1526this->TestFilename = &TestFilename;1527Valid = true;1528return Error::success();1529}15301531void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) {1532Mismatch.NumEntries += 1;1533Mismatch.CountSum += MismatchFunc.CountSum / Test.CountSum;1534for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {1535if (Test.ValueCounts[I] >= 1.0f)1536Mismatch.ValueCounts[I] +=1537MismatchFunc.ValueCounts[I] / Test.ValueCounts[I];1538}1539}15401541void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) {1542Unique.NumEntries += 1;1543Unique.CountSum += UniqueFunc.CountSum / Test.CountSum;1544for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {1545if (Test.ValueCounts[I] >= 1.0f)1546Unique.ValueCounts[I] += UniqueFunc.ValueCounts[I] / Test.ValueCounts[I];1547}1548}15491550void OverlapStats::dump(raw_fd_ostream &OS) const {1551if (!Valid)1552return;15531554const char *EntryName =1555(Level == ProgramLevel ? "functions" : "edge counters");1556if (Level == ProgramLevel) {1557OS << "Profile overlap infomation for base_profile: " << *BaseFilename1558<< " and test_profile: " << *TestFilename << "\nProgram level:\n";1559} else {1560OS << "Function level:\n"1561<< " Function: " << FuncName << " (Hash=" << FuncHash << ")\n";1562}15631564OS << " # of " << EntryName << " overlap: " << Overlap.NumEntries << "\n";1565if (Mismatch.NumEntries)1566OS << " # of " << EntryName << " mismatch: " << Mismatch.NumEntries1567<< "\n";1568if (Unique.NumEntries)1569OS << " # of " << EntryName1570<< " only in test_profile: " << Unique.NumEntries << "\n";15711572OS << " Edge profile overlap: " << format("%.3f%%", Overlap.CountSum * 100)1573<< "\n";1574if (Mismatch.NumEntries)1575OS << " Mismatched count percentage (Edge): "1576<< format("%.3f%%", Mismatch.CountSum * 100) << "\n";1577if (Unique.NumEntries)1578OS << " Percentage of Edge profile only in test_profile: "1579<< format("%.3f%%", Unique.CountSum * 100) << "\n";1580OS << " Edge profile base count sum: " << format("%.0f", Base.CountSum)1581<< "\n"1582<< " Edge profile test count sum: " << format("%.0f", Test.CountSum)1583<< "\n";15841585for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {1586if (Base.ValueCounts[I] < 1.0f && Test.ValueCounts[I] < 1.0f)1587continue;1588char ProfileKindName[20] = {0};1589switch (I) {1590case IPVK_IndirectCallTarget:1591strncpy(ProfileKindName, "IndirectCall", 19);1592break;1593case IPVK_MemOPSize:1594strncpy(ProfileKindName, "MemOP", 19);1595break;1596case IPVK_VTableTarget:1597strncpy(ProfileKindName, "VTable", 19);1598break;1599default:1600snprintf(ProfileKindName, 19, "VP[%d]", I);1601break;1602}1603OS << " " << ProfileKindName1604<< " profile overlap: " << format("%.3f%%", Overlap.ValueCounts[I] * 100)1605<< "\n";1606if (Mismatch.NumEntries)1607OS << " Mismatched count percentage (" << ProfileKindName1608<< "): " << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n";1609if (Unique.NumEntries)1610OS << " Percentage of " << ProfileKindName1611<< " profile only in test_profile: "1612<< format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n";1613OS << " " << ProfileKindName1614<< " profile base count sum: " << format("%.0f", Base.ValueCounts[I])1615<< "\n"1616<< " " << ProfileKindName1617<< " profile test count sum: " << format("%.0f", Test.ValueCounts[I])1618<< "\n";1619}1620}16211622namespace IndexedInstrProf {1623Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {1624using namespace support;1625static_assert(std::is_standard_layout_v<Header>,1626"Use standard layout for Header for simplicity");1627Header H;16281629H.Magic = endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1630// Check the magic number.1631if (H.Magic != IndexedInstrProf::Magic)1632return make_error<InstrProfError>(instrprof_error::bad_magic);16331634// Read the version.1635H.Version = endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1636if (H.getIndexedProfileVersion() >1637IndexedInstrProf::ProfVersion::CurrentVersion)1638return make_error<InstrProfError>(instrprof_error::unsupported_version);16391640static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version12,1641"Please update the reader as needed when a new field is added "1642"or when indexed profile version gets bumped.");16431644Buffer += sizeof(uint64_t); // Skip Header.Unused field.1645H.HashType = endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1646H.HashOffset = endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1647if (H.getIndexedProfileVersion() >= 8)1648H.MemProfOffset =1649endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1650if (H.getIndexedProfileVersion() >= 9)1651H.BinaryIdOffset =1652endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1653// Version 11 is handled by this condition.1654if (H.getIndexedProfileVersion() >= 10)1655H.TemporalProfTracesOffset =1656endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1657if (H.getIndexedProfileVersion() >= 12)1658H.VTableNamesOffset =1659endian::readNext<uint64_t, llvm::endianness::little>(Buffer);1660return H;1661}16621663uint64_t Header::getIndexedProfileVersion() const {1664return GET_VERSION(Version);1665}16661667size_t Header::size() const {1668switch (getIndexedProfileVersion()) {1669// To retain backward compatibility, new fields must be appended to the end1670// of the header, and byte offset of existing fields shouldn't change when1671// indexed profile version gets incremented.1672static_assert(1673IndexedInstrProf::ProfVersion::CurrentVersion == Version12,1674"Please update the size computation below if a new field has "1675"been added to the header; for a version bump without new "1676"fields, add a case statement to fall through to the latest version.");1677case 12ull:1678return 72;1679case 11ull:1680[[fallthrough]];1681case 10ull:1682return 64;1683case 9ull:1684return 56;1685case 8ull:1686return 48;1687default: // Version7 (when the backwards compatible header was introduced).1688return 40;1689}1690}16911692} // namespace IndexedInstrProf16931694} // end namespace llvm169516961697