Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Profile] Add binary profile correlation for code coverage. #69493

Merged
merged 14 commits into from
Dec 14, 2023
Merged
11 changes: 8 additions & 3 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,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"
Expand Down Expand Up @@ -102,17 +103,21 @@ 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;
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved

// Re-link builtin bitcodes after optimization
cl::opt<bool> ClRelinkBuiltinBitcodePostop(
"relink-builtin-bitcode-postop", cl::Optional,
cl::desc("Re-link builtin bitcodes after optimization."), cl::init(false));
}
} // namespace llvm

namespace {

// Default filename used for profile generation.
std::string getDefaultProfileGenName() {
return DebugInfoCorrelate ? "default_%m.proflite" : "default_%m.profraw";
return DebugInfoCorrelate || ProfileCorrelate != InstrProfCorrelator::NONE
? "default_%m.proflite"
: "default_%m.profraw";
}

class EmitAssemblyHelper {
Expand Down Expand Up @@ -204,7 +209,7 @@ class EmitAssemblyHelper {
void EmitAssembly(BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS,
BackendConsumer *BC);
};
}
} // namespace

static SanitizerCoverageOptions
getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
Expand Down
17 changes: 17 additions & 0 deletions compiler-rt/include/profile/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ INSTR_PROF_SECT_ENTRY(IPSK_covfun, \
INSTR_PROF_SECT_ENTRY(IPSK_orderfile, \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON), \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COFF), "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON), \
INSTR_PROF_COVDATA_COFF, "__LLVM_COV,")
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")

#undef INSTR_PROF_SECT_ENTRY
#endif
Expand Down Expand Up @@ -701,6 +707,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
#define INSTR_PROF_COVFUN_COMMON __llvm_covfun
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
Expand All @@ -713,6 +721,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
#define INSTR_PROF_COVFUN_COFF ".lcovfun$M"
/* Since cov data and cov names sections are not allocated, we don't need to
* access them at runtime.
*/
#define INSTR_PROF_COVDATA_COFF ".lcovd"
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"

#ifdef _WIN32
Expand All @@ -729,6 +742,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_COVFUN_COFF
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
#else
/* Runtime section names and name strings. */
Expand All @@ -744,6 +759,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON)
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON)
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVFUN_COMMON)
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON)
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON)
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@

#if defined(_MSC_VER)
/* Merge read-write sections into .data. */
#pragma comment(linker, "/MERGE:.lprfc=.data")
#pragma comment(linker, "/MERGE:.lprfb=.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
* after the fact.
* Do *NOT* merge .lprfc .rdata. When binary profile correlation is enabled,
* llvm-cov must be able to find after the fact.
*/

/* Allocate read-only section bounds. */
Expand Down
5 changes: 3 additions & 2 deletions compiler-rt/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
46 changes: 46 additions & 0 deletions compiler-rt/test/profile/instrprof-binary-correlate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// REQUIRES: linux || windows
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved
// Default
// RUN: %clang -o %t.normal -fprofile-instr-generate -fcoverage-mapping %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 %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.
15 changes: 11 additions & 4 deletions llvm/docs/CommandGuide/llvm-profdata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,14 @@ 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 ``--debug-info-correlate`` or ``--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

Expand Down Expand Up @@ -346,8 +352,9 @@ 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 ``--debug-info-correlate`` or ``--profile-correlate=debug-info`` was used
for instrumentation, use this option to show the correlated functions from the
raw profile.

.. option:: --covered

Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/ProfileData/InstrProf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
55 changes: 43 additions & 12 deletions llvm/include/llvm/ProfileData/InstrProfCorrelator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,8 +31,9 @@ class ObjectFile;
/// to their functions.
class InstrProfCorrelator {
public:
/// Indicate which kind correlator to use.
enum ProfCorrelatorKind { NONE, DEBUG_INFO };
/// 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 Filename, ProfCorrelatorKind FileKind);
Expand Down Expand Up @@ -71,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;
};
Expand Down Expand Up @@ -145,19 +153,20 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {

Error dumpYaml(int MaxWarnings, raw_ostream &OS) override;

void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
IntPtrT FunctionPtr, uint32_t NumCounters);
void addDataProbe(uint64_t 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
Expand Down Expand Up @@ -214,6 +223,28 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
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

#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
17 changes: 17 additions & 0 deletions llvm/include/llvm/ProfileData/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ INSTR_PROF_SECT_ENTRY(IPSK_covfun, \
INSTR_PROF_SECT_ENTRY(IPSK_orderfile, \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON), \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COFF), "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_covdata, \
INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON), \
INSTR_PROF_COVDATA_COFF, "__LLVM_COV,")
INSTR_PROF_SECT_ENTRY(IPSK_covname, \
INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON), \
INSTR_PROF_COVNAME_COFF, "__LLVM_COV,")

#undef INSTR_PROF_SECT_ENTRY
#endif
Expand Down Expand Up @@ -701,6 +707,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
#define INSTR_PROF_COVFUN_COMMON __llvm_covfun
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
#define INSTR_PROF_COVNAME_COMMON __llvm_covnames
#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
/* Windows section names. Because these section names contain dollar characters,
* they must be quoted.
Expand All @@ -713,6 +721,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
#define INSTR_PROF_COVFUN_COFF ".lcovfun$M"
/* Since cov data and cov names sections are not allocated, we don't need to
* access them at runtime.
*/
#define INSTR_PROF_COVDATA_COFF ".lcovd"
#define INSTR_PROF_COVNAME_COFF ".lcovn"
#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"

#ifdef _WIN32
Expand All @@ -729,6 +742,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_COVFUN_COFF
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_COVDATA_COFF
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_COVNAME_COFF
#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
#else
/* Runtime section names and name strings. */
Expand All @@ -744,6 +759,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON)
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON)
#define INSTR_PROF_COVFUN_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVFUN_COMMON)
#define INSTR_PROF_COVDATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVDATA_COMMON)
#define INSTR_PROF_COVNAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVNAME_COMMON)
/* Order file instrumentation. */
#define INSTR_PROF_ORDERFILE_SECT_NAME \
INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
Expand Down
9 changes: 0 additions & 9 deletions llvm/include/llvm/ProfileData/InstrProfReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ class InstrProfReader {

virtual bool instrEntryBBEnabled() const = 0;

/// Return true if we must provide debug info to create PGO profiles.
virtual bool useDebugInfoCorrelate() const { return false; }

/// Return true if the profile has single byte counters representing coverage.
virtual bool hasSingleByteCoverage() const = 0;

Expand Down Expand Up @@ -378,12 +375,6 @@ class RawInstrProfReader : public InstrProfReader {
return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
}

bool useDebugInfoCorrelate() const override {
return (Version & VARIANT_MASK_DBG_CORRELATE) != 0;
}

bool useCorrelate() const { return useDebugInfoCorrelate(); }

bool hasSingleByteCoverage() const override {
return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) {
/*AddSegmentInfo=*/false) ||
Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF,
/*AddSegmentInfo=*/false) ||
Name == getInstrProfSectionName(IPSK_covdata, Triple::ELF,
/*AddSegmentInfo=*/false) ||
Name == getInstrProfSectionName(IPSK_covname, Triple::ELF,
/*AddSegmentInfo=*/false) ||
Name == ".llvmbc" || Name == ".llvmcmd")
return SectionKind::getMetadata();

Expand Down