Skip to content

[InstrFDO][TypeProf] Implement binary instrumentation and profile read/write #66825

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

Merged
merged 44 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
361f8f6
[IRPGO][ValueProfile] Instrument virtual table address that could be …
mingmingl-llvm Sep 17, 2023
cb0246f
Address feebacks on the code. Questions will be followed up shortly.
mingmingl-llvm Sep 29, 2023
3c6ca04
In InstrProf.cpp, add option -enable-vtable-type-profiling to flag co…
mingmingl-llvm Oct 2, 2023
3780bd9
A few fixes:
mingmingl-llvm Oct 2, 2023
9255867
resolve feedbacks on code
mingmingl-llvm Oct 4, 2023
8d8a45a
Rebase onto main (a fresh commit on Oct27) and add the following changes
mingmingl-llvm Oct 28, 2023
82fac8e
address feedback
mingmingl-llvm Nov 1, 2023
d54d059
small changes:
mingmingl-llvm Nov 1, 2023
ebf4c1d
pick up upstream change; sync main branch with upstream and 'git merg…
mingmingl-llvm Nov 7, 2023
52143e9
update clang-format version to 117.0.4 released binary and run clang-…
mingmingl-llvm Nov 7, 2023
2350d7f
The changes:
mingmingl-llvm Nov 7, 2023
af34929
Update main branch of my llvm fork. Run 'git merge main' and resolve …
mingmingl-llvm Nov 9, 2023
fcf92af
resolve feedback
mingmingl-llvm Nov 13, 2023
f5d12b5
merge upstream main changes and resolve conflict
mingmingl-llvm Nov 16, 2023
17d941c
Merge branch 'main' into vtable
mingmingl-llvm Nov 16, 2023
c000e64
run clang-format over modified files
mingmingl-llvm Nov 16, 2023
5b09e43
merge main branch changes
mingmingl-llvm Nov 25, 2023
313eb10
undo clang-format on unchanged lines
mingmingl-llvm Nov 26, 2023
abcbc6d
Changes:
mingmingl-llvm Dec 3, 2023
8c725ef
fix three test failures related with zlib usage
mingmingl-llvm Dec 6, 2023
1050a6b
apply git-format change
mingmingl-llvm Dec 11, 2023
9f01a30
run 'git merge main', resolve conflicts and run clang-format on the diff
mingmingl-llvm Dec 14, 2023
a9deaec
Polish tests
mingmingl-llvm Dec 14, 2023
66efde8
In raw profile reader, read multi-byte data using 'swap'. The 'swap' …
mingmingl-llvm Dec 30, 2023
9ec0784
undo git-formatted lines and follow existing style
mingmingl-llvm Jan 2, 2024
0d9abe5
run 'git merge main'
mingmingl-llvm Jan 2, 2024
8240524
one-liner fix for tools/llvm-profdata/raw-64-bits-le.test
mingmingl-llvm Jan 2, 2024
60cd296
fix two test failures. They are overlooked when running 'git merge main'
mingmingl-llvm Jan 2, 2024
a7633ad
run 'git merge main'
mingmingl-llvm Feb 27, 2024
a61c8a4
A few changes after 'git merge main':
mingmingl-llvm Feb 27, 2024
4dbe23e
Changes
mingmingl-llvm Feb 28, 2024
000d818
apply clang-format change
mingmingl-llvm Feb 28, 2024
c57422b
simple clean-ups
mingmingl-llvm Mar 2, 2024
df6eadf
For helper function needsComdatForCounter, limit the first parameter …
mingmingl-llvm Mar 3, 2024
c30888c
Merge branch 'main' into vtable
mingmingl-llvm Mar 4, 2024
4a9e6c9
unify 'maybeSetComdat'
mingmingl-llvm Mar 4, 2024
61e8292
resolve review feedback
mingmingl-llvm Mar 6, 2024
fc1d2be
resolve comment
mingmingl-llvm Mar 26, 2024
d8967d2
merge main branch and resolve conflicts
mingmingl-llvm Mar 26, 2024
27239f0
Merge branch 'main' into vtable
mingmingl-llvm Mar 28, 2024
0158523
Changes:
mingmingl-llvm Mar 28, 2024
2abdfe3
remove InstrProfSymtab::getGlobalVariable method; it's not used in th…
mingmingl-llvm Mar 28, 2024
7ea9217
resolve comments
mingmingl-llvm Mar 29, 2024
0a0c364
Changes:
mingmingl-llvm Mar 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions compiler-rt/test/profile/Linux/instrprof-vtable-value-prof.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// REQUIRES: lld-available

