diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -619,9 +619,14 @@ /// Read a single record. Error readNextRecord(NamedInstrProfRecord &Record) override; - /// Return the NamedInstrProfRecord associated with FuncName and FuncHash - Expected getInstrProfRecord(StringRef FuncName, - uint64_t FuncHash); + /// Return the NamedInstrProfRecord associated with FuncName and FuncHash. + /// When return a hash_mismatch error and MismatchedFuncSum is not nullptr, + /// the sum of all counters in the mismatched function will be set to + /// MismatchedFuncSum. If there are multiple instances of mismatched + /// functions, MismatchedFuncSum returns the maximum. + Expected + getInstrProfRecord(StringRef FuncName, uint64_t FuncHash, + uint64_t *MismatchedFuncSum = nullptr); /// Return the memprof record for the function identified by /// llvm::md5(Name). diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -1026,10 +1026,10 @@ return *Symtab; } -Expected -IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, - uint64_t FuncHash) { +Expected IndexedInstrProfReader::getInstrProfRecord( + StringRef FuncName, uint64_t FuncHash, uint64_t *MismatchedFuncSum) { ArrayRef Data; + uint64_t FuncSum = 0; Error Err = Remapper->getRecords(FuncName, Data); if (Err) return std::move(Err); @@ -1038,6 +1038,19 @@ // A flag to indicate if the records are from the same type // of profile (i.e cs vs nocs). bool CSBitMatch = false; + auto getFuncSum = [](const std::vector &Counts) { + uint64_t ValueSum = 0; + for (unsigned I = 0, S = Counts.size(); I < S; I++) { + uint64_t CountValue = Counts[I]; + if (CountValue == (uint64_t)-1) + continue; + // Handle overflow -- if that happens, return max. + if (std::numeric_limits::max() - CountValue <= ValueSum) + return std::numeric_limits::max(); + ValueSum += CountValue; + } + return ValueSum; + }; for (const NamedInstrProfRecord &I : Data) { // Check for a match and fill the vector if there is one. @@ -1046,9 +1059,14 @@ if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) == NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) { CSBitMatch = true; + if (MismatchedFuncSum == nullptr) + continue; + FuncSum = std::max(FuncSum, getFuncSum(I.Counts)); } } if (CSBitMatch) { + if (MismatchedFuncSum != nullptr) + *MismatchedFuncSum = FuncSum; return error(instrprof_error::hash_mismatch); } return error(instrprof_error::unknown_function); diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -1224,8 +1224,9 @@ bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, bool &AllMinusOnes) { auto &Ctx = M->getContext(); - Expected Result = - PGOReader->getInstrProfRecord(FuncInfo.FuncName, FuncInfo.FunctionHash); + uint64_t MismatchedFuncSum = 0; + Expected Result = PGOReader->getInstrProfRecord( + FuncInfo.FuncName, FuncInfo.FunctionHash, &MismatchedFuncSum); if (Error E = Result.takeError()) { handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { auto Err = IPE.get(); @@ -1254,9 +1255,11 @@ if (SkipWarning) return; - std::string Msg = IPE.message() + std::string(" ") + F.getName().str() + - std::string(" Hash = ") + - std::to_string(FuncInfo.FunctionHash); + std::string Msg = + IPE.message() + std::string(" ") + F.getName().str() + + std::string(" Hash = ") + std::to_string(FuncInfo.FunctionHash) + + std::string(" up to ") + std::to_string(MismatchedFuncSum) + + std::string(" count discarded"); Ctx.diagnose( DiagnosticInfoPGOProfile(M->getName().data(), Msg, DS_Warning)); diff --git a/llvm/test/Transforms/PGOProfile/Inputs/diag.proftext b/llvm/test/Transforms/PGOProfile/Inputs/diag.proftext --- a/llvm/test/Transforms/PGOProfile/Inputs/diag.proftext +++ b/llvm/test/Transforms/PGOProfile/Inputs/diag.proftext @@ -5,3 +5,9 @@ 1 1 +foo +12885999999 +2 +6000 +4000 + diff --git a/llvm/test/Transforms/PGOProfile/diag_mismatch.ll b/llvm/test/Transforms/PGOProfile/diag_mismatch.ll --- a/llvm/test/Transforms/PGOProfile/diag_mismatch.ll +++ b/llvm/test/Transforms/PGOProfile/diag_mismatch.ll @@ -1,7 +1,7 @@ ; RUN: llvm-profdata merge %S/Inputs/diag.proftext -o %t.profdata ; RUN: opt < %s -passes=pgo-instr-use -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s -; CHECK: warning: {{.+}}: function control flow change detected (hash mismatch) foo +; CHECK: warning: {{.+}}: function control flow change detected (hash mismatch) foo Hash = 742261418966908927 up to 10000 count discarded target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu"