Index: include/llvm/ProfileData/InstrProf.h =================================================================== --- include/llvm/ProfileData/InstrProf.h +++ include/llvm/ProfileData/InstrProf.h @@ -17,6 +17,10 @@ #define LLVM_PROFILEDATA_INSTRPROF_H_ #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" #include #include #include @@ -44,6 +48,41 @@ return std::error_code(static_cast(E), instrprof_category()); } +const uint64_t InstrProfFeature_Mask = 0xffffffffull << 32; + +enum class instrprof_feature { + // Use function name's md5 hash as index profile's key + md5hash_key = 32, + last = 63 +}; + +/// A helper function to extract the fromat version value from the version +/// field. The feature bits are filtered out. +inline uint64_t getFormatVersion(uint64_t version) { + return (version & ~InstrProfFeature_Mask); +} + +/// A helper function to test feature bit of the feature set +inline bool hasFeature(instrprof_feature feature, uint64_t feature_set) { + return (feature_set & (1ull << (int)feature)) != 0; +} + +inline uint64_t MD5Hash(StringRef Str) { + MD5 Hash; + Hash.update(Str); + llvm::MD5::MD5Result Result; + Hash.final(Result); + // Return the least significant 8 bytes. Our MD5 implementation returns the + // result in little endian, so we may need to swap bytes. + using namespace llvm::support; + return endian::read(Result); +} + +/// Returns MD5 hash in hex string. +inline StringRef MD5HashStr(StringRef Str) { + return utohexstr(MD5Hash(Str), true); +} + /// Profiling information for a single function. struct InstrProfRecord { InstrProfRecord() {} @@ -54,6 +93,67 @@ std::vector Counts; }; +namespace RawInstrProf { + +const uint64_t Version = 1; + + +// Magic number to detect file format and endianness. +// Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, +// so that utilities, like strings, don't grab it as a string. 129 is also +// invalid UTF-8, and high enough to be interesting. +// Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" +// for 32-bit platforms. + +template +static uint64_t getMagic(); +template <> +uint64_t getMagic() { + return + uint64_t(255) << 56 | + uint64_t('l') << 48 | + uint64_t('p') << 40 | + uint64_t('r') << 32 | + uint64_t('o') << 24 | + uint64_t('f') << 16 | + uint64_t('r') << 8 | + uint64_t(129); +} + +template <> +uint64_t getMagic() { + return + uint64_t(255) << 56 | + uint64_t('l') << 48 | + uint64_t('p') << 40 | + uint64_t('r') << 32 | + uint64_t('o') << 24 | + uint64_t('f') << 16 | + uint64_t('R') << 8 | + uint64_t(129); + +} +} + +namespace IndexedInstrProf { +enum class HashT : uint32_t { + MD5, + Last = MD5 +}; + +static inline uint64_t ComputeHash(HashT Type, StringRef K) { + switch (Type) { + case HashT::MD5: + return MD5Hash(K); + } + llvm_unreachable("Unhandled hash type"); +} + +const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" +const uint64_t Version = 2; +const HashT HashType = HashT::MD5; +} + } // end namespace llvm namespace std { Index: include/llvm/ProfileData/InstrProfReader.h =================================================================== --- include/llvm/ProfileData/InstrProfReader.h +++ include/llvm/ProfileData/InstrProfReader.h @@ -53,7 +53,7 @@ std::error_code LastError; public: - InstrProfReader() : LastError(instrprof_error::success) {} + InstrProfReader() : LastError(instrprof_error::success), Version(0) {} virtual ~InstrProfReader() {} /// Read the header. Required before reading first record. @@ -74,7 +74,13 @@ /// Clear the current error code and return a successful one. std::error_code success() { return error(instrprof_error::success); } + /// Raw or Indexed Profile Version value. + /// The version field contains two parts: Format version at lower 32 bit, + /// and feature set at upper 32bit. + uint64_t Version; + public: + uint64_t getVersion() { return Version; } /// Return true if the reader has finished reading the profile data. bool isEOF() { return LastError == instrprof_error::eof; } /// Return true if the reader encountered an error reading profiling data. @@ -239,8 +245,6 @@ std::unique_ptr Index; /// Iterator over the profile data. InstrProfReaderIndex::data_iterator RecordIterator; - /// The file format version of the profile data. - uint64_t FormatVersion; /// The maximal execution count among all functions. uint64_t MaxFunctionCount; Index: include/llvm/ProfileData/InstrProfWriter.h =================================================================== --- include/llvm/ProfileData/InstrProfWriter.h +++ include/llvm/ProfileData/InstrProfWriter.h @@ -34,7 +34,7 @@ StringMap FunctionData; uint64_t MaxFunctionCount; public: - InstrProfWriter() : MaxFunctionCount(0) {} + InstrProfWriter() : MaxFunctionCount(0), MD5HashKey(false) {} /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is @@ -42,6 +42,7 @@ std::error_code addFunctionCounts(StringRef FunctionName, uint64_t FunctionHash, ArrayRef Counters); + void setUseMD5HashKey() { MD5HashKey = true; } /// Write the profile to \c OS void write(raw_fd_ostream &OS); /// Write the profile, returning the raw data. For testing. @@ -49,6 +50,7 @@ private: std::pair writeImpl(raw_ostream &OS); + bool MD5HashKey; }; } // end namespace llvm Index: include/llvm/Transforms/Instrumentation.h =================================================================== --- include/llvm/Transforms/Instrumentation.h +++ include/llvm/Transforms/Instrumentation.h @@ -79,11 +79,14 @@ /// Options for the frontend instrumentation based profiling pass. struct InstrProfOptions { - InstrProfOptions() : NoRedZone(false) {} + InstrProfOptions() : NoRedZone(false), IncludeNamesInProfile(false) {} // Add the 'noredzone' attribute to added runtime library calls. bool NoRedZone; + // Include full funciton names in profile. + bool IncludeNamesInProfile; + // Name of the profile file to use as output std::string InstrProfileOutput; }; Index: lib/ProfileData/InstrProfIndexed.h =================================================================== --- lib/ProfileData/InstrProfIndexed.h +++ lib/ProfileData/InstrProfIndexed.h @@ -17,40 +17,6 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" - -namespace llvm { - -namespace IndexedInstrProf { -enum class HashT : uint32_t { - MD5, - - Last = MD5 -}; - -static inline uint64_t MD5Hash(StringRef Str) { - MD5 Hash; - Hash.update(Str); - llvm::MD5::MD5Result Result; - Hash.final(Result); - // Return the least significant 8 bytes. Our MD5 implementation returns the - // result in little endian, so we may need to swap bytes. - using namespace llvm::support; - return endian::read(Result); -} - -static inline uint64_t ComputeHash(HashT Type, StringRef K) { - switch (Type) { - case HashT::MD5: - return IndexedInstrProf::MD5Hash(K); - } - llvm_unreachable("Unhandled hash type"); -} - -const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" -const uint64_t Version = 2; -const HashT HashType = HashT::MD5; -} - -} // end namespace llvm +#include "llvm/ProfileData/InstrProf.h" #endif Index: lib/ProfileData/InstrProfReader.cpp =================================================================== --- lib/ProfileData/InstrProfReader.cpp +++ lib/ProfileData/InstrProfReader.cpp @@ -140,42 +140,13 @@ } template -static uint64_t getRawMagic(); - -template <> -uint64_t getRawMagic() { - return - uint64_t(255) << 56 | - uint64_t('l') << 48 | - uint64_t('p') << 40 | - uint64_t('r') << 32 | - uint64_t('o') << 24 | - uint64_t('f') << 16 | - uint64_t('r') << 8 | - uint64_t(129); -} - -template <> -uint64_t getRawMagic() { - return - uint64_t(255) << 56 | - uint64_t('l') << 48 | - uint64_t('p') << 40 | - uint64_t('r') << 32 | - uint64_t('o') << 24 | - uint64_t('f') << 16 | - uint64_t('R') << 8 | - uint64_t(129); -} - -template bool RawInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { if (DataBuffer.getBufferSize() < sizeof(uint64_t)) return false; uint64_t Magic = - *reinterpret_cast(DataBuffer.getBufferStart()); - return getRawMagic() == Magic || - sys::getSwappedBytes(getRawMagic()) == Magic; + *reinterpret_cast(DataBuffer.getBufferStart()); + return RawInstrProf::getMagic() == Magic || + sys::getSwappedBytes(RawInstrProf::getMagic()) == Magic; } template @@ -185,8 +156,8 @@ if (DataBuffer->getBufferSize() < sizeof(RawHeader)) return error(instrprof_error::bad_header); auto *Header = - reinterpret_cast(DataBuffer->getBufferStart()); - ShouldSwapBytes = Header->Magic != getRawMagic(); + reinterpret_cast(DataBuffer->getBufferStart()); + ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic(); return readHeader(*Header); } @@ -209,7 +180,7 @@ return instrprof_error::malformed; // The magic should have the same byte order as in the previous header. uint64_t Magic = *reinterpret_cast(CurrentPos); - if (Magic != swap(getRawMagic())) + if (Magic != swap(RawInstrProf::getMagic())) return instrprof_error::bad_magic; // There's another profile to read, so we need to process the header. @@ -217,14 +188,11 @@ return readHeader(*Header); } -static uint64_t getRawVersion() { - return 1; -} - template std::error_code RawInstrProfReader::readHeader(const RawHeader &Header) { - if (swap(Header.Version) != getRawVersion()) + Version = swap(Header.Version); + if (getFormatVersion(Version) != RawInstrProf::Version) return error(instrprof_error::unsupported_version); CountersDelta = swap(Header.CountersDelta); @@ -366,8 +334,8 @@ return error(instrprof_error::bad_magic); // Read the version. - FormatVersion = endian::readNext(Cur); - if (FormatVersion > IndexedInstrProf::Version) + Version = endian::readNext(Cur); + if (getFormatVersion(Version) > IndexedInstrProf::Version) return error(instrprof_error::unsupported_version); // Read the maximal function count. @@ -383,7 +351,7 @@ // The rest of the file is an on disk hash table. Index.reset(InstrProfReaderIndex::Create( Start + HashOffset, Cur, Start, - InstrProfLookupTrait(HashType, FormatVersion))); + InstrProfLookupTrait(HashType, getFormatVersion(Version)))); // Set up our iterator for readNextRecord. RecordIterator = Index->data_begin(); @@ -392,7 +360,12 @@ std::error_code IndexedInstrProfReader::getFunctionCounts( StringRef FuncName, uint64_t FuncHash, std::vector &Counts) { - auto Iter = Index->find(FuncName); + + StringRef FuncNameOrHash = FuncName; + if (hasFeature(instrprof_feature::md5hash_key, Version)) + FuncNameOrHash = MD5HashStr(FuncName); + + auto Iter = Index->find(FuncNameOrHash); if (Iter == Index->end()) return error(instrprof_error::unknown_function); Index: lib/ProfileData/InstrProfWriter.cpp =================================================================== --- lib/ProfileData/InstrProfWriter.cpp +++ lib/ProfileData/InstrProfWriter.cpp @@ -116,9 +116,12 @@ using namespace llvm::support; endian::Writer LE(OS); + uint64_t Version = IndexedInstrProf::Version; + if (MD5HashKey) + Version |= (1ull << (int)instrprof_feature::md5hash_key); // Write the header. LE.write(IndexedInstrProf::Magic); - LE.write(IndexedInstrProf::Version); + LE.write(Version); LE.write(MaxFunctionCount); LE.write(static_cast(IndexedInstrProf::HashType)); Index: lib/Transforms/Instrumentation/InstrProfiling.cpp =================================================================== --- lib/Transforms/Instrumentation/InstrProfiling.cpp +++ lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -20,11 +20,16 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/ProfileData/InstrProf.h" using namespace llvm; #define DEBUG_TYPE "instrprof" +static cl::opt +InstrProfileWithNameHash("instr-prof-with-namehash", + cl::desc("FE uses MD5 hash string in place of function names.")); + namespace { class InstrProfiling : public ModulePass { @@ -34,7 +39,10 @@ InstrProfiling() : ModulePass(ID) {} InstrProfiling(const InstrProfOptions &Options) - : ModulePass(ID), Options(Options) {} + : ModulePass(ID), Options(Options) { + if (InstrProfileWithNameHash) + this->Options.IncludeNamesInProfile = false; + } const char *getPassName() const override { return "Frontend instrumentation-based coverage lowering"; @@ -94,6 +102,9 @@ /// Emit the necessary plumbing to pull in the runtime initialization. void emitRuntimeHook(); + /// Emit version and magic global variables + void emitHeaderGlobals(); + /// Add uses of our data variables and runtime hook. void emitUses(); @@ -136,6 +147,7 @@ emitRegistration(); emitRuntimeHook(); + emitHeaderGlobals(); emitUses(); emitInitialization(); return true; @@ -184,8 +196,8 @@ /// Get the name of a profiling variable for a particular function. static std::string getVarName(InstrProfIncrementInst *Inc, StringRef VarName) { - auto *Arr = cast(Inc->getName()->getInitializer()); - StringRef Name = Arr->isCString() ? Arr->getAsCString() : Arr->getAsString(); + StringRef Name = Inc->getName()->getName(); + Name = Name.drop_front(strlen("__llvm_profile_name_")); return ("__llvm_profile_" + VarName + "_" + Name).str(); } @@ -305,6 +317,30 @@ UsedVars.push_back(User); } +void InstrProfiling::emitHeaderGlobals() { + const char *const VersionVarName = "__llvm_profile_version"; + const char *const MagicVarName = "__llvm_profile_magic"; + + auto *Int64Ty = Type::getInt64Ty(M->getContext()); + bool Is64bit = (M->getDataLayout().getPointerSizeInBits() == + Int64Ty->getPrimitiveSizeInBits()); + uint64_t Magic = Is64bit ? RawInstrProf::getMagic() + : RawInstrProf::getMagic(); + auto *MagicVar = + new GlobalVariable(*M, Int64Ty, false, GlobalValue::LinkOnceODRLinkage, + ConstantInt::get(Int64Ty, Magic), MagicVarName); + MagicVar->setVisibility(GlobalValue::HiddenVisibility); + UsedVars.push_back(MagicVar); + + uint64_t Version = RawInstrProf::Version; + if (!Options.IncludeNamesInProfile) + Version |= (1ull << (int)instrprof_feature::md5hash_key); + auto *VersionVar = + new GlobalVariable(*M, Int64Ty, false, GlobalValue::LinkOnceODRLinkage, + ConstantInt::get(Int64Ty, Version), VersionVarName); + UsedVars.push_back(VersionVar); +} + void InstrProfiling::emitUses() { if (UsedVars.empty()) return; Index: test/Instrumentation/InstrProfiling/profiling.ll =================================================================== --- test/Instrumentation/InstrProfiling/profiling.ll +++ test/Instrumentation/InstrProfiling/profiling.ll @@ -6,8 +6,8 @@ ; CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 @__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00" ; CHECK: @__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00", section "__DATA,__llvm_prf_names", align 1 -@baz_prof_name = hidden constant [3 x i8] c"baz" -; CHECK: @baz_prof_name = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1 +@__llvm_profile_name_baz = hidden constant [3 x i8] c"baz" +; CHECK: @__llvm_profile_name_baz = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1 ; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 @@ -26,9 +26,9 @@ ; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 define void @baz() { - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 0) - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 1) - call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 2) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 1) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 2) ret void } Index: test/Instrumentation/InstrProfiling/profiling_md5hash_key.ll =================================================================== --- /dev/null +++ test/Instrumentation/InstrProfiling/profiling_md5hash_key.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -instrprof -instr-prof-with-namehash -S | FileCheck %s + +target triple = "x86_64-apple-macosx10.10.0" + +@__llvm_profile_name_foo = hidden constant [16 x i8] c"5cf8c24cdb18bdac" +; CHECK: @__llvm_profile_name_foo = hidden constant [16 x i8] c"5cf8c24cdb18bdac", section "__DATA,__llvm_prf_names", align 1 +@__llvm_profile_name_bar = hidden constant [17 x i8] c"e413754a191db537\00" +; CHECK: @__llvm_profile_name_bar = hidden constant [17 x i8] c"e413754a191db537\00", section "__DATA,__llvm_prf_names", align 1 +@__llvm_profile_name_baz = hidden constant [16 x i8] c"68bbf6b7a4fffe73" +; CHECK: @__llvm_profile_name_baz = hidden constant [16 x i8] c"68bbf6b7a4fffe73", section "__DATA,__llvm_prf_names", align 1 + +; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +define void @foo() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +; CHECK: @__llvm_profile_counters_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +define void @bar() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__llvm_profile_name_bar, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 + +define void @baz() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 1) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @__llvm_profile_name_baz, i32 0, i32 0), i64 0, i32 3, i32 2) + ret void +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +; CHECK: @__llvm_profile_runtime = external global i32 +; CHECK: @__llvm_profile_version = linkonce_odr global i64 4294967297 +; CHECK: @llvm.used = appending global [6 x i8*] [i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_bar to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_baz to i8*), i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast (i64* @__llvm_profile_magic to i8*), i8* bitcast (i64* @__llvm_profile_version to i8*)], section "llvm.metadata" Index: test/tools/llvm-profdata/raw-64-bits-le-md5.test =================================================================== --- /dev/null +++ test/tools/llvm-profdata/raw-64-bits-le-md5.test @@ -0,0 +1,37 @@ +RUN: printf '\201rforpl\377' > %t +RUN: printf '\1\0\0\0\1\0\0\0' >> %t +RUN: printf '\2\0\0\0\0\0\0\0' >> %t +RUN: printf '\3\0\0\0\0\0\0\0' >> %t +RUN: printf '\40\0\0\0\0\0\0\0' >> %t +RUN: printf '\0\0\4\0\1\0\0\0' >> %t +RUN: printf '\0\0\4\0\2\0\0\0' >> %t + +RUN: printf '\20\0\0\0' >> %t +RUN: printf '\1\0\0\0' >> %t +RUN: printf '\1\0\0\0\0\0\0\0' >> %t +RUN: printf '\0\0\4\0\2\0\0\0' >> %t +RUN: printf '\0\0\4\0\1\0\0\0' >> %t + +RUN: printf '\20\0\0\0' >> %t +RUN: printf '\02\0\0\0' >> %t +RUN: printf '\02\0\0\0\0\0\0\0' >> %t +RUN: printf '\03\0\4\0\2\0\0\0' >> %t +RUN: printf '\10\0\4\0\1\0\0\0' >> %t + +RUN: printf '\023\0\0\0\0\0\0\0' >> %t +RUN: printf '\067\0\0\0\0\0\0\0' >> %t +RUN: printf '\101\0\0\0\0\0\0\0' >> %t +RUN: printf '5cf8c24cdb18bdace413754a191db537' >> %t + +RUN: llvm-profdata show %t -function=foo -counts | FileCheck %s + +CHECK: Counters: +CHECK: 5cf8c24cdb18bdac: +CHECK: Hash: 0x0000000000000001 +CHECK: Counters: 1 +CHECK: Function count: 19 +CHECK: Block counts: [] +CHECK: Functions shown: 1 +CHECK: Total functions: 2 +CHECK: Maximum function count: 55 +CHECK: Maximum internal block count: 65 Index: tools/llvm-profdata/llvm-profdata.cpp =================================================================== --- tools/llvm-profdata/llvm-profdata.cpp +++ tools/llvm-profdata/llvm-profdata.cpp @@ -58,6 +58,8 @@ exitWithError(ec.message(), Filename); auto Reader = std::move(ReaderOrErr.get()); + if (hasFeature(instrprof_feature::md5hash_key, Reader->getVersion())) + Writer.setUseMD5HashKey(); for (const auto &I : *Reader) if (std::error_code EC = Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) @@ -143,10 +145,20 @@ auto Reader = std::move(ReaderOrErr.get()); uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; size_t ShownFunctions = 0, TotalFunctions = 0; + std::string FuncNameOrHashStr; + if (!ShowFunction.empty()) { + bool IsNameMD5HashString = hasFeature(instrprof_feature::md5hash_key, + Reader->getVersion()); + if (IsNameMD5HashString) + FuncNameOrHashStr = MD5HashStr(ShowFunction); + else + FuncNameOrHashStr = ShowFunction; + } + for (const auto &Func : *Reader) { bool Show = ShowAllFunctions || (!ShowFunction.empty() && - Func.Name.find(ShowFunction) != Func.Name.npos); + Func.Name.find(FuncNameOrHashStr) != Func.Name.npos); ++TotalFunctions; assert(Func.Counts.size() > 0 && "function missing entry counter"); Index: unittests/ProfileData/InstrProfTest.cpp =================================================================== --- unittests/ProfileData/InstrProfTest.cpp +++ unittests/ProfileData/InstrProfTest.cpp @@ -66,6 +66,34 @@ ASSERT_TRUE(++I == E); } +TEST_F(InstrProfTest, write_and_read_one_function_md5hash) { + Writer.setUseMD5HashKey(); + Writer.addFunctionCounts("5cf8c24cdb18bdac", 0x1234, {1, 2, 3, 4}); + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + + auto I = Reader->begin(), E = Reader->end(); + ASSERT_TRUE(I != E); + ASSERT_EQ(StringRef("5cf8c24cdb18bdac"), I->Name); + ASSERT_EQ(0x1234U, I->Hash); + ASSERT_EQ(4U, I->Counts.size()); + ASSERT_EQ(1U, I->Counts[0]); + ASSERT_EQ(2U, I->Counts[1]); + ASSERT_EQ(3U, I->Counts[2]); + ASSERT_EQ(4U, I->Counts[3]); + ASSERT_TRUE(++I == E); + + StringRef NameKey("foo"); + std::vector Counts; + ASSERT_TRUE(NoError(Reader->getFunctionCounts(NameKey, 0x1234, Counts))); + ASSERT_EQ(4U, Counts.size()); + ASSERT_EQ(1U, Counts[0]); + ASSERT_EQ(2U, Counts[1]); + ASSERT_EQ(3U, Counts[2]); + ASSERT_EQ(4U, Counts[3]); + +} + TEST_F(InstrProfTest, get_function_counts) { Writer.addFunctionCounts("foo", 0x1234, {1, 2}); Writer.addFunctionCounts("foo", 0x1235, {3, 4});