// RUN: %clangxx_pgogen -fuse-ld=lld -O2 -g -fprofile-generate=. -mllvm -enable-vtable-value-profiling %s -o %t-test
// RUN: env LLVM_PROFILE_FILE=%t-test.profraw %t-test

// Show vtable profiles from raw profile.
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-test.profraw | FileCheck %s --check-prefixes=COMMON,RAW

// Generate indexed profile from raw profile and show the data.
// RUN: llvm-profdata merge %t-test.profraw -o %t-test.profdata
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-test.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED

// Generate text profile from raw and indexed profiles respectively and show the data.
// RUN: llvm-profdata merge --text %t-test.profraw -o %t-raw.proftext
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text %t-raw.proftext | FileCheck %s --check-prefix=ICTEXT
// RUN: llvm-profdata merge --text %t-test.profdata -o %t-indexed.proftext
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text %t-indexed.proftext | FileCheck %s --check-prefix=ICTEXT

// Generate indexed profile from text profiles and show the data
// RUN: llvm-profdata merge --binary %t-raw.proftext -o %t-text.profraw
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-text.profraw | FileCheck %s --check-prefixes=COMMON,INDEXED
// RUN: llvm-profdata merge --binary %t-indexed.proftext -o %t-text.profdata
// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-text.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED

// COMMON: Counters:
// COMMON-NEXT: main:
// COMMON-NEXT: Hash: 0x0f9a16fe6d398548
// COMMON-NEXT: Counters: 2
// COMMON-NEXT: Indirect Call Site Count: 2
// COMMON-NEXT: Number of instrumented vtables: 2
// RAW: Indirect Target Results:
// RAW-NEXT: [ 0, _ZN8Derived15func1Eii, 250 ] (25.00%)
// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii, 750 ] (75.00%)
// RAW-NEXT: [ 1, _ZN8Derived15func2Eii, 250 ] (25.00%)
// RAW-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii, 750 ] (75.00%)
// RAW-NEXT: VTable Results:
// RAW-NEXT: [ 0, _ZTV8Derived1, 250 ] (25.00%)
// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%)
// RAW-NEXT: [ 1, _ZTV8Derived1, 250 ] (25.00%)
// RAW-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%)
// INDEXED: Indirect Target Results:
// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii, 750 ] (75.00%)
// INDEXED-NEXT: [ 0, _ZN8Derived15func1Eii, 250 ] (25.00%)
// INDEXED-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii, 750 ] (75.00%)
// INDEXED-NEXT: [ 1, _ZN8Derived15func2Eii, 250 ] (25.00%)
// INDEXED-NEXT: VTable Results:
// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%)
// INDEXED-NEXT: [ 0, _ZTV8Derived1, 250 ] (25.00%)
// INDEXED-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%)
// INDEXED-NEXT: [ 1, _ZTV8Derived1, 250 ] (25.00%)
// COMMON: Instrumentation level: IR entry_first = 0
// COMMON-NEXT: Functions shown: 1
// COMMON-NEXT: Total functions: 6
// COMMON-NEXT: Maximum function count: 1000
// COMMON-NEXT: Maximum internal block count: 250
// COMMON-NEXT: Statistics for indirect call sites profile:
// COMMON-NEXT: Total number of sites: 2
// COMMON-NEXT: Total number of sites with values: 2
// COMMON-NEXT: Total number of profiled values: 4
// COMMON-NEXT: Value sites histogram:
// COMMON-NEXT: NumTargets, SiteCount
// COMMON-NEXT: 2, 2
// COMMON-NEXT: Statistics for vtable profile:
// COMMON-NEXT: Total number of sites: 2
// COMMON-NEXT: Total number of sites with values: 2
// COMMON-NEXT: Total number of profiled values: 4
// COMMON-NEXT: Value sites histogram:
// COMMON-NEXT: NumTargets, SiteCount
// COMMON-NEXT: 2, 2

