Skip to content

Commit 787cd8f

Browse files
authored
[InstrProf] Add debuginfod correlation support (#106606)
This patch adds debuginfod support into llvm-profdata to find the assosicated executable by a build id in a raw profile to correlate a profile with a provided correlation kind (debug-info or binary).
1 parent 876b0e6 commit 787cd8f

File tree

10 files changed

+253
-36
lines changed

10 files changed

+253
-36
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// REQUIRES: curl
2+
// RUN: rm -rf %t
3+
4+
// Default instrumented build with no profile correlation.
5+
// RUN: %clang_pgogen -o %t.default -Wl,--build-id=0x12345678 -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
6+
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.default
7+
// RUN: llvm-profdata merge -o %t.default.profdata %t.profraw
8+
9+
// Build with profile debuginfo correlation.
10+
// RUN: %clang_pgogen -o %t.correlate.exe -Wl,--build-id=0x12345678 -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
11+
// RUN: env LLVM_PROFILE_FILE=%t.debug-info-correlate.proflite %run %t.correlate.exe
12+
13+
// Test llvm-profdata merge profile correlation with --debuginfod option.
14+
// RUN: mkdir -p %t/buildid/12345678
15+
// RUN: cp %t.correlate.exe %t/buildid/12345678/debuginfo
16+
// RUN: mkdir -p %t/debuginfod-cache
17+
// RUN: env DEBUGINFOD_CACHE_PATH=%t/debuginfod-cache DEBUGINFOD_URLS=file://%t llvm-profdata merge -o %t.correlate-debuginfod.profdata --debuginfod --correlate=debug-info %t.debug-info-correlate.proflite
18+
// RUN: diff <(llvm-profdata show --all-functions --counts %t.default.profdata) <(llvm-profdata show --all-functions --counts %t.correlate-debuginfod.profdata)
19+
20+
// Test llvm-profdata merge profile correlation with --debug-file-directory option.
21+
// RUN: mkdir -p %t/.build-id/12
22+
// RUN: cp %t.correlate.exe %t/.build-id/12/345678.debug
23+
// RUN: llvm-profdata merge -o %t.correlate-debug-file-dir.profdata --debug-file-directory %t --correlate=debug-info %t.debug-info-correlate.proflite
24+
// RUN: diff <(llvm-profdata show --all-functions --counts %t.default.profdata) <(llvm-profdata show --all-functions --counts %t.correlate-debug-file-dir.profdata)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// REQUIRES: linux || windows
2+
// REQUIRES: curl
3+
4+
// Default instrumented build with no profile correlation.
5+
// RUN: %clang_profgen -o %t.default.exe -Wl,--build-id=0x12345678 -fprofile-instr-generate -fcoverage-mapping %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp
6+
// RUN: env LLVM_PROFILE_FILE=%t.default.profraw %run %t.default.exe
7+
// RUN: llvm-profdata merge -o %t.default.profdata %t.default.profraw
8+
// RUN: llvm-profdata show --all-functions --counts %t.default.profdata > %t.default.profdata.show
9+
10+
// Build with profile binary correlation.
11+
// RUN: %clang_profgen -o %t.correlate.exe -Wl,--build-id=0x12345678 -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
12+
// Strip above binary and run
13+
// RUN: llvm-strip %t.correlate.exe -o %t.stripped.exe
14+
// RUN: env LLVM_PROFILE_FILE=%t.correlate.profraw %run %t.stripped.exe
15+
16+
// Test llvm-profdata merge profile correlation with --debuginfod option.
17+
// RUN: mkdir -p %t/buildid/12345678
18+
// RUN: cp %t.correlate.exe %t/buildid/12345678/debuginfo
19+
// RUN: mkdir -p %t/debuginfod-cache
20+
// RUN: env DEBUGINFOD_CACHE_PATH=%t/debuginfod-cache DEBUGINFOD_URLS=file://%t llvm-profdata merge -o %t.correlate-debuginfod.profdata --debuginfod --correlate=binary %t.correlate.profraw
21+
// RUN: llvm-profdata show --all-functions --counts %t.correlate-debuginfod.profdata > %t.correlate-debuginfod.profdata.show
22+
// RUN: diff %t.default.profdata.show %t.correlate-debuginfod.profdata.show
23+
24+
// Test llvm-profdata merge profile correlation with --debug-file-directory option.
25+
// RUN: mkdir -p %t/.build-id/12
26+
// RUN: cp %t.correlate.exe %t/.build-id/12/345678.debug
27+
// RUN: llvm-profdata merge -o %t.correlate-debug-file-dir.profdata --debug-file-directory %t --correlate=binary %t.correlate.profraw
28+
// RUN: llvm-profdata show --all-functions --counts %t.correlate-debug-file-dir.profdata > %t.correlate-debug-file-dir.profdata.show
29+
// RUN: diff %t.default.profdata.show %t.correlate-debug-file-dir.profdata.show
30+
31+
// Test error for llvm-profdata merge profile correlation with only --correlate=binary option.
32+
// RUN: not llvm-profdata merge -o %t.correlate-error.profdata --correlate=binary %t.correlate.profraw 2>&1 | FileCheck %s --check-prefix=MISSING-FLAG
33+
// MISSING-FLAG: error: Expected --debuginfod or --debug-file-directory when --correlate is provided
34+
35+
// Test error for llvm-profdata merge profile correlation when a proper --correlate option is not provided.
36+
// RUN: not llvm-profdata merge -o %t.correlate-error.profdata --debug-file-directory %t --correlate="" %t.correlate.profraw 2>&1 | FileCheck %s --check-prefix=MISSING-CORRELATION-KIND
37+
// MISSING-CORRELATION-KIND: error: Expected --correlate when --debug-file-directory is provided
38+
39+
// Test error for llvm-profdata merge profile correlation with mixing correlation options.
40+
// RUN: not llvm-profdata merge -o %t.error.profdata --binary-file=%t.correlate.exe --debug-file-directory %t --correlate=binary %t.correlate.profraw 2>&1 | FileCheck %s --check-prefix=MIXING-FLAGS
41+
// MIXING-FLAGS: error: Expected only one of -binary-file, -debuginfod or -debug-file-directory

compiler-rt/test/profile/lit.cfg.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,6 @@ def exclude_unsupported_files_for_aix(dirname):
179179

180180
if config.android:
181181
config.unsupported = True
182+
183+
if config.have_curl:
184+
config.available_features.add("curl")

llvm/docs/CommandGuide/llvm-profdata.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,25 @@ OPTIONS
210210
the raw profile. When ``-profile-correlate=binary`` was used for
211211
instrumentation, use this option to correlate the raw profile.
212212

213+
.. option:: --debuginfod
214+
215+
Use debuginfod to find the associated executables that contain profile data and
216+
name sections for the raw profiles to correlate them.
217+
When -profile-correlate=binary was used for instrumentation, this option can be
218+
used for correlation.
219+
220+
.. option:: --debug-file-directory=<dir>
221+
222+
Use provided local directories to search for executables that contain profile
223+
data and name sections for the raw profiles to correlate them.
224+
When -profile-correlate=binary was used for instrumentation, this option can be
225+
used for correlation.
226+
227+
.. option:: --correlate=<kind>
228+
229+
Specify the correlation kind (debug_info or binary) to use when -debuginfod or
230+
-debug-file-directory=<dir> option is provided.
231+
213232
.. option:: --temporal-profile-trace-reservoir-size
214233

215234
The maximum number of temporal profile traces to be stored in the output

llvm/include/llvm/ProfileData/InstrProfCorrelator.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
1414

1515
#include "llvm/ADT/DenseSet.h"
16+
#include "llvm/Debuginfod/BuildIDFetcher.h"
17+
#include "llvm/Object/BuildID.h"
1618
#include "llvm/ProfileData/InstrProf.h"
1719
#include "llvm/Support/Error.h"
1820
#include "llvm/Support/MemoryBuffer.h"
@@ -36,7 +38,9 @@ class InstrProfCorrelator {
3638
enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY };
3739

3840
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
39-
get(StringRef Filename, ProfCorrelatorKind FileKind);
41+
get(StringRef Filename, ProfCorrelatorKind FileKind,
42+
const object::BuildIDFetcher *BIDFetcher = nullptr,
43+
const ArrayRef<llvm::object::BuildID> BIs = std::nullopt);
4044

4145
/// Construct a ProfileData vector used to correlate raw instrumentation data
4246
/// to their functions.

llvm/include/llvm/ProfileData/InstrProfReader.h

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,21 @@ class InstrProfReader {
197197

198198
/// Factory method to create an appropriately typed reader for the given
199199
/// instrprof file.
200-
static Expected<std::unique_ptr<InstrProfReader>>
201-
create(const Twine &Path, vfs::FileSystem &FS,
202-
const InstrProfCorrelator *Correlator = nullptr,
203-
std::function<void(Error)> Warn = nullptr);
204-
205-
static Expected<std::unique_ptr<InstrProfReader>>
206-
create(std::unique_ptr<MemoryBuffer> Buffer,
207-
const InstrProfCorrelator *Correlator = nullptr,
208-
std::function<void(Error)> Warn = nullptr);
200+
static Expected<std::unique_ptr<InstrProfReader>> create(
201+
const Twine &Path, vfs::FileSystem &FS,
202+
const InstrProfCorrelator *Correlator = nullptr,
203+
const object::BuildIDFetcher *BIDFetcher = nullptr,
204+
const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
205+
InstrProfCorrelator::ProfCorrelatorKind::NONE,
206+
std::function<void(Error)> Warn = nullptr);
207+
208+
static Expected<std::unique_ptr<InstrProfReader>> create(
209+
std::unique_ptr<MemoryBuffer> Buffer,
210+
const InstrProfCorrelator *Correlator = nullptr,
211+
const object::BuildIDFetcher *BIDFetcher = nullptr,
212+
const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
213+
InstrProfCorrelator::ProfCorrelatorKind::NONE,
214+
std::function<void(Error)> Warn = nullptr);
209215

210216
/// \param Weight for raw profiles use this as the temporal profile trace
211217
/// weight
@@ -314,6 +320,14 @@ class RawInstrProfReader : public InstrProfReader {
314320
/// If available, this hold the ProfileData array used to correlate raw
315321
/// instrumentation data to their functions.
316322
const InstrProfCorrelatorImpl<IntPtrT> *Correlator;
323+
/// Fetches debuginfo by build id to correlate profiles.
324+
const object::BuildIDFetcher *BIDFetcher;
325+
/// Correlates profiles with build id fetcher by fetching debuginfo with build
326+
/// ID.
327+
std::unique_ptr<InstrProfCorrelator> BIDFetcherCorrelator;
328+
/// Indicates if should use debuginfo or binary to correlate with build id
329+
/// fetcher.
330+
InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind;
317331
/// A list of timestamps paired with a function name reference.
318332
std::vector<std::pair<uint64_t, uint64_t>> TemporalProfTimestamps;
319333
bool ShouldSwapBytes;
@@ -349,13 +363,18 @@ class RawInstrProfReader : public InstrProfReader {
349363
static const uint64_t MaxCounterValue = (1ULL << 56);
350364

351365
public:
352-
RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer,
353-
const InstrProfCorrelator *Correlator,
354-
std::function<void(Error)> Warn)
366+
RawInstrProfReader(
367+
std::unique_ptr<MemoryBuffer> DataBuffer,
368+
const InstrProfCorrelator *Correlator,
369+
const object::BuildIDFetcher *BIDFetcher,
370+
const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
371+
std::function<void(Error)> Warn)
355372
: DataBuffer(std::move(DataBuffer)),
356373
Correlator(dyn_cast_or_null<const InstrProfCorrelatorImpl<IntPtrT>>(
357374
Correlator)),
358-
Warn(Warn) {}
375+
BIDFetcher(BIDFetcher),
376+
BIDFetcherCorrelatorKind(BIDFetcherCorrelatorKind), Warn(Warn) {}
377+
359378
RawInstrProfReader(const RawInstrProfReader &) = delete;
360379
RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
361380

@@ -439,7 +458,7 @@ class RawInstrProfReader : public InstrProfReader {
439458

440459
void advanceData() {
441460
// `CountersDelta` is a constant zero when using debug info correlation.
442-
if (!Correlator) {
461+
if (!Correlator && !BIDFetcherCorrelator) {
443462
// The initial CountersDelta is the in-memory address difference between
444463
// the data and counts sections:
445464
// start(__llvm_prf_cnts) - start(__llvm_prf_data)

llvm/lib/ProfileData/InstrProfCorrelator.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,31 @@ InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
9191
}
9292

9393
llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
94-
InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
94+
InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
95+
const object::BuildIDFetcher *BIDFetcher,
96+
const ArrayRef<object::BuildID> BIs) {
97+
std::optional<std::string> Path;
98+
if (BIDFetcher) {
99+
if (BIs.empty())
100+
return make_error<InstrProfError>(
101+
instrprof_error::unable_to_correlate_profile,
102+
"unsupported profile binary correlation when there is no build ID "
103+
"in a profile");
104+
if (BIs.size() > 1)
105+
return make_error<InstrProfError>(
106+
instrprof_error::unable_to_correlate_profile,
107+
"unsupported profile binary correlation when there are multiple "
108+
"build IDs in a profile");
109+
110+
Path = BIDFetcher->fetch(BIs.front());
111+
if (!Path)
112+
return make_error<InstrProfError>(
113+
instrprof_error::unable_to_correlate_profile,
114+
"Missing build ID: " + llvm::toHex(BIs.front(),
115+
/*LowerCase=*/true));
116+
Filename = *Path;
117+
}
118+
95119
if (FileKind == DEBUG_INFO) {
96120
auto DsymObjectsOrErr =
97121
object::MachOObjectFile::findDsymObjectMembers(Filename);

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,22 +150,25 @@ static void printBinaryIdsInternal(raw_ostream &OS,
150150
}
151151
}
152152

153-
Expected<std::unique_ptr<InstrProfReader>>
154-
InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
155-
const InstrProfCorrelator *Correlator,
156-
std::function<void(Error)> Warn) {
153+
Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
154+
const Twine &Path, vfs::FileSystem &FS,
155+
const InstrProfCorrelator *Correlator,
156+
const object::BuildIDFetcher *BIDFetcher,
157+
const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
158+
std::function<void(Error)> Warn) {
157159
// Set up the buffer to read.
158160
auto BufferOrError = setupMemoryBuffer(Path, FS);
159161
if (Error E = BufferOrError.takeError())
160162
return std::move(E);
161163
return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
162-
Warn);
164+
BIDFetcher, BIDFetcherCorrelatorKind, Warn);
163165
}
164166

165-
Expected<std::unique_ptr<InstrProfReader>>
166-
InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
167-
const InstrProfCorrelator *Correlator,
168-
std::function<void(Error)> Warn) {
167+
Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
168+
std::unique_ptr<MemoryBuffer> Buffer, const InstrProfCorrelator *Correlator,
169+
const object::BuildIDFetcher *BIDFetcher,
170+
const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
171+
std::function<void(Error)> Warn) {
169172
if (Buffer->getBufferSize() == 0)
170173
return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
171174

@@ -174,9 +177,13 @@ InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
174177
if (IndexedInstrProfReader::hasFormat(*Buffer))
175178
Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
176179
else if (RawInstrProfReader64::hasFormat(*Buffer))
177-
Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
180+
Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator,
181+
BIDFetcher, BIDFetcherCorrelatorKind,
182+
Warn));
178183
else if (RawInstrProfReader32::hasFormat(*Buffer))
179-
Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
184+
Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator,
185+
BIDFetcher, BIDFetcherCorrelatorKind,
186+
Warn));
180187
else if (TextInstrProfReader::hasFormat(*Buffer))
181188
Result.reset(new TextInstrProfReader(std::move(Buffer)));
182189
else
@@ -633,6 +640,19 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
633640
if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
634641
return error(instrprof_error::bad_header);
635642

