Index: llvm/test/tools/llvm-profdata/invalid-profdata.test =================================================================== --- llvm/test/tools/llvm-profdata/invalid-profdata.test +++ llvm/test/tools/llvm-profdata/invalid-profdata.test @@ -21,7 +21,8 @@ RUN: echo ":10" >> %t.input RUN: not llvm-profdata merge %t.input -text -output=/dev/null 2>&1 | FileCheck %s --check-prefix=BROKEN -BROKEN: Malformed instrumentation profile data +BROKEN: warning: {{.*}}invalid-profdata.test.tmp.input: Malformed instrumentation profile data +BROKEN-NEXT: error: No profiles could be merged. RUN: echo ":ir" > %t.input RUN: echo "_ZN6Thread5StartEv" >> %t.input Index: llvm/test/tools/llvm-profdata/text-format-errors.test =================================================================== --- llvm/test/tools/llvm-profdata/text-format-errors.test +++ llvm/test/tools/llvm-profdata/text-format-errors.test @@ -1,14 +1,21 @@ Tests for instrumentation profile bad encoding. 1- Detect invalid count -RUN: not llvm-profdata show %p/Inputs/invalid-count-later.proftext 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER -RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER -INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data +RUN: not llvm-profdata show %p/Inputs/invalid-count-later.proftext 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER-SHOW +INVALID-COUNT-LATER-SHOW: error: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data + +RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER-MERGE +INVALID-COUNT-LATER-MERGE: warning: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data +INVALID-COUNT-LATER-MERGE-NEXT: warning: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data +INVALID-COUNT-LATER-MERGE-NEXT: error: No profiles could be merged. 2- Detect bad hash -RUN: not llvm-profdata show %p/Inputs/bad-hash.proftext 2>&1 | FileCheck %s --check-prefix=BAD-HASH -RUN: not llvm-profdata merge %p/Inputs/bad-hash.proftext %p/Inputs/bad-hash.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=BAD-HASH -BAD-HASH: error: {{.*}}bad-hash.proftext: Malformed instrumentation profile data +RUN: not llvm-profdata show %p/Inputs/bad-hash.proftext 2>&1 | FileCheck %s --check-prefix=BAD-HASH-SHOW +BAD-HASH-SHOW: error: {{.*}}bad-hash.proftext: Malformed instrumentation profile data + +RUN: not llvm-profdata merge %p/Inputs/bad-hash.proftext %p/Inputs/bad-hash.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=BAD-HASH-MERGE +BAD-HASH-MERGE: warning: {{.*}}bad-hash.proftext: Malformed instrumentation profile data +BAD-HASH-NEXT: error: No profiles could be merged. 3- Detect no counts RUN: not llvm-profdata show %p/Inputs/no-counts.proftext 2>&1 | FileCheck %s --check-prefix=NO-COUNTS Index: llvm/tools/llvm-profdata/llvm-profdata.cpp =================================================================== --- llvm/tools/llvm-profdata/llvm-profdata.cpp +++ llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -174,33 +174,16 @@ struct WriterContext { std::mutex Lock; InstrProfWriter Writer; - Error Err; - std::string ErrWhence; + std::vector> Errors; std::mutex &ErrLock; SmallSet &WriterErrorCodes; WriterContext(bool IsSparse, std::mutex &ErrLock, SmallSet &WriterErrorCodes) - : Lock(), Writer(IsSparse), Err(Error::success()), ErrWhence(""), - ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) {} + : Lock(), Writer(IsSparse), Errors(), ErrLock(ErrLock), + WriterErrorCodes(WriterErrorCodes) {} }; -/// Determine whether an error is fatal for profile merging. -static bool isFatalError(instrprof_error IPE) { - switch (IPE) { - default: - return true; - case instrprof_error::success: - case instrprof_error::eof: - case instrprof_error::unknown_function: - case instrprof_error::hash_mismatch: - case instrprof_error::count_mismatch: - case instrprof_error::counter_overflow: - case instrprof_error::value_site_count_mismatch: - return false; - } -} - /// Computer the overlap b/w profile BaseFilename and TestFileName, /// and store the program level result to Overlap. static void overlapInput(const std::string &BaseFilename, @@ -213,7 +196,7 @@ // Skip the empty profiles by returning sliently. instrprof_error IPE = InstrProfError::take(std::move(E)); if (IPE != instrprof_error::empty_raw_profile) - WC->Err = make_error(IPE); + WC->Errors.emplace_back(make_error(IPE), TestFilename); return; } @@ -232,21 +215,17 @@ WriterContext *WC) { std::unique_lock CtxGuard{WC->Lock}; - // If there's a pending hard error, don't do more work. - if (WC->Err) - return; - // Copy the filename, because llvm::ThreadPool copied the input "const // WeightedFile &" by value, making a reference to the filename within it // invalid outside of this packaged task. - WC->ErrWhence = Input.Filename; + std::string Filename = Input.Filename; auto ReaderOrErr = InstrProfReader::create(Input.Filename); if (Error E = ReaderOrErr.takeError()) { // Skip the empty profiles by returning sliently. instrprof_error IPE = InstrProfError::take(std::move(E)); if (IPE != instrprof_error::empty_raw_profile) - WC->Err = make_error(IPE); + WC->Errors.emplace_back(make_error(IPE), Filename); return; } @@ -254,9 +233,11 @@ bool IsIRProfile = Reader->isIRLevelProfile(); bool HasCSIRProfile = Reader->hasCSIRLevelProfile(); if (WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) { - WC->Err = make_error( - "Merge IR generated profile with Clang generated profile.", - std::error_code()); + WC->Errors.emplace_back( + make_error( + "Merge IR generated profile with Clang generated profile.", + std::error_code()), + Filename); return; } @@ -279,21 +260,16 @@ FuncName, firstTime); }); } - if (Reader->hasError()) { - if (Error E = Reader->getError()) { - instrprof_error IPE = InstrProfError::take(std::move(E)); - if (isFatalError(IPE)) - WC->Err = make_error(IPE); - } - } + if (Reader->hasError()) + if (Error E = Reader->getError()) + WC->Errors.emplace_back(std::move(E), Filename); } /// Merge the \p Src writer context into \p Dst. static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) { - // If we've already seen a hard error, continuing with the merge would - // clobber it. - if (Dst->Err || Src->Err) - return; + for (auto &ErrorPair : Src->Errors) + Dst->Errors.push_back(std::move(ErrorPair)); + Src->Errors.clear(); bool Reported = false; Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) { @@ -302,7 +278,7 @@ return; } Reported = true; - Dst->Err = std::move(E); + Dst->Errors.emplace_back(std::move(E), ""); }); } @@ -365,20 +341,18 @@ } while (Mid > 0); } - // Handle deferred hard errors encountered during merging. + // Handle deferred errors encountered during merging. If the number of errors + // is equal to the number of inputs, or a truly fatal error occurred, the + // merge failed. + unsigned NumErrors = 0; for (std::unique_ptr &WC : Contexts) { - if (!WC->Err) - continue; - if (!WC->Err.isA()) - exitWithError(std::move(WC->Err), WC->ErrWhence); - - instrprof_error IPE = InstrProfError::take(std::move(WC->Err)); - if (isFatalError(IPE)) - exitWithError(make_error(IPE), WC->ErrWhence); - else - warn(toString(make_error(IPE)), - WC->ErrWhence); + for (auto &ErrorPair : WC->Errors) { + ++NumErrors; + warn(toString(std::move(ErrorPair.first)), ErrorPair.second); + } } + if (NumErrors == Inputs.size()) + exitWithError("No profiles could be merged."); std::error_code EC; raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::OF_None);