// ICTEXT: :ir
// ICTEXT: main
// ICTEXT: # Func Hash:
// ICTEXT: 1124236338992350536
// ICTEXT: # Num Counters:
// ICTEXT: 2
// ICTEXT: # Counter Values:
// ICTEXT: 1000
// ICTEXT: 1
// ICTEXT: # Num Value Kinds:
// ICTEXT: 2
// ICTEXT: # ValueKind = IPVK_IndirectCallTarget:
// ICTEXT: 0
// ICTEXT: # NumValueSites:
// ICTEXT: 2
// ICTEXT: 2
// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii:750
// ICTEXT: _ZN8Derived15func1Eii:250
// ICTEXT: 2
// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii:750
// ICTEXT: _ZN8Derived15func2Eii:250
// ICTEXT: # ValueKind = IPVK_VTableTarget:
// ICTEXT: 2
// ICTEXT: # NumValueSites:
// ICTEXT: 2
// ICTEXT: 2
// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E:750
// ICTEXT: _ZTV8Derived1:250
// ICTEXT: 2
// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E:750
// ICTEXT: _ZTV8Derived1:250

#include <cstdio>
#include <cstdlib>
class Base {
public:
virtual int func1(int a, int b) = 0;
virtual int func2(int a, int b) = 0;
};
class Derived1 : public Base {
public:
int func1(int a, int b) override { return a + b; }

int func2(int a, int b) override { return a * b; }
};
namespace {
class Derived2 : public Base {
public:
int func1(int a, int b) override { return a - b; }

int func2(int a, int b) override { return a * (a - b); }
};
} // namespace
__attribute__((noinline)) Base *createType(int a) {
Base *base = nullptr;
if (a % 4 == 0)
base = new Derived1();
else
base = new Derived2();
return base;
}
int main(int argc, char **argv) {
int sum = 0;
for (int i = 0; i < 1000; i++) {
int a = rand();
int b = rand();
Base *ptr = createType(i);
sum += ptr->func1(a, b) + ptr->func2(b, a);
}
printf("sum is %d\n", sum);
return 0;
}
62 changes: 57 additions & 5 deletions llvm/include/llvm/Analysis/IndirectCallVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,75 @@
#include <vector>

namespace llvm {
// Visitor class that finds all indirect call.
// Visitor class that finds indirect calls or instructions that gives vtable
// value, depending on Type.
struct PGOIndirectCallVisitor : public InstVisitor<PGOIndirectCallVisitor> {
enum class InstructionType {
kIndirectCall = 0,
kVTableVal = 1,
};
std::vector<CallBase *> IndirectCalls;
PGOIndirectCallVisitor() = default;
std::vector<Instruction *> ProfiledAddresses;
PGOIndirectCallVisitor(InstructionType Type) : Type(Type) {}

void visitCallBase(CallBase &Call) {
if (Call.isIndirectCall())
if (!Call.isIndirectCall())
return;

if (Type == InstructionType::kIndirectCall) {
IndirectCalls.push_back(&Call);
return;
}

assert(Type == InstructionType::kVTableVal && "Control flow guaranteed");

LoadInst *LI = dyn_cast<LoadInst>(Call.getCalledOperand());
// The code pattern to look for
//
// %vtable = load ptr, ptr %b
// %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1
// %2 = load ptr, ptr %vfn
// %call = tail call i32 %2(ptr %b)
//
// %vtable is the vtable address value to profile, and
// %2 is the indirect call target address to profile.
if (LI != nullptr) {
Value *Ptr = LI->getPointerOperand();
Value *VTablePtr = Ptr->stripInBoundsConstantOffsets();
// This is a heuristic to find address feeding instructions.
// FIXME: Add support in the frontend so LLVM type intrinsics are
// emitted without LTO. This way, added intrinsics could filter
// non-vtable instructions and reduce instrumentation overhead.
// Since a non-vtable profiled address is not within the address
// range of vtable objects, it's stored as zero in indexed profiles.
// A pass that looks up symbol with an zero hash will (almost) always
// find nullptr and skip the actual transformation (e.g., comparison
// of symbols). So the performance overhead from non-vtable profiled
// address is negligible if exists at all. Comparing loaded address
// with symbol address guarantees correctness.
if (VTablePtr != nullptr && isa<Instruction>(VTablePtr))
ProfiledAddresses.push_back(cast<Instruction>(VTablePtr));
}
}

private:
InstructionType Type;
};

// Helper function that finds all indirect call sites.
inline std::vector<CallBase *> findIndirectCalls(Function &F) {
PGOIndirectCallVisitor ICV;
PGOIndirectCallVisitor ICV(
PGOIndirectCallVisitor::InstructionType::kIndirectCall);
ICV.visit(F);
return ICV.IndirectCalls;
}

inline std::vector<Instruction *> findVTableAddrs(Function &F) {
PGOIndirectCallVisitor ICV(
PGOIndirectCallVisitor::InstructionType::kVTableVal);
ICV.visit(F);
return ICV.ProfiledAddresses;
}

} // namespace llvm

#endif
Loading
Loading