643+
if (BIDFetcher) {
644+
std::vector<object::BuildID> BinaryIDs;
645+
if (Error E = readBinaryIds(BinaryIDs))
646+
return E;
647+
if (auto E = InstrProfCorrelator::get("", BIDFetcherCorrelatorKind,
648+
BIDFetcher, BinaryIDs)
649+
.moveInto(BIDFetcherCorrelator)) {
650+
return E;
651+
}
652+
if (auto Err = BIDFetcherCorrelator->correlateProfileData(0))
653+
return Err;
654+
}
655+
636656
if (Correlator) {
637657
// These sizes in the raw file are zero because we constructed them in the
638658
// Correlator.
@@ -643,6 +663,14 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
643663
DataEnd = Data + Correlator->getDataSize();
644664
NamesStart = Correlator->getNamesPointer();
645665
NamesEnd = NamesStart + Correlator->getNamesSize();
666+
} else if (BIDFetcherCorrelator) {
667+
InstrProfCorrelatorImpl<IntPtrT> *BIDFetcherCorrelatorImpl =
668+
dyn_cast_or_null<InstrProfCorrelatorImpl<IntPtrT>>(
669+
BIDFetcherCorrelator.get());
670+
Data = BIDFetcherCorrelatorImpl->getDataPointer();
671+
DataEnd = Data + BIDFetcherCorrelatorImpl->getDataSize();
672+
NamesStart = BIDFetcherCorrelatorImpl->getNamesPointer();
673+
NamesEnd = NamesStart + BIDFetcherCorrelatorImpl->getNamesSize();
646674
} else {
647675
Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
648676
Start + DataOffset);

llvm/tools/llvm-profdata/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ add_llvm_tool(llvm-profdata
1212
intrinsics_gen
1313
GENERATE_DRIVER
1414
)
15+
16+
if(NOT LLVM_TOOL_LLVM_DRIVER_BUILD)
17+
target_link_libraries(llvm-profdata PRIVATE LLVMDebuginfod)
18+
endif()

0 commit comments

Comments
 (0)