This is an archive of the discontinued LLVM Phabricator instance.

[Profile] Allow online merging with debug info correlation.
ClosedPublic

Authored by zequanwu on Aug 10 2023, 9:22 AM.

Details

Summary

When using debug info correlation, value profiling needs to be switched off.
So, we are only merging counter sections. In that case the existance of data
section is just used to provide an extra check in case of corrupted profile.

This patch performs counter merging by iterating the counter section by counter
size and add them together.

Diff Detail

Event Timeline

zequanwu created this revision.Aug 10 2023, 9:22 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 10 2023, 9:22 AM
Herald added subscribers: Enna1, ormris. · View Herald Transcript
zequanwu requested review of this revision.Aug 10 2023, 9:22 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptAug 10 2023, 9:22 AM
Herald added subscribers: Restricted Project, cfe-commits. · View Herald Transcript
zequanwu updated this revision to Diff 549077.Aug 10 2023, 9:24 AM

Remove debug includes.

ellis added a comment.Aug 10 2023, 3:21 PM

Thanks for working on this!

compiler-rt/lib/profile/InstrProfilingMerge.c
105–107

I just realized that I need to throw an error here for temporal profiles since online merging won't work for that case.

131

Since we don't have the data section, we need to be confident that existing profile comes from the same binary (so that the counter section is identical). Can we add some extra checks here? I'm thinking we can verify that some fields in the headers match and that the variant flags are identical.

136–138

Can you add a check to make sure src and dst have the same number of counters (SrcCountersEnd - SrcCountersStart)?

compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
26

We need to run this line twice to correctly test __llvm_profile_merge_from_buffer()

compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
35

I know this is outside the scope of this patch, but I don't think simply llvm-profdata show is sufficient to compare profiles. I'll try to fix this.

ellis added a comment.Aug 10 2023, 4:51 PM

I've just published https://reviews.llvm.org/D157664, so you'll want to rebase ontop of it if it lands soon. I would also like to see some more tests added to instrprof-merge-error.c to make sure two different binaries can't merge profiles together with --debug-info-correlate. I was thinking the test would be something like this.

// RUN: %clang_pgogen -o %t/a -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %t/main.c
// RUN: %clang_pgogen -o %t/b -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %t/main.c %t/foo.c
// RUN: env LLVM_PROFILE_FILE=%t/default_%m.profdata %run %t/a
// This next line should fail to merge because the counter sections have different sizes
// RUN: env LLVM_PROFILE_FILE=%t/default_%m.profdata %run %t/b

//--- main.c
int main() { return 0; }
//--- foo.c
int foo() { return 4; }
zequanwu updated this revision to Diff 549424.Aug 11 2023, 8:43 AM
zequanwu marked 3 inline comments as done.

Address comments.

compiler-rt/lib/profile/InstrProfilingMerge.c
131

The comment says the caller of this function is responsible for the check. And we verifies that fields in both headers math before merging at doProfileMerging.

136–138

Added the check at __llvm_profile_check_compatibility.

I use in-memory __llvm_profile_counter_entry_size() to calculate in-file SrcCountersEnd, because the header only tells number of counters.

compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
26

Added.

I've just published https://reviews.llvm.org/D157664, so you'll want to rebase ontop of it if it lands soon. I would also like to see some more tests added to instrprof-merge-error.c to make sure two different binaries can't merge profiles together with --debug-info-correlate. I was thinking the test would be something like this.

// RUN: %clang_pgogen -o %t/a -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %t/main.c
// RUN: %clang_pgogen -o %t/b -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %t/main.c %t/foo.c
// RUN: env LLVM_PROFILE_FILE=%t/default_%m.profdata %run %t/a
// This next line should fail to merge because the counter sections have different sizes
// RUN: env LLVM_PROFILE_FILE=%t/default_%m.profdata %run %t/b

//--- main.c
int main() { return 0; }
//--- foo.c
int foo() { return 4; }

In this example, %m will translated to two different values so they won't be merged. As I mentioned in the inline comment, __llvm_profile_check_compatibility will verify that for us.

BTW, I noticed something strange with -pgo-function-entry-coverage when merging via llvm-profdata.
In this file compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c, I ran the following:

// RUN: %clang_pgogen -o %t.cov.normal -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: rm -rf %t.dir && mkdir %t.dir
// RUN: env LLVM_PROFILE_FILE=%t.dir/%m.profraw %run %t.cov.normal
// RUN: env LLVM_PROFILE_FILE=%t.dir/%m.profraw %run %t.cov.normal
// RUN: llvm-profdata merge -o %t.cov.normal.profdata %t.dir/
// RUN: llvm-profdata show --all-functions --counts %t.cov.normal.profdata
// It shows block counts 1.
Counters:
  main:
    Hash: 0x06d15c67b2c35b9c
    Counters: 1
    Block counts: [1]
  _Z3fooi:
    Hash: 0x0209aa3e3852da94
    Counters: 1
    Block counts: [1]
  _Z3bari:
    Hash: 0x0209aa3e1d398548
    Counters: 1
    Block counts: [1]
  _Z6unusedi:
    Hash: 0x0a4d0ad3efffffff
    Counters: 1
    Block counts: [0]
Instrumentation level: IR  entry_first = 0
Functions shown: 4
Total functions: 4
Maximum function count: 1
Maximum internal block count: 0

