https://github.com/ZequanWu updated https://github.com/llvm/llvm-project/pull/69493
>From 3a394ce5d4d7d91251337bd0a2c1c1a074eb37e6 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Tue, 17 Oct 2023 19:24:12 -0400 Subject: [PATCH 1/6] [Profile] Add binary profile correlation. --- clang/lib/CodeGen/BackendUtil.cpp | 10 +- clang/lib/CodeGen/CoverageMappingGen.cpp | 20 ++ .../CodeGen/coverage-profile-raw-version.c | 9 + compiler-rt/include/profile/InstrProfData.inc | 2 + compiler-rt/lib/profile/InstrProfiling.h | 3 + .../lib/profile/InstrProfilingBuffer.c | 14 ++ compiler-rt/lib/profile/InstrProfilingMerge.c | 8 +- .../profile/InstrProfilingPlatformWindows.c | 2 - .../lib/profile/InstrProfilingWriter.c | 24 +-- compiler-rt/test/CMakeLists.txt | 5 +- .../Darwin/instrprof-debug-info-correlate.c | 4 +- .../instrprof-debug-info-correlate-warnings.c | 2 +- .../Linux/instrprof-debug-info-correlate.c | 6 +- .../instrprof-show-debug-info-correlation.c | 6 +- .../test/profile/instrprof-binary-correlate.c | 29 +++ llvm/include/llvm/ProfileData/InstrProf.h | 6 +- .../llvm/ProfileData/InstrProfCorrelator.h | 59 ++++- .../llvm/ProfileData/InstrProfData.inc | 2 + .../llvm/ProfileData/InstrProfReader.h | 10 + .../Instrumentation/PGOInstrumentation.h | 2 - .../CodeGen/TargetLoweringObjectFileImpl.cpp | 23 +- .../Coverage/CoverageMappingReader.cpp | 28 ++- llvm/lib/ProfileData/InstrProf.cpp | 8 +- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 203 ++++++++++++++---- llvm/lib/ProfileData/InstrProfReader.cpp | 8 +- .../Instrumentation/InstrProfiling.cpp | 31 +-- .../Instrumentation/PGOInstrumentation.cpp | 3 +- .../debug-info-correlate-coverage.ll | 2 +- .../InstrProfiling/debug-info-correlate.ll | 2 +- llvm/tools/llvm-profdata/llvm-profdata.cpp | 37 +++- 30 files changed, 436 insertions(+), 132 deletions(-) create mode 100644 clang/test/CodeGen/coverage-profile-raw-version.c create mode 100644 compiler-rt/test/profile/instrprof-binary-correlate.c diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 70accce456d3c07..dad3c9a145b5049 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -42,6 +42,7 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/ProfileData/InstrProfCorrelator.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" @@ -98,13 +99,16 @@ extern cl::opt<bool> PrintPipelinePasses; static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP( "sanitizer-early-opt-ep", cl::Optional, cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false)); -} + +extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate; +} // namespace llvm namespace { // Default filename used for profile generation. std::string getDefaultProfileGenName() { - return DebugInfoCorrelate ? "default_%m.proflite" : "default_%m.profraw"; + return ProfileCorrelate.getNumOccurrences() ? "default_%m.proflite" + : "default_%m.profraw"; } class EmitAssemblyHelper { @@ -197,7 +201,7 @@ class EmitAssemblyHelper { void EmitAssembly(BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS); }; -} +} // namespace static SanitizerCoverageOptions getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) { diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 76ed10091b025be..daff0d1d50923f5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -31,6 +31,10 @@ // is textually included. #define COVMAP_V3 +namespace llvm { +extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate; +} // namespace llvm + static llvm::cl::opt<bool> EmptyLineCommentCoverage( "emptyline-comment-coverage", llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " @@ -1831,6 +1835,22 @@ void CoverageMappingModuleGen::emit() { llvm::GlobalValue::InternalLinkage, NamesArrVal, llvm::getCoverageUnusedNamesVarName()); } + const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); + llvm::Type *IntTy64 = llvm::Type::getInt64Ty(Ctx); + uint64_t ProfileVersion = INSTR_PROF_RAW_VERSION; + if (llvm::ProfileCorrelate == llvm::InstrProfCorrelator::BINARY) + ProfileVersion |= VARIANT_MASK_BIN_CORRELATE; + auto *VersionVariable = new llvm::GlobalVariable( + CGM.getModule(), llvm::Type::getInt64Ty(Ctx), true, + llvm::GlobalValue::WeakAnyLinkage, + llvm::Constant::getIntegerValue(IntTy64, llvm::APInt(64, ProfileVersion)), + VarName); + VersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility); + llvm::Triple TT(CGM.getModule().getTargetTriple()); + if (TT.supportsCOMDAT()) { + VersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage); + VersionVariable->setComdat(CGM.getModule().getOrInsertComdat(VarName)); + } } unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) { diff --git a/clang/test/CodeGen/coverage-profile-raw-version.c b/clang/test/CodeGen/coverage-profile-raw-version.c new file mode 100644 index 000000000000000..fc81179e1a33e06 --- /dev/null +++ b/clang/test/CodeGen/coverage-profile-raw-version.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -mllvm -profile-correlate=binary -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s --check-prefix=BIN-CORRELATE + +// CHECK: @__llvm_profile_raw_version = {{.*}} i64 8 +// BIN-CORRELATE: @__llvm_profile_raw_version = {{.*}} i64 4294967304 + +int main() { + return 0; +} diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc index 8ba7e186d4fb1a6..1841ef348a70061 100644 --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -655,6 +655,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * version for other variants of profile. We set the 8th most significant bit * (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation * generated profile, and 0 if this is a Clang FE generated profile. + * 1 in bit 32 indicates there is no profile name and data sections. * 1 in bit 57 indicates there are context-sensitive records in the profile. * The 59th bit indicates whether to use debug info to correlate profiles. * The 60th bit indicates single byte coverage instrumentation. @@ -664,6 +665,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, */ #define VARIANT_MASKS_ALL 0xffffffff00000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) +#define VARIANT_MASK_BIN_CORRELATE (0x1ULL << 32) #define VARIANT_MASK_IR_PROF (0x1ULL << 56) #define VARIANT_MASK_CSIR_PROF (0x1ULL << 57) #define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58) diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index 4433d7bd48871fc..8b9e029ee8baee5 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -267,6 +267,9 @@ uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin, uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End); +/*! \brief Get the size of the profile name section in bytes. */ +uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End); + /*! \brief Get the size in bytes of a single counter entry. */ size_t __llvm_profile_counter_entry_size(void); diff --git a/compiler-rt/lib/profile/InstrProfilingBuffer.c b/compiler-rt/lib/profile/InstrProfilingBuffer.c index 61ac5d9c0285002..e60aa9fc04e7fac 100644 --- a/compiler-rt/lib/profile/InstrProfilingBuffer.c +++ b/compiler-rt/lib/profile/InstrProfilingBuffer.c @@ -53,6 +53,9 @@ uint64_t __llvm_profile_get_size_for_buffer(void) { COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin, const __llvm_profile_data *End) { + if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) || + (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE)) + return 0; intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) / sizeof(__llvm_profile_data); @@ -61,9 +64,20 @@ uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin, COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End) { + if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) || + (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE)) + return 0; return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data); } +COMPILER_RT_VISIBILITY +uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End) { + if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) || + (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE)) + return 0; + return End - Begin; +} + COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) { if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) return sizeof(uint8_t); diff --git a/compiler-rt/lib/profile/InstrProfilingMerge.c b/compiler-rt/lib/profile/InstrProfilingMerge.c index 9cf12f251f7262d..554ce3693b6e464 100644 --- a/compiler-rt/lib/profile/InstrProfilingMerge.c +++ b/compiler-rt/lib/profile/InstrProfilingMerge.c @@ -66,8 +66,9 @@ int __llvm_profile_check_compatibility(const char *ProfileData, Header->NumCounters != __llvm_profile_get_num_counters(__llvm_profile_begin_counters(), __llvm_profile_end_counters()) || - Header->NamesSize != (uint64_t)(__llvm_profile_end_names() - - __llvm_profile_begin_names()) || + Header->NamesSize != + __llvm_profile_get_name_size(__llvm_profile_begin_names(), + __llvm_profile_end_names()) || Header->ValueKindLast != IPVK_Last) return 1; @@ -132,7 +133,8 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, // Merge counters by iterating the entire counter section when debug info // correlation is enabled. - if (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) { + if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) || + (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE)) { for (SrcCounter = SrcCountersStart, DstCounter = __llvm_profile_begin_counters(); SrcCounter < SrcCountersEnd;) { diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c index dd576b2f8357dbb..23a7739355e2ed6 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c @@ -13,8 +13,6 @@ #if defined(_MSC_VER) /* Merge read-write sections into .data. */ -#pragma comment(linker, "/MERGE:.lprfc=.data") -#pragma comment(linker, "/MERGE:.lprfd=.data") #pragma comment(linker, "/MERGE:.lprfv=.data") #pragma comment(linker, "/MERGE:.lprfnd=.data") /* Do *NOT* merge .lprfn and .lcovmap into .rdata. llvm-cov must be able to find diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c index 1e22398a4c0f64a..f3709694427d5c8 100644 --- a/compiler-rt/lib/profile/InstrProfilingWriter.c +++ b/compiler-rt/lib/profile/InstrProfilingWriter.c @@ -259,19 +259,19 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, const char *CountersBegin, const char *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, const char *NamesEnd, int SkipNameDataWrite) { - int DebugInfoCorrelate = - (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) != 0ULL; + int ProfileCorrelation = + (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) || + (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE); /* Calculate size of sections. */ const uint64_t DataSectionSize = - DebugInfoCorrelate ? 0 : __llvm_profile_get_data_size(DataBegin, DataEnd); - const uint64_t NumData = - DebugInfoCorrelate ? 0 : __llvm_profile_get_num_data(DataBegin, DataEnd); + __llvm_profile_get_data_size(DataBegin, DataEnd); + const uint64_t NumData = __llvm_profile_get_num_data(DataBegin, DataEnd); const uint64_t CountersSectionSize = __llvm_profile_get_counters_size(CountersBegin, CountersEnd); const uint64_t NumCounters = __llvm_profile_get_num_counters(CountersBegin, CountersEnd); - const uint64_t NamesSize = DebugInfoCorrelate ? 0 : NamesEnd - NamesBegin; + const uint64_t NamesSize = __llvm_profile_get_name_size(NamesBegin, NamesEnd); /* Create the header. */ __llvm_profile_header Header; @@ -298,7 +298,7 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, #endif /* The data and names sections are omitted in lightweight mode. */ - if (DebugInfoCorrelate) { + if (ProfileCorrelation) { Header.CountersDelta = 0; Header.NamesDelta = 0; } @@ -314,19 +314,19 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, /* Write the profile data. */ ProfDataIOVec IOVecData[] = { - {DebugInfoCorrelate ? NULL : DataBegin, sizeof(uint8_t), DataSectionSize, + {ProfileCorrelation ? NULL : DataBegin, sizeof(uint8_t), DataSectionSize, 0}, {NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1}, {CountersBegin, sizeof(uint8_t), CountersSectionSize, 0}, {NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1}, - {(SkipNameDataWrite || DebugInfoCorrelate) ? NULL : NamesBegin, + {(SkipNameDataWrite || ProfileCorrelation) ? NULL : NamesBegin, sizeof(uint8_t), NamesSize, 0}, {NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}}; if (Writer->Write(Writer, IOVecData, sizeof(IOVecData) / sizeof(*IOVecData))) return -1; - - /* Value profiling is not yet supported in continuous mode. */ - if (__llvm_profile_is_continuous_mode_enabled()) + /* Value profiling is not yet supported in continuous mode and profile + * correlation mode. */ + if (__llvm_profile_is_continuous_mode_enabled() || ProfileCorrelation) return 0; return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd); diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt index f9b01b15b0e62c6..7357604b1f651eb 100644 --- a/compiler-rt/test/CMakeLists.txt +++ b/compiler-rt/test/CMakeLists.txt @@ -37,8 +37,9 @@ if(NOT ANDROID) if(NOT COMPILER_RT_STANDALONE_BUILD AND NOT LLVM_RUNTIMES_BUILD) # Use LLVM utils and Clang from the same build tree. list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS - clang clang-resource-headers FileCheck count not llvm-config llvm-nm llvm-objdump - llvm-readelf llvm-readobj llvm-size llvm-symbolizer compiler-rt-headers sancov split-file) + clang clang-resource-headers FileCheck count not llvm-config llvm-nm + llvm-objdump llvm-readelf llvm-readobj llvm-size llvm-symbolizer + compiler-rt-headers sancov split-file llvm-strip) if (WIN32) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS KillTheDoctor) endif() diff --git a/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c index f347d439e2e0671..46d25a4e386dc3a 100644 --- a/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c +++ b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c @@ -1,5 +1,5 @@ // Value profiling is currently not supported in lightweight mode. -// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.proflite @@ -9,7 +9,7 @@ // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) -// RUN: %clang_pgogen -o %t.cov -g -mllvm --debug-info-correlate -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t.cov -g -mllvm --profile-correlate=debug-info -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov // RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov.dSYM %t.cov.proflite diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c index 5069c6340b64fd2..25022f241a6d281 100644 --- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c +++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c @@ -1,6 +1,6 @@ // Disable full debug info and verify that we get warnings during merging -// RUN: %clang_pgogen -o %t -gline-tables-only -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t -gline-tables-only -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite --max-debug-info-correlation-warnings=2 2>&1 >/dev/null | FileCheck %s --check-prefixes=CHECK,LIMIT --implicit-check-not=warning // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite --max-debug-info-correlation-warnings=0 2>&1 >/dev/null | FileCheck %s --check-prefixes=CHECK,NOLIMIT --implicit-check-not=warning diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c index a918d7b6299005e..ccfd65b6f4c4b16 100644 --- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c +++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c @@ -3,19 +3,19 @@ // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal // RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw -// RUN: %clang_pgogen -o %t.d4 -g -gdwarf-4 -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t.d4 -g -gdwarf-4 -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.d4.proflite %run %t.d4 // RUN: llvm-profdata merge -o %t.d4.profdata --debug-info=%t.d4 %t.d4.proflite // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.d4.profdata) -// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) -// RUN: %clang_pgogen -o %t.cov -g -mllvm --debug-info-correlate -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: %clang_pgogen -o %t.cov -g -mllvm --profile-correlate=debug-info -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov // RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov %t.cov.proflite diff --git a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c index 226d678aca347a4..93bf40f98d3ab62 100644 --- a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c +++ b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c @@ -1,10 +1,10 @@ -// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %s +// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %s // RUN: llvm-profdata show --debug-info=%t --detailed-summary --show-prof-sym-list | FileCheck %s // RUN: llvm-profdata show --debug-info=%t --show-format=yaml | FileCheck %s --match-full-lines --check-prefix YAML -// RUN: %clang_pgogen -o %t.no.dbg -mllvm --debug-info-correlate -mllvm --disable-vp=true %s +// RUN: %clang_pgogen -o %t.no.dbg -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %s // RUN: not llvm-profdata show --debug-info=%t.no.dbg 2>&1 | FileCheck %s --check-prefix NO-DBG -// NO-DBG: unable to correlate profile: could not find any profile metadata in debug info +// NO-DBG: unable to correlate profile: could not find any profile data metadata in correlated file // YAML: Probes: // YAML: - Function Name: a diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c new file mode 100644 index 000000000000000..2154c13027e286b --- /dev/null +++ b/compiler-rt/test/profile/instrprof-binary-correlate.c @@ -0,0 +1,29 @@ +// REQUIRES: linux || windows +// Default +// RUN: %clang -o %t.normal -fprofile-instr-generate -fcoverage-mapping -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw + +// With -profile-correlate=binary flag +// RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe +// RUN: llvm-profdata merge -o %t-1.profdata --object-file=%t-1.exe %t-1.profraw +// RUN: diff %t.normal.profdata %t-1.profdata + +// Strip above binary and run +// RUN: llvm-strip %t-1.exe -o %t-2.exe +// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe +// RUN: llvm-profdata merge -o %t-2.profdata --object-file=%t-1.exe %t-2.profraw +// RUN: diff %t.normal.profdata %t-2.profdata + +// Online merging. +// RUN: env LLVM_PROFILE_FILE=%t-3.profraw %run %t.normal +// RUN: env LLVM_PROFILE_FILE=%t-4.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.merged.profdata %t-3.profraw %t-4.profraw +// RUN: rm -rf %t.profdir && mkdir %t.profdir +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe +// RUN: llvm-profdata merge -o %t-4.profdata --object-file=%t-1.exe %t.profdir +// RUN: diff %t.normal.merged.profdata %t-4.profdata + +// TODO: After adding support for binary ID, test binaries with different binary IDs. diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h index 9239c1a691eca19..00a7bafb54e89ea 100644 --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -328,8 +328,8 @@ enum class instrprof_error { too_large, truncated, malformed, - missing_debug_info_for_correlation, - unexpected_debug_info_for_correlation, + missing_correlation_info, + unexpected_correlation_info, unable_to_correlate_profile, unknown_function, invalid_prof, @@ -460,7 +460,7 @@ class InstrProfSymtab { /// only initialize the symtab with reference to the data and /// the section base address. The decompression will be delayed /// until before it is used. See also \c create(StringRef) method. - Error create(object::SectionRef &Section); + Error create(object::SectionRef &Section, bool MightHasNullByte = false); /// This interface is used by reader of CoverageMapping test /// format. diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h index dd062951f277c1c..661570eaee11300 100644 --- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h +++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// This file defines InstrProfCorrelator used to generate PGO profiles from -// raw profile data and debug info. +// This file defines InstrProfCorrelator used to generate PGO/coverage profiles +// from raw profile data and debug info/binary file. //===----------------------------------------------------------------------===// #ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H @@ -31,8 +31,12 @@ class ObjectFile; /// to their functions. class InstrProfCorrelator { public: + /// Indicate if we should use the debug info or profile metadata sections to + /// correlate. + enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY }; + static llvm::Expected<std::unique_ptr<InstrProfCorrelator>> - get(StringRef DebugInfoFilename); + get(StringRef Filename, ProfCorrelatorKind FileKind); /// Construct a ProfileData vector used to correlate raw instrumentation data /// to their functions. @@ -68,11 +72,18 @@ class InstrProfCorrelator { protected: struct Context { static llvm::Expected<std::unique_ptr<Context>> - get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj); + get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj, + ProfCorrelatorKind FileKind); std::unique_ptr<MemoryBuffer> Buffer; /// The address range of the __llvm_prf_cnts section. uint64_t CountersSectionStart; uint64_t CountersSectionEnd; + /// The pointer points to start/end of profile data/name sections if + /// FileKind is Binary. + const char *DataStart; + const char *DataEnd; + const char *NameStart; + size_t NameSize; /// True if target and host have different endian orders. bool ShouldSwapBytes; }; @@ -104,7 +115,7 @@ class InstrProfCorrelator { private: static llvm::Expected<std::unique_ptr<InstrProfCorrelator>> - get(std::unique_ptr<MemoryBuffer> Buffer); + get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind); const InstrProfCorrelatorKind Kind; }; @@ -128,7 +139,7 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator { static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>> get(std::unique_ptr<InstrProfCorrelator::Context> Ctx, - const object::ObjectFile &Obj); + const object::ObjectFile &Obj, ProfCorrelatorKind FileKind); protected: std::vector<RawInstrProf::ProfileData<IntPtrT>> Data; @@ -138,21 +149,23 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator { int MaxWarnings, InstrProfCorrelator::CorrelationData *Data = nullptr) = 0; + virtual Error correlateProfileNameImpl() = 0; + Error dumpYaml(int MaxWarnings, raw_ostream &OS) override; void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT FunctionPtr, uint32_t NumCounters); + // Byte-swap the value if necessary. + template <class T> T maybeSwap(T Value) const { + return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value; + } + private: InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind, std::unique_ptr<InstrProfCorrelator::Context> Ctx) : InstrProfCorrelator(Kind, std::move(Ctx)){}; llvm::DenseSet<IntPtrT> CounterOffsets; - - // Byte-swap the value if necessary. - template <class T> T maybeSwap(T Value) const { - return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value; - } }; /// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes @@ -205,6 +218,30 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> { void correlateProfileDataImpl( int MaxWarnings, InstrProfCorrelator::CorrelationData *Data = nullptr) override; + + Error correlateProfileNameImpl() override; +}; + +/// BinaryInstrProfCorrelator - A child of InstrProfCorrelatorImpl that +/// takes an object file as input to correlate profiles. +template <class IntPtrT> +class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> { +public: + BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx) + : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)) {} + + /// Return a pointer to the names string that this class constructs. + const char *getNamesPointer() const { return this->Ctx.NameStart; } + + /// Return the number of bytes in the names string. + size_t getNamesSize() const { return this->Ctx.NameSize; } + +private: + void correlateProfileDataImpl( + int MaxWarnings, + InstrProfCorrelator::CorrelationData *Data = nullptr) override; + + Error correlateProfileNameImpl() override; }; } // end namespace llvm diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc index 13be2753e514efe..f6c5f2b3fa17301 100644 --- a/llvm/include/llvm/ProfileData/InstrProfData.inc +++ b/llvm/include/llvm/ProfileData/InstrProfData.inc @@ -655,6 +655,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * version for other variants of profile. We set the 8th most significant bit * (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation * generated profile, and 0 if this is a Clang FE generated profile. + * 1 in bit 32 indicates whether to use binary to correlate profiles. * 1 in bit 57 indicates there are context-sensitive records in the profile. * The 59th bit indicates whether to use debug info to correlate profiles. * The 60th bit indicates single byte coverage instrumentation. @@ -664,6 +665,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, */ #define VARIANT_MASKS_ALL 0xffffffff00000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) +#define VARIANT_MASK_BIN_CORRELATE (0x1ULL << 32) #define VARIANT_MASK_IR_PROF (0x1ULL << 56) #define VARIANT_MASK_CSIR_PROF (0x1ULL << 57) #define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58) diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h index 5f54cbeb1b01eda..d5eb009087d9f9b 100644 --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -126,6 +126,8 @@ class InstrProfReader { /// Return true if we must provide debug info to create PGO profiles. virtual bool useDebugInfoCorrelate() const { return false; } + virtual bool useBinaryCorrelate() const { return false; } + /// Return true if the profile has single byte counters representing coverage. virtual bool hasSingleByteCoverage() const = 0; @@ -374,6 +376,14 @@ class RawInstrProfReader : public InstrProfReader { return (Version & VARIANT_MASK_DBG_CORRELATE) != 0; } + bool useBinaryCorrelate() const override { + return (Version & VARIANT_MASK_BIN_CORRELATE) != 0; + } + + bool useCorrelate() const { + return useDebugInfoCorrelate() || useBinaryCorrelate(); + } + bool hasSingleByteCoverage() const override { return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0; } diff --git a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h index 5b1977b7de9a2ae..3d8f3bd9235451f 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h @@ -24,8 +24,6 @@ namespace llvm { -extern cl::opt<bool> DebugInfoCorrelate; - class Function; class Instruction; class Module; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 6210e7fc128a30c..fd785ff2629932e 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -57,6 +57,7 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" #include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/InstrProfCorrelator.h" #include "llvm/Support/Base64.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" @@ -71,6 +72,10 @@ using namespace llvm; using namespace dwarf; +namespace llvm { +extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate; +} // namespace llvm + static cl::opt<bool> JumpTableInFunctionSection( "jumptable-in-function-section", cl::Hidden, cl::init(false), cl::desc("Putting Jump Table in function section")); @@ -472,7 +477,15 @@ static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) { /*AddSegmentInfo=*/false) || Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF, /*AddSegmentInfo=*/false) || - Name == ".llvmbc" || Name == ".llvmcmd") + Name == ".llvmbc" || Name == ".llvmcmd" || + // Instead of checking the flag, maybe we should check if + // VARIANT_MASK_BIN_CORRELATE flag is set at the profile version global + // variable. + (ProfileCorrelate == InstrProfCorrelator::BINARY && + (Name == getInstrProfSectionName(llvm::IPSK_name, Triple::ELF, + /*AddSegmentInfo=*/false) || + Name == getInstrProfSectionName(llvm::IPSK_data, Triple::ELF, + /*AddSegmentInfo=*/false)))) return SectionKind::getMetadata(); if (Name.empty() || Name[0] != '.') return K; @@ -1674,9 +1687,15 @@ static int getSelectionForCOFF(const GlobalValue *GV) { MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + StringRef Name = GO->getSection(); + if (ProfileCorrelate == InstrProfCorrelator::BINARY && + (Name == getInstrProfSectionName(llvm::IPSK_name, Triple::COFF, + /*AddSegmentInfo=*/false) || + Name == getInstrProfSectionName(llvm::IPSK_data, Triple::COFF, + /*AddSegmentInfo=*/false))) + Kind = SectionKind::getMetadata(); int Selection = 0; unsigned Characteristics = getCOFFSectionFlags(Kind, TM); - StringRef Name = GO->getSection(); StringRef COMDATSymName = ""; if (GO->hasComdat()) { Selection = getSelectionForCOFF(GO); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index 857498256ec54c4..a56e4c90911141b 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -457,7 +457,7 @@ Expected<bool> RawCoverageMappingDummyChecker::isDummy() { return Tag == Counter::Zero; } -Error InstrProfSymtab::create(SectionRef &Section) { +Error InstrProfSymtab::create(SectionRef &Section, bool MightHasNullByte) { Expected<StringRef> DataOrErr = Section.getContents(); if (!DataOrErr) return DataOrErr.takeError(); @@ -467,7 +467,8 @@ Error InstrProfSymtab::create(SectionRef &Section) { // If this is a linked PE/COFF file, then we have to skip over the null byte // that is allocated in the .lprfn$A section in the LLVM profiling runtime. const ObjectFile *Obj = Section.getObject(); - if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) + if (MightHasNullByte && isa<COFFObjectFile>(Obj) && + !Obj->isRelocatableObject()) Data = Data.drop_front(1); return Error::success(); @@ -1070,11 +1071,24 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch, InstrProfSymtab ProfileNames; std::vector<SectionRef> NamesSectionRefs = *NamesSection; - if (NamesSectionRefs.size() != 1) - return make_error<CoverageMapError>( - coveragemap_error::malformed, - "the size of coverage mapping section is not one"); - if (Error E = ProfileNames.create(NamesSectionRefs.back())) + bool MightHasNullByte = true; + if (NamesSectionRefs.size() != 1) { + // By default, the profile name section in the binary starts with a null + // byte and followed by names. But if binary correlation is enabled, there + // will be 2 name sections. One contains only two null bytes, and another + // one contains the names without the dummy null byte at the beginning. + if (ObjFormat == Triple::COFF) { + NamesSectionRefs.erase( + std::remove_if(NamesSectionRefs.begin(), NamesSectionRefs.end(), + [](const SectionRef &S) { return S.isData(); })); + MightHasNullByte = false; + } + if (NamesSectionRefs.size() != 1) + return make_error<CoverageMapError>( + coveragemap_error::malformed, + "the size of coverage mapping section is not one"); + } + if (Error E = ProfileNames.create(NamesSectionRefs.back(), MightHasNullByte)) return std::move(E); // Look for the coverage records section (Version4 only). diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index ddc11304742df76..349ebf3762df40a 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -113,11 +113,11 @@ static std::string getInstrProfErrString(instrprof_error Err, case instrprof_error::malformed: OS << "malformed instrumentation profile data"; break; - case instrprof_error::missing_debug_info_for_correlation: - OS << "debug info for correlation is required"; + case instrprof_error::missing_correlation_info: + OS << "debug info/binary for correlation is required"; break; - case instrprof_error::unexpected_debug_info_for_correlation: - OS << "debug info for correlation is not necessary"; + case instrprof_error::unexpected_correlation_info: + OS << "debug info/binary for correlation is not necessary"; break; case instrprof_error::unable_to_correlate_profile: OS << "unable to correlate profile"; diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index 71787c9bd8577b4..347879e71bbda18 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -24,15 +24,43 @@ using namespace llvm; -/// Get the __llvm_prf_cnts section. -Expected<object::SectionRef> getCountersSection(const object::ObjectFile &Obj) { +namespace llvm { +cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate( + "profile-correlate", + cl::desc("Use debug info or binary file to correlate profiles."), + cl::init(InstrProfCorrelator::NONE), + cl::values(clEnumValN(InstrProfCorrelator::NONE, "", + "No profile correlation"), + clEnumValN(InstrProfCorrelator::DEBUG_INFO, "debug-info", + "Use debug info to correlate"), + clEnumValN(InstrProfCorrelator::BINARY, "binary", + "Use binary to correlate"))); +} // namespace llvm + +/// Get profile section. +Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj, + InstrProfSectKind IPSK) { + // On COFF, the object file section name may end in "$M". This tells the + // linker to sort these sections between "$A" and "$Z". The linker removes the + // dollar and everything after it in the final binary. Do the same to match. + Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat(); + std::string ExpectedSectionName = + getInstrProfSectionName(IPSK, ObjFormat, + /*AddSegmentInfo=*/false); for (auto &Section : Obj.sections()) if (auto SectionName = Section.getName()) - if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME) + if (SectionName.get() == ExpectedSectionName) { + // There will be extra profile name and data sections in COFF used for + // runtime to detect start/stop of those sections, skipping them. + // (details at compiler-rt/lib/profile/InstrProfilingPlatformWindows.c) + if (ObjFormat == Triple::COFF && IPSK != IPSK_cnts && Section.isData()) + continue; return Section; + } + return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, - "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME ")"); + "could not find section (" + Twine(ExpectedSectionName) + ")"); } const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name"; @@ -41,56 +69,84 @@ const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters"; llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>> InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer, - const object::ObjectFile &Obj) { - auto CountersSection = getCountersSection(Obj); + const object::ObjectFile &Obj, + ProfCorrelatorKind FileKind) { + auto C = std::make_unique<Context>(); + auto CountersSection = getInstrProfSection(Obj, IPSK_cnts); if (auto Err = CountersSection.takeError()) return std::move(Err); - auto C = std::make_unique<Context>(); + if (FileKind == InstrProfCorrelator::BINARY) { + auto DataSection = getInstrProfSection(Obj, IPSK_data); + if (auto Err = DataSection.takeError()) + return std::move(Err); + auto DataOrErr = DataSection->getContents(); + if (!DataOrErr) + return DataOrErr.takeError(); + auto NameSection = getInstrProfSection(Obj, IPSK_name); + if (auto Err = NameSection.takeError()) + return std::move(Err); + auto NameOrErr = NameSection->getContents(); + if (!NameOrErr) + return NameOrErr.takeError(); + C->DataStart = DataOrErr->data(); + C->DataEnd = DataOrErr->data() + DataOrErr->size(); + C->NameStart = NameOrErr->data(); + C->NameSize = NameOrErr->size(); + } C->Buffer = std::move(Buffer); C->CountersSectionStart = CountersSection->getAddress(); C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize(); + // In COFF object file, there's a null byte at the beginning of the counter + // section which doesn't exist in raw profile. + if (Obj.getTripleObjectFormat() == Triple::COFF) + C->CountersSectionStart++; + C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost; return Expected<std::unique_ptr<Context>>(std::move(C)); } llvm::Expected<std::unique_ptr<InstrProfCorrelator>> -InstrProfCorrelator::get(StringRef DebugInfoFilename) { - auto DsymObjectsOrErr = - object::MachOObjectFile::findDsymObjectMembers(DebugInfoFilename); - if (auto Err = DsymObjectsOrErr.takeError()) - return std::move(Err); - if (!DsymObjectsOrErr->empty()) { - // TODO: Enable profile correlation when there are multiple objects in a - // dSYM bundle. - if (DsymObjectsOrErr->size() > 1) - return make_error<InstrProfError>( - instrprof_error::unable_to_correlate_profile, - "using multiple objects is not yet supported"); - DebugInfoFilename = *DsymObjectsOrErr->begin(); +InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) { + if (FileKind == DEBUG_INFO) { + auto DsymObjectsOrErr = + object::MachOObjectFile::findDsymObjectMembers(Filename); + if (auto Err = DsymObjectsOrErr.takeError()) + return std::move(Err); + if (!DsymObjectsOrErr->empty()) { + // TODO: Enable profile correlation when there are multiple objects in a + // dSYM bundle. + if (DsymObjectsOrErr->size() > 1) + return make_error<InstrProfError>( + instrprof_error::unable_to_correlate_profile, + "using multiple objects is not yet supported"); + Filename = *DsymObjectsOrErr->begin(); + } } - auto BufferOrErr = - errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename)); + auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename)); if (auto Err = BufferOrErr.takeError()) return std::move(Err); - return get(std::move(*BufferOrErr)); + return get(std::move(*BufferOrErr), FileKind); } llvm::Expected<std::unique_ptr<InstrProfCorrelator>> -InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer) { +InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer, + ProfCorrelatorKind FileKind) { auto BinOrErr = object::createBinary(*Buffer); if (auto Err = BinOrErr.takeError()) return std::move(Err); if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) { - auto CtxOrErr = Context::get(std::move(Buffer), *Obj); + auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind); if (auto Err = CtxOrErr.takeError()) return std::move(Err); auto T = Obj->makeTriple(); if (T.isArch64Bit()) - return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj); + return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj, + FileKind); if (T.isArch32Bit()) - return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj); + return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj, + FileKind); } return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, "not an object file"); @@ -132,29 +188,35 @@ template <class IntPtrT> llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>> InstrProfCorrelatorImpl<IntPtrT>::get( std::unique_ptr<InstrProfCorrelator::Context> Ctx, - const object::ObjectFile &Obj) { - if (Obj.isELF() || Obj.isMachO()) { - auto DICtx = DWARFContext::create(Obj); - return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx), - std::move(Ctx)); + const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) { + if (FileKind == DEBUG_INFO) { + if (Obj.isELF() || Obj.isMachO()) { + auto DICtx = DWARFContext::create(Obj); + return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>( + std::move(DICtx), std::move(Ctx)); + } + return make_error<InstrProfError>( + instrprof_error::unable_to_correlate_profile, + "unsupported debug info format (only DWARF is supported)"); } + if (Obj.isELF() || Obj.isCOFF()) + return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx)); return make_error<InstrProfError>( - instrprof_error::unable_to_correlate_profile, - "unsupported debug info format (only DWARF is supported)"); + instrprof_error::unable_to_correlate_profile, + "unsupported binary format (only ELF and COFF are supported)"); } template <class IntPtrT> Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) { assert(Data.empty() && Names.empty() && NamesVec.empty()); correlateProfileDataImpl(MaxWarnings); - if (Data.empty() || NamesVec.empty()) + if (this->Data.empty()) return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, - "could not find any profile metadata in debug info"); - auto Result = - collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names); - CounterOffsets.clear(); - NamesVec.clear(); + "could not find any profile data metadata in correlated file"); + Error Result = correlateProfileNameImpl(); + this->CounterOffsets.clear(); + this->NamesVec.clear(); return Result; } @@ -361,3 +423,64 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( WithColor::warning() << format("Suppressed %d additional warnings\n", NumSuppressedWarnings); } + +template <class IntPtrT> +Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { + if (this->NamesVec.empty()) { + return make_error<InstrProfError>( + instrprof_error::unable_to_correlate_profile, + "could not find any profile name metadata in debug info"); + } + auto Result = collectPGOFuncNameStrings(this->NamesVec, + /*doCompression=*/false, this->Names); + return Result; +} + +template <class IntPtrT> +void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( + int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) { + bool UnlimitedWarnings = (MaxWarnings == 0); + // -N suppressed warnings means we can emit up to N (unsuppressed) warnings + int NumSuppressedWarnings = -MaxWarnings; + + const RawInstrProf::ProfileData<IntPtrT> *DataStart = + (const RawInstrProf::ProfileData<IntPtrT> *)this->Ctx->DataStart; + const RawInstrProf::ProfileData<IntPtrT> *DataEnd = + (const RawInstrProf::ProfileData<IntPtrT> *)this->Ctx->DataEnd; + // We need to use < here because the last data record may have no padding. + for (const RawInstrProf::ProfileData<IntPtrT> *I = DataStart; I < DataEnd; + ++I) { + uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr); + uint64_t CountersStart = this->Ctx->CountersSectionStart; + uint64_t CountersEnd = this->Ctx->CountersSectionEnd; + if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) { + if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { + WithColor::warning() << format( + "CounterPtr out of range for function: Actual=0x%x " + "Expected=[0x%x, 0x%x) at data offset=0x%x\n", + CounterPtr, CountersStart, CountersEnd, + (I - DataStart) * sizeof(RawInstrProf::ProfileData<IntPtrT>)); + } + } + IntPtrT CounterOffset = CounterPtr - CountersStart; + this->Data.push_back({I->NameRef, + I->FuncHash, + this->template maybeSwap<IntPtrT>(CounterOffset), + I->FunctionPointer, + // Value profiling is not supported. + 0, + I->NumCounters, + {0, 0}}); + } +} + +template <class IntPtrT> +Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { + if (this->Ctx->NameSize == 0) { + return make_error<InstrProfError>( + instrprof_error::unable_to_correlate_profile, + "could not find any profile data metadata in object file"); + } + this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize); + return Error::success(); +} diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index a920a31d0a4b229..2b5181e6b34043c 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -540,10 +540,10 @@ Error RawInstrProfReader<IntPtrT>::readHeader( "\nPLEASE update this tool to version in the raw profile, or " "regenerate raw profile with expected version.") .str()); - if (useDebugInfoCorrelate() && !Correlator) - return error(instrprof_error::missing_debug_info_for_correlation); - if (!useDebugInfoCorrelate() && Correlator) - return error(instrprof_error::unexpected_debug_info_for_correlation); + if (useCorrelate() && !Correlator) + return error(instrprof_error::missing_correlation_info); + if (!useCorrelate() && Correlator) + return error(instrprof_error::unexpected_correlation_info); BinaryIdsSize = swap(Header.BinaryIdsSize); if (BinaryIdsSize % sizeof(uint64_t)) diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 57fcfd53836911b..7eaa92bfe842e16 100644 --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -60,10 +60,7 @@ using namespace llvm; #define DEBUG_TYPE "instrprof" namespace llvm { -cl::opt<bool> - DebugInfoCorrelate("debug-info-correlate", - cl::desc("Use debug info to correlate profiles."), - cl::init(false)); +extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate; } // namespace llvm namespace { @@ -627,7 +624,7 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) { // in lightweight mode. We need to move the value profile pointer to the // Counter struct to get this working. assert( - !DebugInfoCorrelate && + ProfileCorrelate == InstrProfCorrelator::NONE && "Value profiling is not yet supported with lightweight instrumentation"); GlobalVariable *Name = Ind->getName(); auto It = ProfileDataMap.find(Name); @@ -965,8 +962,8 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) { // Use internal rather than private linkage so the counter variable shows up // in the symbol table when using debug info for correlation. - if (DebugInfoCorrelate && TT.isOSBinFormatMachO() && - Linkage == GlobalValue::PrivateLinkage) + if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO && + TT.isOSBinFormatMachO() && Linkage == GlobalValue::PrivateLinkage) Linkage = GlobalValue::InternalLinkage; // Due to the limitation of binder as of 2021/09/28, the duplicate weak @@ -1030,7 +1027,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) { CounterPtr->setLinkage(Linkage); MaybeSetComdat(CounterPtr); PD.RegionCounters = CounterPtr; - if (DebugInfoCorrelate) { + if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) { if (auto *SP = Fn->getSubprogram()) { DIBuilder DB(*M, true, SP->getUnit()); Metadata *FunctionNameAnnotation[] = { @@ -1083,7 +1080,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) { ConstantExpr::getBitCast(ValuesVar, Type::getInt8PtrTy(Ctx)); } - if (DebugInfoCorrelate) { + if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) { // Mark the counter variable as used so that it isn't optimized out. CompilerUsedVars.push_back(PD.RegionCounters); return PD.RegionCounters; @@ -1124,11 +1121,17 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) { } auto *Data = new GlobalVariable(*M, DataTy, false, Linkage, nullptr, DataVarName); - // Reference the counter variable with a label difference (link-time - // constant). - auto *RelativeCounterPtr = - ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy), - ConstantExpr::getPtrToInt(Data, IntPtrTy)); + Constant *RelativeCounterPtr; + if (ProfileCorrelate == InstrProfCorrelator::BINARY) { + // CounterPtr needs to be absolute when we make data section strippable. + RelativeCounterPtr = ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy); + } else { + // Reference the counter variable with a label difference (link-time + // constant). + RelativeCounterPtr = + ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy), + ConstantExpr::getPtrToInt(Data, IntPtrTy)); + } Constant *DataVals[] = { #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init, diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 7ad1c9bc54f3780..6dcbf3ada5f0c72 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -327,6 +327,7 @@ extern cl::opt<PGOViewCountsType> PGOViewCounts; // Defined in Analysis/BlockFrequencyInfo.cpp: -view-bfi-func-name= extern cl::opt<std::string> ViewBlockFreqFuncName; +extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate; } // namespace llvm static cl::opt<bool> @@ -381,7 +382,7 @@ static GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS) { ProfileVersion |= VARIANT_MASK_CSIR_PROF; if (PGOInstrumentEntry) ProfileVersion |= VARIANT_MASK_INSTR_ENTRY; - if (DebugInfoCorrelate) + if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) ProfileVersion |= VARIANT_MASK_DBG_CORRELATE; if (PGOFunctionEntryCoverage) ProfileVersion |= diff --git a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll index 192bac6e503a07b..dd6461533817050 100644 --- a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll +++ b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -passes=instrprof -debug-info-correlate -S | opt -O2 -S | FileCheck %s +; RUN: opt < %s -passes=instrprof -profile-correlate=debug-info -S | opt -O2 -S | FileCheck %s @__profn_foo = private constant [3 x i8] c"foo" ; CHECK: @__profc_foo diff --git a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll index fd868ead5b78d21..84eaab33701a487 100644 --- a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll +++ b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -passes=instrprof -debug-info-correlate -S > %t.ll +; RUN: opt < %s -passes=instrprof -profile-correlate=debug-info -S > %t.ll ; RUN: FileCheck < %t.ll --implicit-check-not "{{__llvm_prf_data|__llvm_prf_names}}" %s ; RUN: %llc_dwarf -O0 -filetype=obj < %t.ll | llvm-dwarfdump - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s --check-prefix CHECK-DWARF diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 7d665a8005b0d62..c0db32e8343d820 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -413,10 +413,11 @@ static void writeInstrProfile(StringRef OutputFilename, static void mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, - SymbolRemapper *Remapper, StringRef OutputFilename, - ProfileFormat OutputFormat, uint64_t TraceReservoirSize, - uint64_t MaxTraceLength, int MaxDbgCorrelationWarnings, - bool OutputSparse, unsigned NumThreads, FailureMode FailMode, + StringRef ObjectFilename, SymbolRemapper *Remapper, + StringRef OutputFilename, ProfileFormat OutputFormat, + uint64_t TraceReservoirSize, uint64_t MaxTraceLength, + int MaxDbgCorrelationWarnings, bool OutputSparse, + unsigned NumThreads, FailureMode FailMode, const StringRef ProfiledBinary) { if (OutputFormat == PF_Compact_Binary) exitWithError("Compact Binary is deprecated"); @@ -425,12 +426,17 @@ mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, exitWithError("unknown format is specified"); std::unique_ptr<InstrProfCorrelator> Correlator; - if (!DebugInfoFilename.empty()) { + if (!DebugInfoFilename.empty() || !ObjectFilename.empty()) { + InstrProfCorrelator::ProfCorrelatorKind Kind = + DebugInfoFilename.empty() ? InstrProfCorrelator::BINARY + : InstrProfCorrelator::DEBUG_INFO; + StringRef FileName = + DebugInfoFilename.empty() ? ObjectFilename : DebugInfoFilename; if (auto Err = - InstrProfCorrelator::get(DebugInfoFilename).moveInto(Correlator)) - exitWithError(std::move(Err), DebugInfoFilename); + InstrProfCorrelator::get(FileName, Kind).moveInto(Correlator)) + exitWithError(std::move(Err), FileName); if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings)) - exitWithError(std::move(Err), DebugInfoFilename); + exitWithError(std::move(Err), FileName); } std::mutex ErrorLock; @@ -1279,6 +1285,10 @@ static int merge_main(int argc, const char *argv[]) { cl::opt<std::string> DebugInfoFilename( "debug-info", cl::init(""), cl::desc("Use the provided debug info to correlate the raw profile.")); + cl::opt<std::string> ObjectFilename( + "object-file", cl::init(""), + cl::desc("Read and extract profile metadata from object file and show " + "the functions it found.")); cl::opt<unsigned> MaxDbgCorrelationWarnings( "max-debug-info-correlation-warnings", cl::desc("The maximum number of warnings to emit when correlating " @@ -1304,6 +1314,9 @@ static int merge_main(int argc, const char *argv[]) { "(default: 10000)")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); + if (!DebugInfoFilename.empty() && !ObjectFilename.empty()) { + exitWithError("Expected only one of -debug-info, -object-file"); + } WeightedFileVector WeightedInputs; for (StringRef Filename : InputFilenames) @@ -1342,8 +1355,8 @@ static int merge_main(int argc, const char *argv[]) { } if (ProfileKind == instr) - mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), - OutputFilename, OutputFormat, + mergeInstrProfile(WeightedInputs, DebugInfoFilename, ObjectFilename, + Remapper.get(), OutputFilename, OutputFormat, TemporalProfTraceReservoirSize, TemporalProfMaxTraceLength, MaxDbgCorrelationWarnings, OutputSparse, NumThreads, FailureMode, ProfiledBinary); @@ -2893,7 +2906,9 @@ static int showDebugInfoCorrelation(const std::string &Filename, if (SFormat == ShowFormat::Json) exitWithError("JSON output is not supported for debug info correlation"); std::unique_ptr<InstrProfCorrelator> Correlator; - if (auto Err = InstrProfCorrelator::get(Filename).moveInto(Correlator)) + if (auto Err = + InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO) + .moveInto(Correlator)) exitWithError(std::move(Err), Filename); if (SFormat == ShowFormat::Yaml) { if (auto Err = Correlator->dumpYaml(MaxDbgCorrelationWarnings, OS)) >From 776784459f67f44c0455ab0f3b216f7d9c6a6376 Mon Sep 17 00:00:00 2001 From: My Name <zequa...@google.com> Date: Wed, 18 Oct 2023 13:30:21 -0400 Subject: [PATCH 2/6] fix correlator for coff. --- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index 347879e71bbda18..168c2803145f1ff 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -44,12 +44,16 @@ Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj, // linker to sort these sections between "$A" and "$Z". The linker removes the // dollar and everything after it in the final binary. Do the same to match. Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat(); + auto StripSuffix = [ObjFormat](StringRef N) { + return ObjFormat == Triple::COFF ? N.split('$').first : N; + }; std::string ExpectedSectionName = getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false); + ExpectedSectionName = StripSuffix(ExpectedSectionName); for (auto &Section : Obj.sections()) if (auto SectionName = Section.getName()) - if (SectionName.get() == ExpectedSectionName) { + if (StripSuffix(*SectionName) == ExpectedSectionName) { // There will be extra profile name and data sections in COFF used for // runtime to detect start/stop of those sections, skipping them. // (details at compiler-rt/lib/profile/InstrProfilingPlatformWindows.c) >From c5cca07062572077c4140b4eb9a4bdbb22a385a6 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Wed, 18 Oct 2023 13:59:04 -0400 Subject: [PATCH 3/6] update docs and renaming option --- .../test/profile/instrprof-binary-correlate.c | 6 +++--- llvm/docs/CommandGuide/llvm-profdata.rst | 13 +++++++++---- llvm/tools/llvm-profdata/llvm-profdata.cpp | 18 +++++++++--------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c index 2154c13027e286b..bc05dbd99b82516 100644 --- a/compiler-rt/test/profile/instrprof-binary-correlate.c +++ b/compiler-rt/test/profile/instrprof-binary-correlate.c @@ -7,13 +7,13 @@ // With -profile-correlate=binary flag // RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe -// RUN: llvm-profdata merge -o %t-1.profdata --object-file=%t-1.exe %t-1.profraw +// RUN: llvm-profdata merge -o %t-1.profdata --binary-file=%t-1.exe %t-1.profraw // RUN: diff %t.normal.profdata %t-1.profdata // Strip above binary and run // RUN: llvm-strip %t-1.exe -o %t-2.exe // RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe -// RUN: llvm-profdata merge -o %t-2.profdata --object-file=%t-1.exe %t-2.profraw +// RUN: llvm-profdata merge -o %t-2.profdata --binary-file=%t-1.exe %t-2.profraw // RUN: diff %t.normal.profdata %t-2.profdata // Online merging. @@ -23,7 +23,7 @@ // RUN: rm -rf %t.profdir && mkdir %t.profdir // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe -// RUN: llvm-profdata merge -o %t-4.profdata --object-file=%t-1.exe %t.profdir +// RUN: llvm-profdata merge -o %t-4.profdata --binary-file=%t-1.exe %t.profdir // RUN: diff %t.normal.merged.profdata %t-4.profdata // TODO: After adding support for binary ID, test binaries with different binary IDs. diff --git a/llvm/docs/CommandGuide/llvm-profdata.rst b/llvm/docs/CommandGuide/llvm-profdata.rst index be42733ca140567..f81c80601e98a11 100644 --- a/llvm/docs/CommandGuide/llvm-profdata.rst +++ b/llvm/docs/CommandGuide/llvm-profdata.rst @@ -195,8 +195,13 @@ OPTIONS .. option:: --debug-info=<path> Specify the executable or ``.dSYM`` that contains debug info for the raw profile. - When ``-debug-info-correlate`` was used for instrumentation, use this option - to correlate the raw profile. + When ``-profile-correlate=debug-info`` was used for instrumentation, use this + option to correlate the raw profile. + +.. option:: --binary-file=<path> +Specify the executable that contains profile data and profile name sections for +the raw profile. When ``-profile-correlate=binary`` was used for +instrumentation, use this option to correlate the raw profile. .. option:: --temporal-profile-trace-reservoir-size @@ -346,8 +351,8 @@ OPTIONS .. option:: --debug-info=<path> Specify the executable or ``.dSYM`` that contains debug info for the raw profile. - When ``-debug-info-correlate`` was used for instrumentation, use this option - to show the correlated functions from the raw profile. + When ``-profile-correlate=debug-info`` was used for instrumentation, use this + option to show the correlated functions from the raw profile. .. option:: --covered diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index c0db32e8343d820..068504228d97d3f 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -413,7 +413,7 @@ static void writeInstrProfile(StringRef OutputFilename, static void mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, - StringRef ObjectFilename, SymbolRemapper *Remapper, + StringRef BinaryFilename, SymbolRemapper *Remapper, StringRef OutputFilename, ProfileFormat OutputFormat, uint64_t TraceReservoirSize, uint64_t MaxTraceLength, int MaxDbgCorrelationWarnings, bool OutputSparse, @@ -426,12 +426,12 @@ mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, exitWithError("unknown format is specified"); std::unique_ptr<InstrProfCorrelator> Correlator; - if (!DebugInfoFilename.empty() || !ObjectFilename.empty()) { + if (!DebugInfoFilename.empty() || !BinaryFilename.empty()) { InstrProfCorrelator::ProfCorrelatorKind Kind = DebugInfoFilename.empty() ? InstrProfCorrelator::BINARY : InstrProfCorrelator::DEBUG_INFO; StringRef FileName = - DebugInfoFilename.empty() ? ObjectFilename : DebugInfoFilename; + DebugInfoFilename.empty() ? BinaryFilename : DebugInfoFilename; if (auto Err = InstrProfCorrelator::get(FileName, Kind).moveInto(Correlator)) exitWithError(std::move(Err), FileName); @@ -1285,9 +1285,9 @@ static int merge_main(int argc, const char *argv[]) { cl::opt<std::string> DebugInfoFilename( "debug-info", cl::init(""), cl::desc("Use the provided debug info to correlate the raw profile.")); - cl::opt<std::string> ObjectFilename( - "object-file", cl::init(""), - cl::desc("Read and extract profile metadata from object file and show " + cl::opt<std::string> BinaryFilename( + "binary-file", cl::init(""), + cl::desc("Read and extract profile metadata from binary file and show " "the functions it found.")); cl::opt<unsigned> MaxDbgCorrelationWarnings( "max-debug-info-correlation-warnings", @@ -1314,8 +1314,8 @@ static int merge_main(int argc, const char *argv[]) { "(default: 10000)")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); - if (!DebugInfoFilename.empty() && !ObjectFilename.empty()) { - exitWithError("Expected only one of -debug-info, -object-file"); + if (!DebugInfoFilename.empty() && !BinaryFilename.empty()) { + exitWithError("Expected only one of -debug-info, -binary-file"); } WeightedFileVector WeightedInputs; @@ -1355,7 +1355,7 @@ static int merge_main(int argc, const char *argv[]) { } if (ProfileKind == instr) - mergeInstrProfile(WeightedInputs, DebugInfoFilename, ObjectFilename, + mergeInstrProfile(WeightedInputs, DebugInfoFilename, BinaryFilename, Remapper.get(), OutputFilename, OutputFormat, TemporalProfTraceReservoirSize, TemporalProfMaxTraceLength, MaxDbgCorrelationWarnings, >From 44704f6fd6ec0f277ed734b2d91c15b1fb3a7fe6 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Wed, 18 Oct 2023 14:48:54 -0400 Subject: [PATCH 4/6] format --- clang/lib/CodeGen/BackendUtil.cpp | 2 +- compiler-rt/test/profile/instrprof-binary-correlate.c | 8 ++++---- llvm/docs/CommandGuide/llvm-profdata.rst | 7 ++++--- llvm/include/llvm/ProfileData/InstrProfCorrelator.h | 2 +- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index dad3c9a145b5049..69692c28b16cba1 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -56,6 +56,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" +#include "llvm/Transforms/HipStdPar/HipStdPar.h" #include "llvm/Transforms/IPO/EmbedBitcodePass.h" #include "llvm/Transforms/IPO/LowerTypeTests.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" @@ -79,7 +80,6 @@ #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/JumpThreading.h" -#include "llvm/Transforms/HipStdPar/HipStdPar.h" #include "llvm/Transforms/Utils/Debugify.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ModuleUtils.h" diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c index bc05dbd99b82516..d921c4c5dcb0191 100644 --- a/compiler-rt/test/profile/instrprof-binary-correlate.c +++ b/compiler-rt/test/profile/instrprof-binary-correlate.c @@ -7,14 +7,14 @@ // With -profile-correlate=binary flag // RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe -// RUN: llvm-profdata merge -o %t-1.profdata --binary-file=%t-1.exe %t-1.profraw -// RUN: diff %t.normal.profdata %t-1.profdata +// RUN: llvm-profdata merge -o %t-1.profdata --binary-file=%t-1.exe %t-1.profraw +// RUN: diff %t.normal.profdata %t-1.profdata // Strip above binary and run // RUN: llvm-strip %t-1.exe -o %t-2.exe // RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe -// RUN: llvm-profdata merge -o %t-2.profdata --binary-file=%t-1.exe %t-2.profraw -// RUN: diff %t.normal.profdata %t-2.profdata +// RUN: llvm-profdata merge -o %t-2.profdata --binary-file=%t-1.exe %t-2.profraw +// RUN: diff %t.normal.profdata %t-2.profdata // Online merging. // RUN: env LLVM_PROFILE_FILE=%t-3.profraw %run %t.normal diff --git a/llvm/docs/CommandGuide/llvm-profdata.rst b/llvm/docs/CommandGuide/llvm-profdata.rst index f81c80601e98a11..89b331c5bbd9c6b 100644 --- a/llvm/docs/CommandGuide/llvm-profdata.rst +++ b/llvm/docs/CommandGuide/llvm-profdata.rst @@ -199,9 +199,10 @@ OPTIONS option to correlate the raw profile. .. option:: --binary-file=<path> -Specify the executable that contains profile data and profile name sections for -the raw profile. When ``-profile-correlate=binary`` was used for -instrumentation, use this option to correlate the raw profile. + + Specify the executable that contains profile data and profile name sections for + the raw profile. When ``-profile-correlate=binary`` was used for + instrumentation, use this option to correlate the raw profile. .. option:: --temporal-profile-trace-reservoir-size diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h index 661570eaee11300..ba82702354c1898 100644 --- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h +++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h @@ -5,7 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// This file defines InstrProfCorrelator used to generate PGO/coverage profiles +// This file defines InstrProfCorrelator used to generate PGO/coverage profiles // from raw profile data and debug info/binary file. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index 168c2803145f1ff..6796f2828d01726 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -206,8 +206,8 @@ InstrProfCorrelatorImpl<IntPtrT>::get( if (Obj.isELF() || Obj.isCOFF()) return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx)); return make_error<InstrProfError>( - instrprof_error::unable_to_correlate_profile, - "unsupported binary format (only ELF and COFF are supported)"); + instrprof_error::unable_to_correlate_profile, + "unsupported binary format (only ELF and COFF are supported)"); } template <class IntPtrT> >From 384ee6c1197683ff087bf04f8a5d1e79b27ecfc4 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Wed, 18 Oct 2023 17:05:44 -0400 Subject: [PATCH 5/6] add llvm-cov and IR test --- .../test/profile/instrprof-binary-correlate.c | 17 +++++++++++++++++ .../InstrProfiling/binary-correlate.ll | 11 +++++++++++ 2 files changed, 28 insertions(+) create mode 100644 llvm/test/Instrumentation/InstrProfiling/binary-correlate.ll diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c index d921c4c5dcb0191..8009e572652689a 100644 --- a/compiler-rt/test/profile/instrprof-binary-correlate.c +++ b/compiler-rt/test/profile/instrprof-binary-correlate.c @@ -3,27 +3,44 @@ // RUN: %clang -o %t.normal -fprofile-instr-generate -fcoverage-mapping -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal // RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw +// RUN: llvm-cov report --instr-profile=%t.normal.profdata %t.normal > %t.normal.report +// RUN: llvm-cov show --instr-profile=%t.normal.profdata %t.normal > %t.normal.show // With -profile-correlate=binary flag // RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp // RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe // RUN: llvm-profdata merge -o %t-1.profdata --binary-file=%t-1.exe %t-1.profraw +// RUN: llvm-cov report --instr-profile=%t-1.profdata %t-1.exe > %t-1.report +// RUN: llvm-cov show --instr-profile=%t-1.profdata %t-1.exe > %t-1.show // RUN: diff %t.normal.profdata %t-1.profdata +// RUN: diff %t.normal.report %t-1.report +// RUN: diff %t.normal.show %t-1.show // Strip above binary and run // RUN: llvm-strip %t-1.exe -o %t-2.exe // RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe // RUN: llvm-profdata merge -o %t-2.profdata --binary-file=%t-1.exe %t-2.profraw +// RUN: llvm-cov report --instr-profile=%t-2.profdata %t-1.exe > %t-2.report +// RUN: llvm-cov show --instr-profile=%t-2.profdata %t-1.exe > %t-2.show // RUN: diff %t.normal.profdata %t-2.profdata +// RUN: diff %t.normal.report %t-2.report +// RUN: diff %t.normal.show %t-2.show // Online merging. // RUN: env LLVM_PROFILE_FILE=%t-3.profraw %run %t.normal // RUN: env LLVM_PROFILE_FILE=%t-4.profraw %run %t.normal // RUN: llvm-profdata merge -o %t.normal.merged.profdata %t-3.profraw %t-4.profraw +// RUN: llvm-cov report --instr-profile=%t.normal.merged.profdata %t.normal > %t.normal.merged.report +// RUN: llvm-cov show --instr-profile=%t.normal.merged.profdata %t.normal > %t.normal.merged.show + // RUN: rm -rf %t.profdir && mkdir %t.profdir // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe // RUN: llvm-profdata merge -o %t-4.profdata --binary-file=%t-1.exe %t.profdir +// RUN: llvm-cov report --instr-profile=%t-4.profdata %t-1.exe > %t-4.report +// RUN: llvm-cov show --instr-profile=%t-4.profdata %t-1.exe > %t-4.show // RUN: diff %t.normal.merged.profdata %t-4.profdata +// RUN: diff %t.normal.merged.report %t-4.report +// RUN: diff %t.normal.merged.show %t-4.show // TODO: After adding support for binary ID, test binaries with different binary IDs. diff --git a/llvm/test/Instrumentation/InstrProfiling/binary-correlate.ll b/llvm/test/Instrumentation/InstrProfiling/binary-correlate.ll new file mode 100644 index 000000000000000..2206ce17d881dfb --- /dev/null +++ b/llvm/test/Instrumentation/InstrProfiling/binary-correlate.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -passes=instrprof -profile-correlate=binary -S | FileCheck %s + +; CHECK: @__profd_foo = private global { i64, i64, i64, ptr, ptr, i32, [2 x i16] } { i64 {{.*}}, i64 {{.*}}, i64 ptrtoint (ptr @__profc_foo to i64) + +@__profn_foo = private constant [3 x i8] c"foo" +define void @_Z3foov() { + call void @llvm.instrprof.increment(ptr @__profn_foo, i64 12345678, i32 2, i32 0) + ret void +} + +declare void @llvm.instrprof.increment(ptr, i64, i32, i32) >From 37f5fc4fb52eac17b01dced7cffeb6df1212d92c Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Thu, 2 Nov 2023 15:50:53 -0400 Subject: [PATCH 6/6] add missing DebugInfoCorrelate --- llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 6dcbf3ada5f0c72..1717f62327ea410 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -382,7 +382,7 @@ static GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS) { ProfileVersion |= VARIANT_MASK_CSIR_PROF; if (PGOInstrumentEntry) ProfileVersion |= VARIANT_MASK_INSTR_ENTRY; - if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) + if (DebugInfoCorrelate || ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) ProfileVersion |= VARIANT_MASK_DBG_CORRELATE; if (PGOFunctionEntryCoverage) ProfileVersion |= _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits