forked from OSchip/llvm-project
[llvm-profgen] Read sample profiles for post-processing.
Sometimes we would like to run post-processing repeatedly on the original sample profile for tuning. In order to avoid regenerating the original profile from scratch every time, this change adds the support of reading in the original profile (called symbolized profile) and running the post-processor on it. Reviewed By: wenlei Differential Revision: https://reviews.llvm.org/D121655
This commit is contained in:
parent
10cda6e36c
commit
937924eb49
|
@ -0,0 +1,63 @@
|
||||||
|
; RUN: llvm-profgen --format=text --unsymbolized-profile=%S/Inputs/cold-profile-trimming.raw.prof --binary=%S/Inputs/inline-noprobe2.perfbin --output=%t1 --use-offset=0
|
||||||
|
; RUN: llvm-profgen --format=text --llvm-sample-profile=%t1 --binary=%S/Inputs/inline-noprobe2.perfbin --output=%t2 --trim-cold-profile=1 --profile-summary-cold-count=1000
|
||||||
|
; RUN: FileCheck %s --input-file %t2 --check-prefix=CHECK-TRIM
|
||||||
|
|
||||||
|
|
||||||
|
;CHECK-TRIM: partition_pivot_last:5187:7
|
||||||
|
;CHECK-TRIM: partition_pivot_first:3010:5
|
||||||
|
;CHECK-TRIM-NOT: quick_sort:903:25
|
||||||
|
;CHECK-TRIM-NOT: main:820:0
|
||||||
|
|
||||||
|
; original code:
|
||||||
|
; clang -O3 -g -fno-optimize-sibling-calls -fdebug-info-for-profiling qsort.c -o a.out
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void swap(int *a, int *b) {
|
||||||
|
int t = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int partition_pivot_last(int* array, int low, int high) {
|
||||||
|
int pivot = array[high];
|
||||||
|
int i = low - 1;
|
||||||
|
for (int j = low; j < high; j++)
|
||||||
|
if (array[j] < pivot)
|
||||||
|
swap(&array[++i], &array[j]);
|
||||||
|
swap(&array[i + 1], &array[high]);
|
||||||
|
return (i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int partition_pivot_first(int* array, int low, int high) {
|
||||||
|
int pivot = array[low];
|
||||||
|
int i = low + 1;
|
||||||
|
for (int j = low + 1; j <= high; j++)
|
||||||
|
if (array[j] < pivot) { if (j != i) swap(&array[i], &array[j]); i++;}
|
||||||
|
swap(&array[i - 1], &array[low]);
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quick_sort(int* array, int low, int high, int (*partition_func)(int *, int, int)) {
|
||||||
|
if (low < high) {
|
||||||
|
int pi = (*partition_func)(array, low, high);
|
||||||
|
quick_sort(array, low, pi - 1, partition_func);
|
||||||
|
quick_sort(array, pi + 1, high, partition_func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const int size = 200;
|
||||||
|
int sum = 0;
|
||||||
|
int *array = malloc(size * sizeof(int));
|
||||||
|
for(int i = 0; i < 100 * 1000; i++) {
|
||||||
|
for(int j = 0; j < size; j++)
|
||||||
|
array[j] = j % 10 ? rand() % size: j;
|
||||||
|
int (*fptr)(int *, int, int) = i % 3 ? partition_pivot_last : partition_pivot_first;
|
||||||
|
quick_sort(array, 0, size - 1, fptr);
|
||||||
|
sum += array[i % size];
|
||||||
|
}
|
||||||
|
printf("sum=%d\n", sum);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
; Test default llvm-profgen with preinline off
|
||||||
|
; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-noprobe.perfscript --binary=%S/Inputs/inline-cs-noprobe.perfbin --csspgo-preinliner=0 --gen-cs-nested-profile=0 --output=%t1
|
||||||
|
|
||||||
|
; Test llvm-profgen with preinliner on will merge not inlinable profile into base profile.
|
||||||
|
; RUN: llvm-profgen --format=text --llvm-sample-profile=%t1 --binary=%S/Inputs/inline-cs-noprobe.perfbin --csspgo-preinliner=1 --gen-cs-nested-profile=0 --sample-profile-hot-inline-threshold=3000 --sample-profile-cold-inline-threshold=45 --output=%t2
|
||||||
|
; RUN: FileCheck %s --input-file %t2 --check-prefix=CHECK-PREINL
|
||||||
|
|
||||||
|
; Test default llvm-profgen with preinline off
|
||||||
|
; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --csspgo-preinliner=0 --gen-cs-nested-profile=0 --output=%t3
|
||||||
|
|
||||||
|
; Test llvm-profgen with preinliner on will merge not inlinable profile into base profile.
|
||||||
|
; RUN: llvm-profgen --format=text --llvm-sample-profile=%t3 --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --csspgo-preinliner=1 --gen-cs-nested-profile=0 --sample-profile-hot-inline-threshold=3000 --sample-profile-cold-inline-threshold=45 --output=%t4
|
||||||
|
; RUN: FileCheck %s --input-file %t4 --check-prefix=CHECK-PREINL-PROBE
|
||||||
|
|
||||||
|
; CHECK-PREINL: [foo]:309:0
|
||||||
|
; CHECK-PREINL-NEXT: 2.1: 14
|
||||||
|
; CHECK-PREINL-NEXT: 3: 15
|
||||||
|
; CHECK-PREINL-NEXT: 3.1: 14 bar:14
|
||||||
|
; CHECK-PREINL-NEXT: 3.2: 1
|
||||||
|
; CHECK-PREINL-NEXT: 65526: 14
|
||||||
|
; CHECK-PREINL-NEXT: !Attributes: 1
|
||||||
|
; CHECK-PREINL-NEXT:[foo:3.1 @ bar]:84:0
|
||||||
|
; CHECK-PREINL-NEXT: 1: 14
|
||||||
|
; CHECK-PREINL-NEXT: !Attributes: 3
|
||||||
|
|
||||||
|
|
||||||
|
; CHECK-PREINL-PROBE: [foo]:74:0
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 1: 0
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 2: 15
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 3: 15
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 4: 14
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 5: 1
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 6: 15
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 7: 0
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 8: 14 bar:14
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 9: 0
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: !CFGChecksum: 563088904013236
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: !Attributes: 1
|
||||||
|
; CHECK-PREINL-PROBE-NEXT:[foo:8 @ bar]:28:14
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 1: 14
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: 4: 14
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: !CFGChecksum: 72617220756
|
||||||
|
; CHECK-PREINL-PROBE-NEXT: !Attributes: 3
|
|
@ -7,12 +7,14 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
#include "ProfileGenerator.h"
|
#include "ProfileGenerator.h"
|
||||||
#include "ErrorHandling.h"
|
#include "ErrorHandling.h"
|
||||||
|
#include "PerfReader.h"
|
||||||
#include "ProfiledBinary.h"
|
#include "ProfiledBinary.h"
|
||||||
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
|
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
|
||||||
#include "llvm/ProfileData/ProfileCommon.h"
|
#include "llvm/ProfileData/ProfileCommon.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
||||||
cl::Required,
|
cl::Required,
|
||||||
|
@ -109,7 +111,7 @@ bool ProfileGeneratorBase::UseFSDiscriminator = false;
|
||||||
|
|
||||||
std::unique_ptr<ProfileGeneratorBase>
|
std::unique_ptr<ProfileGeneratorBase>
|
||||||
ProfileGeneratorBase::create(ProfiledBinary *Binary,
|
ProfileGeneratorBase::create(ProfiledBinary *Binary,
|
||||||
const ContextSampleCounterMap &SampleCounters,
|
const ContextSampleCounterMap *SampleCounters,
|
||||||
bool ProfileIsCSFlat) {
|
bool ProfileIsCSFlat) {
|
||||||
std::unique_ptr<ProfileGeneratorBase> Generator;
|
std::unique_ptr<ProfileGeneratorBase> Generator;
|
||||||
if (ProfileIsCSFlat) {
|
if (ProfileIsCSFlat) {
|
||||||
|
@ -125,6 +127,24 @@ ProfileGeneratorBase::create(ProfiledBinary *Binary,
|
||||||
return Generator;
|
return Generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ProfileGeneratorBase>
|
||||||
|
ProfileGeneratorBase::create(ProfiledBinary *Binary,
|
||||||
|
const SampleProfileMap &&Profiles,
|
||||||
|
bool ProfileIsCSFlat) {
|
||||||
|
std::unique_ptr<ProfileGeneratorBase> Generator;
|
||||||
|
if (ProfileIsCSFlat) {
|
||||||
|
if (Binary->useFSDiscriminator())
|
||||||
|
exitWithError("FS discriminator is not supported in CS profile.");
|
||||||
|
Generator.reset(new CSProfileGenerator(Binary, std::move(Profiles)));
|
||||||
|
} else {
|
||||||
|
Generator.reset(new ProfileGenerator(Binary, std::move(Profiles)));
|
||||||
|
}
|
||||||
|
ProfileGeneratorBase::UseFSDiscriminator = Binary->useFSDiscriminator();
|
||||||
|
FunctionSamples::ProfileIsFS = Binary->useFSDiscriminator();
|
||||||
|
|
||||||
|
return Generator;
|
||||||
|
}
|
||||||
|
|
||||||
void ProfileGeneratorBase::write(std::unique_ptr<SampleProfileWriter> Writer,
|
void ProfileGeneratorBase::write(std::unique_ptr<SampleProfileWriter> Writer,
|
||||||
SampleProfileMap &ProfileMap) {
|
SampleProfileMap &ProfileMap) {
|
||||||
// Populate profile symbol list if extended binary format is used.
|
// Populate profile symbol list if extended binary format is used.
|
||||||
|
@ -372,31 +392,39 @@ void ProfileGeneratorBase::updateTotalSamples() {
|
||||||
|
|
||||||
void ProfileGeneratorBase::collectProfiledFunctions() {
|
void ProfileGeneratorBase::collectProfiledFunctions() {
|
||||||
std::unordered_set<const BinaryFunction *> ProfiledFunctions;
|
std::unordered_set<const BinaryFunction *> ProfiledFunctions;
|
||||||
// Go through all the stacks, ranges and branches in sample counters, use the
|
if (SampleCounters) {
|
||||||
// start of the range to look up the function it belongs and record the
|
// Go through all the stacks, ranges and branches in sample counters, use
|
||||||
// function.
|
// the start of the range to look up the function it belongs and record the
|
||||||
for (const auto &CI : SampleCounters) {
|
// function.
|
||||||
if (const auto *CtxKey = dyn_cast<AddrBasedCtxKey>(CI.first.getPtr())) {
|
for (const auto &CI : *SampleCounters) {
|
||||||
for (auto Addr : CtxKey->Context) {
|
if (const auto *CtxKey = dyn_cast<AddrBasedCtxKey>(CI.first.getPtr())) {
|
||||||
if (FuncRange *FRange = Binary->findFuncRangeForOffset(
|
for (auto Addr : CtxKey->Context) {
|
||||||
Binary->virtualAddrToOffset(Addr)))
|
if (FuncRange *FRange = Binary->findFuncRangeForOffset(
|
||||||
|
Binary->virtualAddrToOffset(Addr)))
|
||||||
|
ProfiledFunctions.insert(FRange->Func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Item : CI.second.RangeCounter) {
|
||||||
|
uint64_t StartOffset = Item.first.first;
|
||||||
|
if (FuncRange *FRange = Binary->findFuncRangeForOffset(StartOffset))
|
||||||
|
ProfiledFunctions.insert(FRange->Func);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Item : CI.second.BranchCounter) {
|
||||||
|
uint64_t SourceOffset = Item.first.first;
|
||||||
|
uint64_t TargetOffset = Item.first.first;
|
||||||
|
if (FuncRange *FRange = Binary->findFuncRangeForOffset(SourceOffset))
|
||||||
|
ProfiledFunctions.insert(FRange->Func);
|
||||||
|
if (FuncRange *FRange = Binary->findFuncRangeForOffset(TargetOffset))
|
||||||
ProfiledFunctions.insert(FRange->Func);
|
ProfiledFunctions.insert(FRange->Func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
for (auto Item : CI.second.RangeCounter) {
|
// This is for the case the input is a llvm sample profile.
|
||||||
uint64_t StartOffset = Item.first.first;
|
for (const auto &FS : ProfileMap) {
|
||||||
if (FuncRange *FRange = Binary->findFuncRangeForOffset(StartOffset))
|
if (auto *Func = Binary->getBinaryFunction(FS.first.getName()))
|
||||||
ProfiledFunctions.insert(FRange->Func);
|
ProfiledFunctions.insert(Func);
|
||||||
}
|
|
||||||
|
|
||||||
for (auto Item : CI.second.BranchCounter) {
|
|
||||||
uint64_t SourceOffset = Item.first.first;
|
|
||||||
uint64_t TargetOffset = Item.first.first;
|
|
||||||
if (FuncRange *FRange = Binary->findFuncRangeForOffset(SourceOffset))
|
|
||||||
ProfiledFunctions.insert(FRange->Func);
|
|
||||||
if (FuncRange *FRange = Binary->findFuncRangeForOffset(TargetOffset))
|
|
||||||
ProfiledFunctions.insert(FRange->Func);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,11 +444,18 @@ ProfileGenerator::getTopLevelFunctionProfile(StringRef FuncName) {
|
||||||
|
|
||||||
void ProfileGenerator::generateProfile() {
|
void ProfileGenerator::generateProfile() {
|
||||||
collectProfiledFunctions();
|
collectProfiledFunctions();
|
||||||
if (Binary->usePseudoProbes()) {
|
|
||||||
generateProbeBasedProfile();
|
if (Binary->usePseudoProbes())
|
||||||
} else {
|
Binary->decodePseudoProbe();
|
||||||
generateLineNumBasedProfile();
|
|
||||||
|
if (SampleCounters) {
|
||||||
|
if (Binary->usePseudoProbes()) {
|
||||||
|
generateProbeBasedProfile();
|
||||||
|
} else {
|
||||||
|
generateLineNumBasedProfile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postProcessProfiles();
|
postProcessProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,9 +483,9 @@ void ProfileGenerator::trimColdProfiles(const SampleProfileMap &Profiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileGenerator::generateLineNumBasedProfile() {
|
void ProfileGenerator::generateLineNumBasedProfile() {
|
||||||
assert(SampleCounters.size() == 1 &&
|
assert(SampleCounters->size() == 1 &&
|
||||||
"Must have one entry for profile generation.");
|
"Must have one entry for profile generation.");
|
||||||
const SampleCounter &SC = SampleCounters.begin()->second;
|
const SampleCounter &SC = SampleCounters->begin()->second;
|
||||||
// Fill in function body samples
|
// Fill in function body samples
|
||||||
populateBodySamplesForAllFunctions(SC.RangeCounter);
|
populateBodySamplesForAllFunctions(SC.RangeCounter);
|
||||||
// Fill in boundary sample counts as well as call site samples for calls
|
// Fill in boundary sample counts as well as call site samples for calls
|
||||||
|
@ -460,12 +495,11 @@ void ProfileGenerator::generateLineNumBasedProfile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileGenerator::generateProbeBasedProfile() {
|
void ProfileGenerator::generateProbeBasedProfile() {
|
||||||
assert(SampleCounters.size() == 1 &&
|
assert(SampleCounters->size() == 1 &&
|
||||||
"Must have one entry for profile generation.");
|
"Must have one entry for profile generation.");
|
||||||
Binary->decodePseudoProbe();
|
|
||||||
// Enable pseudo probe functionalities in SampleProf
|
// Enable pseudo probe functionalities in SampleProf
|
||||||
FunctionSamples::ProfileIsProbeBased = true;
|
FunctionSamples::ProfileIsProbeBased = true;
|
||||||
const SampleCounter &SC = SampleCounters.begin()->second;
|
const SampleCounter &SC = SampleCounters->begin()->second;
|
||||||
// Fill in function body samples
|
// Fill in function body samples
|
||||||
populateBodySamplesWithProbesForAllFunctions(SC.RangeCounter);
|
populateBodySamplesWithProbesForAllFunctions(SC.RangeCounter);
|
||||||
// Fill in boundary sample counts as well as call site samples for calls
|
// Fill in boundary sample counts as well as call site samples for calls
|
||||||
|
@ -687,10 +721,15 @@ void CSProfileGenerator::generateProfile() {
|
||||||
|
|
||||||
collectProfiledFunctions();
|
collectProfiledFunctions();
|
||||||
|
|
||||||
if (Binary->usePseudoProbes()) {
|
if (Binary->usePseudoProbes())
|
||||||
generateProbeBasedProfile();
|
Binary->decodePseudoProbe();
|
||||||
} else {
|
|
||||||
generateLineNumBasedProfile();
|
if (SampleCounters) {
|
||||||
|
if (Binary->usePseudoProbes()) {
|
||||||
|
generateProbeBasedProfile();
|
||||||
|
} else {
|
||||||
|
generateLineNumBasedProfile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Binary->getTrackFuncContextSize())
|
if (Binary->getTrackFuncContextSize())
|
||||||
|
@ -709,7 +748,7 @@ void CSProfileGenerator::computeSizeForProfiledFunctions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSProfileGenerator::generateLineNumBasedProfile() {
|
void CSProfileGenerator::generateLineNumBasedProfile() {
|
||||||
for (const auto &CI : SampleCounters) {
|
for (const auto &CI : *SampleCounters) {
|
||||||
const auto *CtxKey = cast<StringBasedCtxKey>(CI.first.getPtr());
|
const auto *CtxKey = cast<StringBasedCtxKey>(CI.first.getPtr());
|
||||||
|
|
||||||
// Get or create function profile for the range
|
// Get or create function profile for the range
|
||||||
|
@ -967,10 +1006,9 @@ extractPrefixContextStack(SampleContextFrameVector &ContextStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSProfileGenerator::generateProbeBasedProfile() {
|
void CSProfileGenerator::generateProbeBasedProfile() {
|
||||||
Binary->decodePseudoProbe();
|
|
||||||
// Enable pseudo probe functionalities in SampleProf
|
// Enable pseudo probe functionalities in SampleProf
|
||||||
FunctionSamples::ProfileIsProbeBased = true;
|
FunctionSamples::ProfileIsProbeBased = true;
|
||||||
for (const auto &CI : SampleCounters) {
|
for (const auto &CI : *SampleCounters) {
|
||||||
const AddrBasedCtxKey *CtxKey =
|
const AddrBasedCtxKey *CtxKey =
|
||||||
dyn_cast<AddrBasedCtxKey>(CI.first.getPtr());
|
dyn_cast<AddrBasedCtxKey>(CI.first.getPtr());
|
||||||
SampleContextFrameVector ContextStack;
|
SampleContextFrameVector ContextStack;
|
||||||
|
|
|
@ -33,11 +33,18 @@ class ProfileGeneratorBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ProfileGeneratorBase(ProfiledBinary *Binary,
|
ProfileGeneratorBase(ProfiledBinary *Binary,
|
||||||
const ContextSampleCounterMap &Counters)
|
const ContextSampleCounterMap *Counters)
|
||||||
: Binary(Binary), SampleCounters(Counters){};
|
: Binary(Binary), SampleCounters(Counters){};
|
||||||
|
ProfileGeneratorBase(ProfiledBinary *Binary,
|
||||||
|
const SampleProfileMap &&Profiles)
|
||||||
|
: Binary(Binary), ProfileMap(std::move(Profiles)){};
|
||||||
|
|
||||||
virtual ~ProfileGeneratorBase() = default;
|
virtual ~ProfileGeneratorBase() = default;
|
||||||
static std::unique_ptr<ProfileGeneratorBase>
|
static std::unique_ptr<ProfileGeneratorBase>
|
||||||
create(ProfiledBinary *Binary, const ContextSampleCounterMap &SampleCounters,
|
create(ProfiledBinary *Binary, const ContextSampleCounterMap *Counters,
|
||||||
|
bool ProfileIsCSFlat);
|
||||||
|
static std::unique_ptr<ProfileGeneratorBase>
|
||||||
|
create(ProfiledBinary *Binary, const SampleProfileMap &&ProfileMap,
|
||||||
bool ProfileIsCSFlat);
|
bool ProfileIsCSFlat);
|
||||||
virtual void generateProfile() = 0;
|
virtual void generateProfile() = 0;
|
||||||
void write();
|
void write();
|
||||||
|
@ -113,20 +120,22 @@ protected:
|
||||||
|
|
||||||
uint64_t ColdCountThreshold;
|
uint64_t ColdCountThreshold;
|
||||||
|
|
||||||
|
ProfiledBinary *Binary = nullptr;
|
||||||
|
|
||||||
// Used by SampleProfileWriter
|
// Used by SampleProfileWriter
|
||||||
SampleProfileMap ProfileMap;
|
SampleProfileMap ProfileMap;
|
||||||
|
|
||||||
ProfiledBinary *Binary = nullptr;
|
const ContextSampleCounterMap *SampleCounters = nullptr;
|
||||||
|
|
||||||
const ContextSampleCounterMap &SampleCounters;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProfileGenerator : public ProfileGeneratorBase {
|
class ProfileGenerator : public ProfileGeneratorBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ProfileGenerator(ProfiledBinary *Binary,
|
ProfileGenerator(ProfiledBinary *Binary,
|
||||||
const ContextSampleCounterMap &Counters)
|
const ContextSampleCounterMap *Counters)
|
||||||
: ProfileGeneratorBase(Binary, Counters){};
|
: ProfileGeneratorBase(Binary, Counters){};
|
||||||
|
ProfileGenerator(ProfiledBinary *Binary, const SampleProfileMap &&Profiles)
|
||||||
|
: ProfileGeneratorBase(Binary, std::move(Profiles)){};
|
||||||
void generateProfile() override;
|
void generateProfile() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -143,9 +152,10 @@ private:
|
||||||
void populateBodySamplesForAllFunctions(const RangeSample &RangeCounter);
|
void populateBodySamplesForAllFunctions(const RangeSample &RangeCounter);
|
||||||
void
|
void
|
||||||
populateBoundarySamplesForAllFunctions(const BranchSample &BranchCounters);
|
populateBoundarySamplesForAllFunctions(const BranchSample &BranchCounters);
|
||||||
void populateBodySamplesWithProbesForAllFunctions(const RangeSample &RangeCounter);
|
|
||||||
void
|
void
|
||||||
populateBoundarySamplesWithProbesForAllFunctions(const BranchSample &BranchCounters);
|
populateBodySamplesWithProbesForAllFunctions(const RangeSample &RangeCounter);
|
||||||
|
void populateBoundarySamplesWithProbesForAllFunctions(
|
||||||
|
const BranchSample &BranchCounters);
|
||||||
void postProcessProfiles();
|
void postProcessProfiles();
|
||||||
void trimColdProfiles(const SampleProfileMap &Profiles,
|
void trimColdProfiles(const SampleProfileMap &Profiles,
|
||||||
uint64_t ColdCntThreshold);
|
uint64_t ColdCntThreshold);
|
||||||
|
@ -154,9 +164,10 @@ private:
|
||||||
class CSProfileGenerator : public ProfileGeneratorBase {
|
class CSProfileGenerator : public ProfileGeneratorBase {
|
||||||
public:
|
public:
|
||||||
CSProfileGenerator(ProfiledBinary *Binary,
|
CSProfileGenerator(ProfiledBinary *Binary,
|
||||||
const ContextSampleCounterMap &Counters)
|
const ContextSampleCounterMap *Counters)
|
||||||
: ProfileGeneratorBase(Binary, Counters){};
|
: ProfileGeneratorBase(Binary, Counters){};
|
||||||
|
CSProfileGenerator(ProfiledBinary *Binary, const SampleProfileMap &&Profiles)
|
||||||
|
: ProfileGeneratorBase(Binary, std::move(Profiles)){};
|
||||||
void generateProfile() override;
|
void generateProfile() override;
|
||||||
|
|
||||||
// Trim the context stack at a given depth.
|
// Trim the context stack at a given depth.
|
||||||
|
|
|
@ -49,6 +49,12 @@ static cl::opt<std::string> UnsymbolizedProfFilename(
|
||||||
static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"),
|
static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"),
|
||||||
cl::aliasopt(UnsymbolizedProfFilename));
|
cl::aliasopt(UnsymbolizedProfFilename));
|
||||||
|
|
||||||
|
static cl::opt<std::string>
|
||||||
|
SampleProfFilename("llvm-sample-profile",
|
||||||
|
cl::value_desc("llvm sample profile"), cl::ZeroOrMore,
|
||||||
|
cl::desc("Path of the LLVM sample profile"),
|
||||||
|
cl::cat(ProfGenCategory));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
BinaryPath("binary", cl::value_desc("binary"), cl::Required,
|
BinaryPath("binary", cl::value_desc("binary"), cl::Required,
|
||||||
cl::desc("Path of profiled executable binary."),
|
cl::desc("Path of profiled executable binary."),
|
||||||
|
@ -76,7 +82,9 @@ static void validateCommandLine() {
|
||||||
uint16_t HasPerfScript = PerfScriptFilename.getNumOccurrences();
|
uint16_t HasPerfScript = PerfScriptFilename.getNumOccurrences();
|
||||||
uint16_t HasUnsymbolizedProfile =
|
uint16_t HasUnsymbolizedProfile =
|
||||||
UnsymbolizedProfFilename.getNumOccurrences();
|
UnsymbolizedProfFilename.getNumOccurrences();
|
||||||
uint16_t S = HasPerfData + HasPerfScript + HasUnsymbolizedProfile;
|
uint16_t HasSampleProfile = SampleProfFilename.getNumOccurrences();
|
||||||
|
uint16_t S =
|
||||||
|
HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile;
|
||||||
if (S != 1) {
|
if (S != 1) {
|
||||||
std::string Msg =
|
std::string Msg =
|
||||||
S > 1
|
S > 1
|
||||||
|
@ -97,6 +105,7 @@ static void validateCommandLine() {
|
||||||
CheckFileExists(HasPerfData, PerfDataFilename);
|
CheckFileExists(HasPerfData, PerfDataFilename);
|
||||||
CheckFileExists(HasPerfScript, PerfScriptFilename);
|
CheckFileExists(HasPerfScript, PerfScriptFilename);
|
||||||
CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename);
|
CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename);
|
||||||
|
CheckFileExists(HasSampleProfile, SampleProfFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!llvm::sys::fs::exists(BinaryPath)) {
|
if (!llvm::sys::fs::exists(BinaryPath)) {
|
||||||
|
@ -146,20 +155,34 @@ int main(int argc, const char *argv[]) {
|
||||||
if (ShowDisassemblyOnly)
|
if (ShowDisassemblyOnly)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
PerfInputFile PerfFile = getPerfInputFile();
|
if (SampleProfFilename.getNumOccurrences()) {
|
||||||
std::unique_ptr<PerfReaderBase> Reader =
|
LLVMContext Context;
|
||||||
PerfReaderBase::create(Binary.get(), PerfFile);
|
auto ReaderOrErr = SampleProfileReader::create(SampleProfFilename, Context);
|
||||||
// Parse perf events and samples
|
std::unique_ptr<sampleprof::SampleProfileReader> Reader =
|
||||||
Reader->parsePerfTraces();
|
std::move(ReaderOrErr.get());
|
||||||
|
Reader->read();
|
||||||
|
std::unique_ptr<ProfileGeneratorBase> Generator =
|
||||||
|
ProfileGeneratorBase::create(Binary.get(),
|
||||||
|
std::move(Reader->getProfiles()),
|
||||||
|
Reader->profileIsCSFlat());
|
||||||
|
Generator->generateProfile();
|
||||||
|
Generator->write();
|
||||||
|
} else {
|
||||||
|
PerfInputFile PerfFile = getPerfInputFile();
|
||||||
|
std::unique_ptr<PerfReaderBase> Reader =
|
||||||
|
PerfReaderBase::create(Binary.get(), PerfFile);
|
||||||
|
// Parse perf events and samples
|
||||||
|
Reader->parsePerfTraces();
|
||||||
|
|
||||||
if (SkipSymbolization)
|
if (SkipSymbolization)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
std::unique_ptr<ProfileGeneratorBase> Generator =
|
std::unique_ptr<ProfileGeneratorBase> Generator =
|
||||||
ProfileGeneratorBase::create(Binary.get(), Reader->getSampleCounters(),
|
ProfileGeneratorBase::create(Binary.get(), &Reader->getSampleCounters(),
|
||||||
Reader->profileIsCSFlat());
|
Reader->profileIsCSFlat());
|
||||||
Generator->generateProfile();
|
Generator->generateProfile();
|
||||||
Generator->write();
|
Generator->write();
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue