From 0833ccb526c74402438bfc5f5a79606de9991156 Mon Sep 17 00:00:00 2001 From: Nathan Slingerland Date: Tue, 17 Nov 2015 22:08:53 +0000 Subject: [PATCH] [llvm-profdata] Improve error messaging when merging mismatched profile data Summary: This change tries to make the root cause of instrumented profile data merge failures clearer. Previous: $ llvm-profdata merge test_0.profraw test_1.profraw -o test_merged.profdata test_1.profraw: foo: Function count mismatch test_1.profraw: bar: Function count mismatch test_1.profraw: baz: Function count mismatch ... Changed: $ llvm-profdata merge test_0.profraw test_1.profraw -o test_merged.profdata test_1.profraw: foo: Function basic block count change detected (counter mismatch) Make sure that all profile data to be merged is generated from the same binary. test_1.profraw: bar: Function basic block count change detected (counter mismatch) test_1.profraw: baz: Function basic block count change detected (counter mismatch) ... Reviewers: dnovillo, davidxl, bogner Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D14739 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253384 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ProfileData/InstrProf.cpp | 6 +-- .../llvm-profdata/count-mismatch.proftext | 3 +- tools/llvm-profdata/llvm-profdata.cpp | 42 +++++++++++++++++-- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp index ef7b19b2882..2dd0f916c6d 100644 --- a/lib/ProfileData/InstrProf.cpp +++ b/lib/ProfileData/InstrProf.cpp @@ -51,13 +51,13 @@ class InstrProfErrorCategoryType : public std::error_category { case instrprof_error::unknown_function: return "No profile data available for function"; case instrprof_error::hash_mismatch: - return "Function hash mismatch"; + return "Function control flow change detected (hash mismatch)"; case instrprof_error::count_mismatch: - return "Function count mismatch"; + return "Function basic block count change detected (counter mismatch)"; case instrprof_error::counter_overflow: return "Counter overflow"; case instrprof_error::value_site_count_mismatch: - return "Function's value site counts mismatch"; + return "Function value site count change detected (counter mismatch)"; } llvm_unreachable("A value of instrprof_error has no message."); } diff --git a/test/tools/llvm-profdata/count-mismatch.proftext b/test/tools/llvm-profdata/count-mismatch.proftext index 1a2e73fbffd..b42b11dbcf9 100644 --- a/test/tools/llvm-profdata/count-mismatch.proftext +++ b/test/tools/llvm-profdata/count-mismatch.proftext @@ -14,7 +14,8 @@ foo # The hash matches, but we can't combine these because the number of # counters differs. -# MERGE_ERRS: count-mismatch.proftext: foo: Function count mismatch +# MERGE_ERRS: count-mismatch.proftext: foo: Function basic block count change detected (counter mismatch) +# MERGE_ERRS: Make sure that all profile data to be merged is generated from the same binary. foo 1024 3 diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 1cd47dd5e84..f8499c30f66 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -27,6 +27,8 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include + using namespace llvm; static void exitWithError(const Twine &Message, @@ -41,7 +43,8 @@ static void exitWithError(const Twine &Message, ::exit(1); } -static void exitWithErrorCode(const std::error_code &Error, StringRef Whence = "") { +static void exitWithErrorCode(const std::error_code &Error, + StringRef Whence = "") { if (Error.category() == instrprof_category()) { instrprof_error instrError = static_cast(Error.value()); if (instrError == instrprof_error::unrecognized_format) { @@ -57,6 +60,32 @@ namespace { enum ProfileKinds { instr, sample }; } +static void handleMergeWriterError(std::error_code &Error, + StringRef WhenceFile = "", + StringRef WhenceFunction = "", + bool ShowHint = true) +{ + if (!WhenceFile.empty()) + errs() << WhenceFile << ": "; + if (!WhenceFunction.empty()) + errs() << WhenceFunction << ": "; + errs() << Error.message() << "\n"; + + if (ShowHint) { + StringRef Hint = ""; + if (Error.category() == instrprof_category()) { + instrprof_error instrError = static_cast(Error.value()); + if (instrError == instrprof_error::count_mismatch) { + Hint = "Make sure that all profile data to be merged is generated " \ + "from the same binary."; + } + } + + if (!Hint.empty()) + errs() << Hint << "\n"; + } +} + static void mergeInstrProfile(const cl::list &Inputs, StringRef OutputFilename) { if (OutputFilename.compare("-") == 0) @@ -68,15 +97,20 @@ static void mergeInstrProfile(const cl::list &Inputs, exitWithErrorCode(EC, OutputFilename); InstrProfWriter Writer; + std::set WriterErrorCodes; for (const auto &Filename : Inputs) { auto ReaderOrErr = InstrProfReader::create(Filename); if (std::error_code ec = ReaderOrErr.getError()) exitWithErrorCode(ec, Filename); auto Reader = std::move(ReaderOrErr.get()); - for (auto &I : *Reader) - if (std::error_code EC = Writer.addRecord(std::move(I))) - errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; + for (auto &I : *Reader) { + if (std::error_code EC = Writer.addRecord(std::move(I))) { + // Only show hint the first time an error occurs. + bool firstTime = WriterErrorCodes.insert(EC).second; + handleMergeWriterError(EC, Filename, I.Name, firstTime); + } + } if (Reader->hasError()) exitWithErrorCode(Reader->getError(), Filename); } -- 2.34.1