[PGO] Don't reference functions unless value profiling is enabled
This reduces the size of chrome.dll.pdb built with optimizations,
coverage, and line table info from 4,690,210,816 to 2,181,128,192, which
makes it possible to fit under the 4GB limit.
This change can greatly reduce binary size in coverage builds, which do
not need value profiling. IR PGO builds are unaffected. There is a minor
behavior change for frontend PGO.
PGO and coverage both use InstrProfiling to create profile data with
counters. PGO records the address of each function in the __profd_
global. It is used later to map runtime function pointer values back to
source-level function names. Coverage does not appear to use this
information.
Recording the address of every function with code coverage drastically
increases code size. Consider this program:
void foo();
void bar();
inline void inlineMe(int x) {
if (x > 0)
foo();
else
bar();
}
int getVal();
int main() { inlineMe(getVal()); }
With code coverage, the InstrProfiling pass runs before inlining, and it
captures the address of inlineMe in the __profd_ global. This greatly
increases code size, because now the compiler can no longer delete
trivial code.
One downside to this approach is that users of frontend PGO must apply
the -mllvm -enable-value-profiling flag globally in TUs that enable PGO.
Otherwise, some inline virtual method addresses may not be recorded and
will not be able to be promoted. My assumption is that this mllvm flag
is not popular, and most frontend PGO users don't enable it.
Differential Revision: https://reviews.llvm.org/D102818
2021-05-14 05:43:22 +08:00
|
|
|
// RUN: %clang_profgen -mllvm -enable-value-profiling -O2 -o %t %s
|
2015-12-11 13:43:55 +08:00
|
|
|
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
|
|
|
|
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
|
2016-03-26 11:06:42 +08:00
|
|
|
// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata > %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-1 < %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-2 < %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-3 < %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-4 < %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-5 < %t.out
|
|
|
|
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-6 < %t.out
|
2015-12-11 13:43:55 +08:00
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
typedef struct __llvm_profile_data __llvm_profile_data;
|
|
|
|
const __llvm_profile_data *__llvm_profile_begin_data(void);
|
|
|
|
const __llvm_profile_data *__llvm_profile_end_data(void);
|
|
|
|
void __llvm_profile_set_num_value_sites(__llvm_profile_data *Data,
|
|
|
|
uint32_t ValueKind,
|
|
|
|
uint16_t NumValueSites);
|
|
|
|
__llvm_profile_data *
|
|
|
|
__llvm_profile_iterate_data(const __llvm_profile_data *Data);
|
|
|
|
void *__llvm_get_function_addr(const __llvm_profile_data *Data);
|
|
|
|
void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
|
|
|
|
uint32_t CounterIndex);
|
|
|
|
void callee1() {}
|
|
|
|
void callee2() {}
|
|
|
|
|
|
|
|
void caller_without_value_site1() {}
|
|
|
|
void caller_with_value_site_never_called1() {}
|
|
|
|
void caller_with_vp1() {}
|
|
|
|
void caller_with_value_site_never_called2() {}
|
|
|
|
void caller_without_value_site2() {}
|
|
|
|
void caller_with_vp2() {}
|
|
|
|
|
2016-04-14 04:02:07 +08:00
|
|
|
void (*callee1Ptr)();
|
|
|
|
void (*callee2Ptr)();
|
|
|
|
|
|
|
|
void __attribute__ ((noinline)) setFunctionPointers () {
|
|
|
|
callee1Ptr = callee1;
|
|
|
|
callee2Ptr = callee2;
|
|
|
|
}
|
|
|
|
|
2015-12-11 13:43:55 +08:00
|
|
|
int main(int argc, const char *argv[]) {
|
|
|
|
unsigned S, NS = 10, V;
|
|
|
|
const __llvm_profile_data *Data, *DataEnd;
|
|
|
|
|
2016-04-14 04:02:07 +08:00
|
|
|
setFunctionPointers();
|
2015-12-11 13:43:55 +08:00
|
|
|
Data = __llvm_profile_begin_data();
|
|
|
|
DataEnd = __llvm_profile_end_data();
|
|
|
|
for (; Data < DataEnd; Data = __llvm_profile_iterate_data(Data)) {
|
|
|
|
void *func = __llvm_get_function_addr(Data);
|
|
|
|
if (func == caller_without_value_site1 ||
|
|
|
|
func == caller_without_value_site2 ||
|
|
|
|
func == callee1 || func == callee2 || func == main)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
__llvm_profile_set_num_value_sites((__llvm_profile_data *)Data,
|
|
|
|
0 /*IPVK_IndirectCallTarget */, 10);
|
|
|
|
|
|
|
|
if (func == caller_with_value_site_never_called1 ||
|
|
|
|
func == caller_with_value_site_never_called2)
|
|
|
|
continue;
|
|
|
|
for (S = 0; S < NS; S++) {
|
|
|
|
unsigned C;
|
|
|
|
for (C = 0; C < S + 1; C++) {
|
2016-04-14 04:02:07 +08:00
|
|
|
__llvm_profile_instrument_target((uint64_t)callee1Ptr, (void *)Data, S);
|
2015-12-11 13:43:55 +08:00
|
|
|
if (C % 2 == 0)
|
2016-04-14 04:02:07 +08:00
|
|
|
__llvm_profile_instrument_target((uint64_t)callee2Ptr, (void *)Data, S);
|
2015-12-11 13:43:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 13:24:58 +08:00
|
|
|
// CHECK: Counters:
|
2016-03-26 11:06:42 +08:00
|
|
|
// CHECK-1-LABEL: caller_with_value_site_never_called2:
|
|
|
|
// CHECK-1-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-1-NEXT: Counters:
|
|
|
|
// CHECK-1-NEXT: Function count
|
|
|
|
// CHECK-1-NEXT: Indirect Call Site Count: 10
|
|
|
|
// CHECK-1-NEXT: Indirect Target Results:
|
|
|
|
// CHECK-2-LABEL: caller_with_vp2:
|
|
|
|
// CHECK-2-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-2-NEXT: Counters:
|
|
|
|
// CHECK-2-NEXT: Function count:
|
|
|
|
// CHECK-2-NEXT: Indirect Call Site Count: 10
|
|
|
|
// CHECK-2-NEXT: Indirect Target Results:
|
|
|
|
// CHECK-2-NEXT: [ 0, callee1, 1 ]
|
|
|
|
// CHECK-2-NEXT: [ 0, callee2, 1 ]
|
|
|
|
// CHECK-2-NEXT: [ 1, callee1, 2 ]
|
|
|
|
// CHECK-2-NEXT: [ 1, callee2, 1 ]
|
|
|
|
// CHECK-2-NEXT: [ 2, callee1, 3 ]
|
|
|
|
// CHECK-2-NEXT: [ 2, callee2, 2 ]
|
|
|
|
// CHECK-2-NEXT: [ 3, callee1, 4 ]
|
|
|
|
// CHECK-2-NEXT: [ 3, callee2, 2 ]
|
|
|
|
// CHECK-2-NEXT: [ 4, callee1, 5 ]
|
|
|
|
// CHECK-2-NEXT: [ 4, callee2, 3 ]
|
|
|
|
// CHECK-2-NEXT: [ 5, callee1, 6 ]
|
|
|
|
// CHECK-2-NEXT: [ 5, callee2, 3 ]
|
|
|
|
// CHECK-2-NEXT: [ 6, callee1, 7 ]
|
|
|
|
// CHECK-2-NEXT: [ 6, callee2, 4 ]
|
|
|
|
// CHECK-2-NEXT: [ 7, callee1, 8 ]
|
|
|
|
// CHECK-2-NEXT: [ 7, callee2, 4 ]
|
|
|
|
// CHECK-2-NEXT: [ 8, callee1, 9 ]
|
|
|
|
// CHECK-2-NEXT: [ 8, callee2, 5 ]
|
|
|
|
// CHECK-2-NEXT: [ 9, callee1, 10 ]
|
|
|
|
// CHECK-2-NEXT: [ 9, callee2, 5 ]
|
|
|
|
// CHECK-3-LABEL: caller_with_vp1:
|
|
|
|
// CHECK-3-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-3-NEXT: Counters:
|
|
|
|
// CHECK-3-NEXT: Function count
|
|
|
|
// CHECK-3-NEXT: Indirect Call Site Count: 10
|
|
|
|
// CHECK-3-NEXT: Indirect Target Results:
|
|
|
|
// CHECK-3-NEXT: [ 0, callee1, 1 ]
|
|
|
|
// CHECK-3-NEXT: [ 0, callee2, 1 ]
|
|
|
|
// CHECK-3-NEXT: [ 1, callee1, 2 ]
|
|
|
|
// CHECK-3-NEXT: [ 1, callee2, 1 ]
|
|
|
|
// CHECK-3-NEXT: [ 2, callee1, 3 ]
|
|
|
|
// CHECK-3-NEXT: [ 2, callee2, 2 ]
|
|
|
|
// CHECK-3-NEXT: [ 3, callee1, 4 ]
|
|
|
|
// CHECK-3-NEXT: [ 3, callee2, 2 ]
|
|
|
|
// CHECK-3-NEXT: [ 4, callee1, 5 ]
|
|
|
|
// CHECK-3-NEXT: [ 4, callee2, 3 ]
|
|
|
|
// CHECK-3-NEXT: [ 5, callee1, 6 ]
|
|
|
|
// CHECK-3-NEXT: [ 5, callee2, 3 ]
|
|
|
|
// CHECK-3-NEXT: [ 6, callee1, 7 ]
|
|
|
|
// CHECK-3-NEXT: [ 6, callee2, 4 ]
|
|
|
|
// CHECK-3-NEXT: [ 7, callee1, 8 ]
|
|
|
|
// CHECK-3-NEXT: [ 7, callee2, 4 ]
|
|
|
|
// CHECK-3-NEXT: [ 8, callee1, 9 ]
|
|
|
|
// CHECK-3-NEXT: [ 8, callee2, 5 ]
|
|
|
|
// CHECK-3-NEXT: [ 9, callee1, 10 ]
|
|
|
|
// CHECK-3-NEXT: [ 9, callee2, 5 ]
|
|
|
|
// CHECK-4-LABEL: caller_with_value_site_never_called1:
|
|
|
|
// CHECK-4-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-4-NEXT: Counters:
|
|
|
|
// CHECK-4-NEXT: Function count:
|
|
|
|
// CHECK-4-NEXT: Indirect Call Site Count: 10
|
|
|
|
// CHECK-4-NEXT: Indirect Target Results:
|
|
|
|
// CHECK-5-LABEL: caller_without_value_site2:
|
|
|
|
// CHECK-5-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-5-NEXT: Counters:
|
|
|
|
// CHECK-5-NEXT: Function count:
|
|
|
|
// CHECK-5-NEXT: Indirect Call Site Count: 0
|
|
|
|
// CHECK-5-NEXT: Indirect Target Results:
|
|
|
|
// CHECK-6-LABEL: caller_without_value_site1:
|
|
|
|
// CHECK-6-NEXT: Hash: 0x0000000000000000
|
|
|
|
// CHECK-6-NEXT: Counters:
|
|
|
|
// CHECK-6-NEXT: Function count:
|
|
|
|
// CHECK-6-NEXT: Indirect Call Site Count: 0
|
|
|
|
// CHECK-6-NEXT: Indirect Target Results:
|