Skip to content

Commit 11d3074

Browse files
committed
[InstrProf] Add single byte coverage mode
Use the llvm flag `-pgo-function-entry-coverage` to create single byte "counters" to track functions coverage. This mode has significantly less size overhead in both code and data because * We mark a function as "covered" with a store instead of an increment which generally requires fewer assembly instructions * We use a single byte per function rather than 8 bytes per block The trade off of course is that this mode only tells you if a function has been covered. This is useful, for example, to detect dead code. When combined with debug info correlation [0] we are able to create an instrumented Clang binary that is only 150M (the vanilla Clang binary is 143M). That is an overhead of 7M (4.9%) compared to the default instrumentation (without value profiling) which has an overhead of 31M (21.7%). [0] https://groups.google.com/g/llvm-dev/c/r03Z6JoN7d4 Reviewed By: kyulee Differential Revision: https://reviews.llvm.org/D116180
1 parent 936f247 commit 11d3074

31 files changed

+530
-71
lines changed

compiler-rt/include/profile/InstrProfData.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,17 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
660660
* generated profile, and 0 if this is a Clang FE generated profile.
661661
* 1 in bit 57 indicates there are context-sensitive records in the profile.
662662
* The 59th bit indicates whether to use debug info to correlate profiles.
663+
* The 60th bit indicates single byte coverage instrumentation.
664+
* The 61st bit indicates function entry instrumentation only.
663665
*/
664666
#define VARIANT_MASKS_ALL 0xff00000000000000ULL
665667
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
666668
#define VARIANT_MASK_IR_PROF (0x1ULL << 56)
667669
#define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
668670
#define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)
669671
#define VARIANT_MASK_DBG_CORRELATE (0x1ULL << 59)
672+
#define VARIANT_MASK_BYTE_COVERAGE (0x1ULL << 60)
673+
#define VARIANT_MASK_FUNCTION_ENTRY_ONLY (0x1ULL << 61)
670674
#define INSTR_PROF_RAW_VERSION_VAR __llvm_profile_raw_version
671675
#define INSTR_PROF_PROFILE_RUNTIME_VAR __llvm_profile_runtime
672676
#define INSTR_PROF_PROFILE_COUNTER_BIAS_VAR __llvm_profile_counter_bias

compiler-rt/lib/profile/InstrProfiling.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
4545
char *I = __llvm_profile_begin_counters();
4646
char *E = __llvm_profile_end_counters();
4747

48-
memset(I, 0, E - I);
48+
char ResetValue =
49+
(__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) ? 0xFF : 0;
50+
memset(I, ResetValue, E - I);
4951

5052
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
5153
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();

compiler-rt/lib/profile/InstrProfilingBuffer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
6565
}
6666

6767
COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
68+
if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
69+
return sizeof(uint8_t);
6870
return sizeof(uint64_t);
6971
}
7072

compiler-rt/lib/profile/InstrProfilingMerge.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,14 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
155155
if (SrcCounters < SrcCountersStart || SrcCounters >= SrcNameStart ||
156156
(SrcCounters + __llvm_profile_counter_entry_size() * NC) > SrcNameStart)
157157
return 1;
158-
for (unsigned I = 0; I < NC; I++)
159-
((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I];
158+
for (unsigned I = 0; I < NC; I++) {
159+
if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) {
160+
// A value of zero signifies the function is covered.
161+
DstCounters[I] &= SrcCounters[I];
162+
} else {
163+
((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I];
164+
}
165+
}
160166

161167
/* Now merge value profile data. */
162168
if (!VPMergeHook)

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@
88
// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
99

1010
// RUN: diff %t.normal.profdata %t.profdata
11+
12+
// 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
13+
// RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov
14+
// RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov.dSYM %t.cov.proflite
15+
16+
// 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
17+
// RUN: env LLVM_PROFILE_FILE=%t.cov.profraw %run %t.cov.normal
18+
// RUN: llvm-profdata merge -o %t.cov.normal.profdata %t.cov.profraw
19+
20+
// RUN: diff %t.cov.normal.profdata %t.cov.profdata

compiler-rt/test/profile/Inputs/instrprof-debug-info-correlate-bar.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
int foo(int);
2+
int unused(int);
23

34
inline int bar(int a) {
45
while (a > 100)

compiler-rt/test/profile/Inputs/instrprof-debug-info-correlate-foo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ int foo(int a) {
55
return 4 * a + 1;
66
return bar(a);
77
}
8+
9+
int unused(int a) { return a * a; }

compiler-rt/test/profile/Inputs/instrprof-debug-info-correlate-main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include "instrprof-debug-info-correlate-bar.h"
22

33
typedef int (*FP)(int);
4-
FP Fps[2] = {foo, bar};
4+
FP Fps[3] = {foo, bar, unused};
55

66
int main() {
77
for (int i = 0; i < 5; i++)

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,13 @@
1414
// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite
1515

1616
// RUN: diff %t.normal.profdata %t.profdata
17+
18+
// 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
19+
// RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov
20+
// RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov %t.cov.proflite
21+
22+
// 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
23+
// RUN: env LLVM_PROFILE_FILE=%t.cov.profraw %run %t.cov.normal
24+
// RUN: llvm-profdata merge -o %t.cov.normal.profdata %t.cov.profraw
25+
26+
// RUN: diff %t.cov.normal.profdata %t.cov.profdata
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_pgogen -mllvm -pgo-function-entry-coverage %s -o %t.out
2+
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.out
3+
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
4+
// RUN: llvm-profdata show --covered %t.profdata | FileCheck %s --check-prefix CHECK --implicit-check-not goo
5+
6+
int foo(int i) { return 4 * i + 1; }
7+
int bar(int i) { return 4 * i + 2; }
8+
int goo(int i) { return 4 * i + 3; }
9+
10+
int main(int argc, char *argv[]) {
11+
foo(5);
12+
argc ? bar(6) : goo(7);
13+
return 0;
14+
}
15+
16+
// CHECK: main
17+
// CHECK: foo
18+
// CHECK: bar

0 commit comments

Comments
 (0)