// RUN: rm -rf %t.dir && mkdir %t.dir
// RUN: env LLVM_PROFILE_FILE=%t.dir/%t.cov-1.profraw %run %t.cov.normal
// RUN: env LLVM_PROFILE_FILE=%t.dir/%t.cov-2.profraw %run %t.cov.normal
// RUN: llvm-profdata merge -o %t.cov.normal.profdata %t.dir/
// RUN: llvm-profdata show --all-functions --counts %t.cov.normal.profdata
// It shows block counts 2, as opposed to 1.
Counters:
  main:
    Hash: 0x06d15c67b2c35b9c
    Counters: 1
    Block counts: [2]
  _Z3fooi:
    Hash: 0x0209aa3e3852da94
    Counters: 1
    Block counts: [2]
  _Z3bari:
    Hash: 0x0209aa3e1d398548
    Counters: 1
    Block counts: [2]
  _Z6unusedi:
    Hash: 0x0a4d0ad3efffffff
    Counters: 1
    Block counts: [0]
Instrumentation level: IR  entry_first = 0
Functions shown: 4
Total functions: 4
Maximum function count: 2
Maximum internal block count: 0

BTW, I noticed something strange with -pgo-function-entry-coverage when merging via llvm-profdata.

This is intentional. The two raw profiles individually store blocks as either covered or not, but when we merge them they get converted to counters and accumulated.
https://github.com/llvm/llvm-project/blob/6a0feb1503e21432e63d93b44357bad43f8026d1/llvm/lib/ProfileData/InstrProf.cpp#L726
Then in PGOUseFunc::populateCoverage() we annotate blocks as alive if their counter value is non-zero.
https://github.com/llvm/llvm-project/blob/1aee2434ce4c9b5785cbc8f72cbbbd64f9e85297/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp#L1399
My logic was that the indexed profile represents these counters as ints, so we might as well accumulate them. Also, this makes the implementation simpler.

BTW, I noticed something strange with -pgo-function-entry-coverage when merging via llvm-profdata.

This is intentional. The two raw profiles individually store blocks as either covered or not, but when we merge them they get converted to counters and accumulated.
https://github.com/llvm/llvm-project/blob/6a0feb1503e21432e63d93b44357bad43f8026d1/llvm/lib/ProfileData/InstrProf.cpp#L726
Then in PGOUseFunc::populateCoverage() we annotate blocks as alive if their counter value is non-zero.
https://github.com/llvm/llvm-project/blob/1aee2434ce4c9b5785cbc8f72cbbbd64f9e85297/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp#L1399
My logic was that the indexed profile represents these counters as ints, so we might as well accumulate them. Also, this makes the implementation simpler.

Thanks for explanation. That makes sense.

ellis added inline comments.Aug 14 2023, 10:57 AM
compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
24

Let's move this line down since we don't use it until line 31.

30

This looks to be the same as line 2. Lets just reuse that executable.

39

Same here. This is the same as line 12. (And I believe these comments also apply to the Linux test)

zequanwu updated this revision to Diff 550039.Aug 14 2023, 11:37 AM
zequanwu marked 3 inline comments as done.

Rebase and address comments.

ellis accepted this revision.Aug 14 2023, 11:48 AM
This revision is now accepted and ready to land.Aug 14 2023, 11:48 AM
MaskRay accepted this revision.Aug 14 2023, 11:50 AM
This revision was landed with ongoing or failed builds.Aug 14 2023, 12:15 PM
This revision was automatically updated to reflect the committed changes.
aeubanks added inline comments.
compiler-rt/lib/profile/InstrProfilingMerge.c
133

we're running into this error message even though we don't have debug info correlation turned on, is that expected in some configurations? I'm still trying to understand how we could end up in this code path without debug info correlation

https://crbug.com/1473935

aeubanks added inline comments.Aug 21 2023, 5:06 PM
compiler-rt/lib/profile/InstrProfilingMerge.c
133

also it seems like this code path isn't tested?

ellis added inline comments.Aug 22 2023, 10:44 AM
compiler-rt/lib/profile/InstrProfilingMerge.c
133

It's very strange that you are hitting this code path because I didn't think it was possible. Were you ever able to reproduce locally?

aeubanks added inline comments.Aug 22 2023, 10:52 AM
compiler-rt/lib/profile/InstrProfilingMerge.c
133

no, it's only showed up on some bots (both mac and linux), I'm still trying to understand what's going on

aeubanks added inline comments.Aug 22 2023, 2:21 PM
compiler-rt/lib/profile/InstrProfilingMerge.c
133

managed to repro having no DataSize (NumData now).

$ cat /tmp/a.cc
int main() {}
$ cat /tmp/funlist
[clang]
default:skip
$ clang++ -O1 -fprofile-instr-generate -fcoverage-mapping -o /tmp/a -fuse-ld=lld /tmp/z.cc -fprofile-list=/tmp/funlist
$ export LLVM_PROFILE_FILE='a%m.profraw'
$ /tmp/a
$ /tmp/a
LLVM Profile Error: Missing profile data section.
LLVM Profile Error: Invalid profile data to merge
LLVM Profile Error: Profile Merging of file a18405209413954990729_0.profraw failed: Success
LLVM Profile Error: Failed to write file "a18405209413954990729_0.profraw": Success

basically if nothing is instrumented we'll hit this

will revert

This revision is now accepted and ready to land.Aug 22 2023, 2:37 PM