[llvm-profdata] Add overlap command to compute similarity b/w two profile files

Add overlap functionality to llvm-profdata tool to compute the similarity
between two profile files.

Differential Revision: https://reviews.llvm.org/D60977

llvm-svn: 359612
This commit is contained in:
Rong Xu 2019-04-30 21:19:12 +00:00
parent 5642c3feb0
commit 998b97f6f1
17 changed files with 718 additions and 3 deletions

View File

@ -17,6 +17,7 @@ COMMANDS
* :ref:`merge <profdata-merge>`
* :ref:`show <profdata-show>`
* :ref:`overlap <profdata-overlap>`
.. program:: llvm-profdata merge
@ -231,6 +232,72 @@ OPTIONS
Only show context sensitive profile counts. The default is to filter all
context sensitive profile counts.
.. program:: llvm-profdata overlap
.. _profdata-overlap:
OVERLAP
-------
SYNOPSIS
^^^^^^^^
:program:`llvm-profdata overlap` [*options*] [*base profile file*] [*test profile file*]
DESCRIPTION
^^^^^^^^^^^
:program:`llvm-profdata overlap` takes two profile data files and displays the
*overlap* of counter distribution between the whole files and between any of the
specified functions.
In this command, *overlap* is defined as follows:
Suppose *base profile file* has the following counts:
{c1_1, c1_2, ..., c1_n, c1_u_1, c2_u_2, ..., c2_u_s},
and *test profile file* has
{c2_1, c2_2, ..., c2_n, c2_v_1, c2_v_2, ..., c2_v_t}.
Here c{1|2}_i (i = 1 .. n) are matched counters and c1_u_i (i = 1 .. s) and
c2_v_i (i = 1 .. v) are unmatched counters (or counters only existing in)
*base profile file* and *test profile file*, respectively.
Let sum_1 = c1_1 + c1_2 + ... + c1_n + c1_u_1 + c2_u_2 + ... + c2_u_s, and
sum_2 = c2_1 + c2_2 + ... + c2_n + c2_v_1 + c2_v_2 + ... + c2_v_t.
*overlap* = min(c1_1/sum_1, c2_1/sum_2) + min(c1_2/sum_1, c2_2/sum_2) + ...
min(c1_n/sum_1, c2_n/sum_2).
The result overlap distribution is a percentage number, ranging from 0.0% to
100.0%, where 0.0% means there is no overlap and 100.0% means a perfect
overlap.
Here is an example, if *base profile file* has counts of {400, 600}, and
*test profile file* has matched counts of {60000, 40000}. The *overlap* is 80%.
OPTIONS
^^^^^^^
.. option:: -function=string
Print details for a function if the function's name contains the given string.
.. option:: -help
Print a summary of command line options.
.. option:: -o=output or -o output
Specify the output file name. If *output* is ``-`` or it isn't specified,
then the output is sent to standard output.
.. option:: -value-cutoff=n
Show only those functions whose max count values are greater or equal to ``n``.
By default, the value-cutoff is set to max of unsigned long long.
.. option:: -cs
Only show overlap for the context sensitive profile counts. The default is to show
non-context sensitive profile counts.
EXIT STATUS
-----------

View File

@ -590,6 +590,70 @@ StringRef InstrProfSymtab::getOrigFuncName(uint64_t FuncMD5Hash) {
return PGOName.drop_front(S + 1);
}
// To store the sums of profile count values, or the percentage of
// the sums of the total count values.
struct CountSumOrPercent {
uint64_t NumEntries;
double CountSum;
double ValueCounts[IPVK_Last - IPVK_First + 1];
CountSumOrPercent() : NumEntries(0), CountSum(0.0f), ValueCounts() {}
void reset() {
NumEntries = 0;
CountSum = 0.0f;
for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++)
ValueCounts[I] = 0.0f;
}
};
// Function level or program level overlap information.
struct OverlapStats {
enum OverlapStatsLevel { ProgramLevel, FunctionLevel };
// Sum of the total count values for the base profile.
CountSumOrPercent Base;
// Sum of the total count values for the test profile.
CountSumOrPercent Test;
// Overlap lap score. Should be in range of [0.0f to 1.0f].
CountSumOrPercent Overlap;
CountSumOrPercent Mismatch;
CountSumOrPercent Unique;
OverlapStatsLevel Level;
const std::string *BaseFilename;
const std::string *TestFilename;
StringRef FuncName;
uint64_t FuncHash;
bool Valid;
OverlapStats(OverlapStatsLevel L = ProgramLevel)
: Level(L), BaseFilename(nullptr), TestFilename(nullptr), FuncHash(0),
Valid(false) {}
void dump(raw_fd_ostream &OS) const;
void setFuncInfo(StringRef Name, uint64_t Hash) {
FuncName = Name;
FuncHash = Hash;
}
Error accumuateCounts(const std::string &BaseFilename,
const std::string &TestFilename, bool IsCS);
void addOneMismatch(const CountSumOrPercent &MismatchFunc);
void addOneUnique(const CountSumOrPercent &UniqueFunc);
static inline double score(uint64_t Val1, uint64_t Val2, double Sum1,
double Sum2) {
if (Sum1 < 1.0f || Sum2 < 1.0f)
return 0.0f;
return std::min(Val1 / Sum1, Val2 / Sum2);
}
};
// This is used to filter the functions whose overlap information
// to be output.
struct OverlapFuncFilters {
uint64_t ValueCutoff;
const std::string NameFilter;
};
struct InstrProfValueSiteRecord {
/// Value profiling data pairs at a given value site.
std::list<InstrProfValueData> ValueData;
@ -615,6 +679,10 @@ struct InstrProfValueSiteRecord {
function_ref<void(instrprof_error)> Warn);
/// Scale up value profile data counts.
void scale(uint64_t Weight, function_ref<void(instrprof_error)> Warn);
/// Compute the overlap b/w this record and Input record.
void overlap(InstrProfValueSiteRecord &Input, uint32_t ValueKind,
OverlapStats &Overlap, OverlapStats &FuncLevelOverlap);
};
/// Profiling information for a single function.
@ -703,6 +771,18 @@ struct InstrProfRecord {
/// Clear value data entries
void clearValueData() { ValueData = nullptr; }
/// Compute the sums of all counts and store in Sum.
void accumuateCounts(CountSumOrPercent &Sum) const;
/// Compute the overlap b/w this IntrprofRecord and Other.
void overlap(InstrProfRecord &Other, OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap, uint64_t ValueCutoff);
/// Compute the overlap of value profile counts.
void overlapValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap);
private:
struct ValueProfData {
std::vector<InstrProfValueSiteRecord> IndirectCallSites;
@ -1060,5 +1140,4 @@ void createIRLevelProfileFlagVar(Module &M, bool IsCS);
void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput);
} // end namespace llvm
#endif // LLVM_PROFILEDATA_INSTRPROF_H

View File

@ -91,6 +91,9 @@ public:
/// compiler.
virtual InstrProfSymtab &getSymtab() = 0;
/// Compute the sum of counts and return in Sum.
void accumuateCounts(CountSumOrPercent &Sum, bool IsCS);
protected:
std::unique_ptr<InstrProfSymtab> Symtab;

View File

@ -100,6 +100,11 @@ public:
// Internal interface for testing purpose only.
void setValueProfDataEndianness(support::endianness Endianness);
void setOutputSparse(bool Sparse);
// Compute the overlap b/w this object and Other. Program level result is
// stored in Overlap and function level result is stored in FuncLevelOverlap.
void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap,
const OverlapFuncFilters &FuncFilter);
private:
void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,

View File

@ -29,6 +29,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
@ -478,6 +479,127 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) {
return Error::success();
}
void InstrProfRecord::accumuateCounts(CountSumOrPercent &Sum) const {
uint64_t FuncSum = 0;
Sum.NumEntries += Counts.size();
for (size_t F = 0, E = Counts.size(); F < E; ++F)
FuncSum += Counts[F];
Sum.CountSum += FuncSum;
for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) {
uint64_t KindSum = 0;
uint32_t NumValueSites = getNumValueSites(VK);
for (size_t I = 0; I < NumValueSites; ++I) {
uint32_t NV = getNumValueDataForSite(VK, I);
std::unique_ptr<InstrProfValueData[]> VD = getValueForSite(VK, I);
for (uint32_t V = 0; V < NV; V++)
KindSum += VD[V].Count;
}
Sum.ValueCounts[VK] += KindSum;
}
}
void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input,
uint32_t ValueKind,
OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap) {
this->sortByTargetValues();
Input.sortByTargetValues();
double Score = 0.0f, FuncLevelScore = 0.0f;
auto I = ValueData.begin();
auto IE = ValueData.end();
auto J = Input.ValueData.begin();
auto JE = Input.ValueData.end();
while (I != IE && J != JE) {
if (I->Value == J->Value) {
Score += OverlapStats::score(I->Count, J->Count,
Overlap.Base.ValueCounts[ValueKind],
Overlap.Test.ValueCounts[ValueKind]);
FuncLevelScore += OverlapStats::score(
I->Count, J->Count, FuncLevelOverlap.Base.ValueCounts[ValueKind],
FuncLevelOverlap.Test.ValueCounts[ValueKind]);
++I;
} else if (I->Value < J->Value) {
++I;
continue;
}
++J;
}
Overlap.Overlap.ValueCounts[ValueKind] += Score;
FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore;
}
// Return false on mismatch.
void InstrProfRecord::overlapValueProfData(uint32_t ValueKind,
InstrProfRecord &Other,
OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap) {
uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
uint32_t OtherNumValueSites = Other.getNumValueSites(ValueKind);
assert(ThisNumValueSites == OtherNumValueSites);
if (!ThisNumValueSites)
return;
std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =
getOrCreateValueSitesForKind(ValueKind);
MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords =
Other.getValueSitesForKind(ValueKind);
for (uint32_t I = 0; I < ThisNumValueSites; I++)
ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap,
FuncLevelOverlap);
}
void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap,
uint64_t ValueCutoff) {
// FuncLevel CountSum for other should already computed and nonzero.
assert(FuncLevelOverlap.Test.CountSum >= 1.0f);
accumuateCounts(FuncLevelOverlap.Base);
bool Mismatch = (Counts.size() != Other.Counts.size());
// Check if the value profiles mismatch.
if (!Mismatch) {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
uint32_t ThisNumValueSites = getNumValueSites(Kind);
uint32_t OtherNumValueSites = Other.getNumValueSites(Kind);
if (ThisNumValueSites != OtherNumValueSites) {
Mismatch = true;
break;
}
}
}
if (Mismatch) {
Overlap.addOneMismatch(FuncLevelOverlap.Test);
return;
}
// Compute overlap for value counts.
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap);
double Score = 0.0;
uint64_t MaxCount = 0;
// Compute overlap for edge counts.
for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
Score += OverlapStats::score(Counts[I], Other.Counts[I],
Overlap.Base.CountSum, Overlap.Test.CountSum);
MaxCount = std::max(Other.Counts[I], MaxCount);
}
Overlap.Overlap.CountSum += Score;
Overlap.Overlap.NumEntries += 1;
if (MaxCount >= ValueCutoff) {
double FuncScore = 0.0;
for (size_t I = 0, E = Other.Counts.size(); I < E; ++I)
FuncScore += OverlapStats::score(Counts[I], Other.Counts[I],
FuncLevelOverlap.Base.CountSum,
FuncLevelOverlap.Test.CountSum);
FuncLevelOverlap.Overlap.CountSum = FuncScore;
FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size();
FuncLevelOverlap.Valid = true;
}
}
void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input,
uint64_t Weight,
function_ref<void(instrprof_error)> Warn) {
@ -1046,4 +1168,117 @@ void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput) {
}
}
Error OverlapStats::accumuateCounts(const std::string &BaseFilename,
const std::string &TestFilename,
bool IsCS) {
auto getProfileSum = [IsCS](const std::string &Filename,
CountSumOrPercent &Sum) -> Error {
auto ReaderOrErr = InstrProfReader::create(Filename);
if (Error E = ReaderOrErr.takeError()) {
return E;
}
auto Reader = std::move(ReaderOrErr.get());
Reader->accumuateCounts(Sum, IsCS);
return Error::success();
};
auto Ret = getProfileSum(BaseFilename, Base);
if (Ret)
return std::move(Ret);
Ret = getProfileSum(TestFilename, Test);
if (Ret)
return std::move(Ret);
this->BaseFilename = &BaseFilename;
this->TestFilename = &TestFilename;
Valid = true;
return Error::success();
}
void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) {
Mismatch.NumEntries += 1;
Mismatch.CountSum += MismatchFunc.CountSum / Test.CountSum;
for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
if (Test.ValueCounts[I] >= 1.0f)
Mismatch.ValueCounts[I] +=
MismatchFunc.ValueCounts[I] / Test.ValueCounts[I];
}
}
void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) {
Unique.NumEntries += 1;
Unique.CountSum += UniqueFunc.CountSum / Test.CountSum;
for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
if (Test.ValueCounts[I] >= 1.0f)
Unique.ValueCounts[I] += UniqueFunc.ValueCounts[I] / Test.ValueCounts[I];
}
}
void OverlapStats::dump(raw_fd_ostream &OS) const {
if (!Valid)
return;
const char *EntryName =
(Level == ProgramLevel ? "functions" : "edge counters");
if (Level == ProgramLevel) {
OS << "Profile overlap infomation for base_profile: " << *BaseFilename
<< " and test_profile: " << *TestFilename << "\nProgram level:\n";
} else {
OS << "Function level:\n"
<< " Function: " << FuncName << " (Hash=" << FuncHash << ")\n";
}
OS << " # of " << EntryName << " overlap: " << Overlap.NumEntries << "\n";
if (Mismatch.NumEntries)
OS << " # of " << EntryName << " mismatch: " << Mismatch.NumEntries
<< "\n";
if (Unique.NumEntries)
OS << " # of " << EntryName
<< " only in test_profile: " << Unique.NumEntries << "\n";
OS << " Edge profile overlap: " << format("%.3f%%", Overlap.CountSum * 100)
<< "\n";
if (Mismatch.NumEntries)
OS << " Mismatched count percentage (Edge): "
<< format("%.3f%%", Mismatch.CountSum * 100) << "\n";
if (Unique.NumEntries)
OS << " Percentage of Edge profile only in test_profile: "
<< format("%.3f%%", Unique.CountSum * 100) << "\n";
OS << " Edge profile base count sum: " << format("%.0f", Base.CountSum)
<< "\n"
<< " Edge profile test count sum: " << format("%.0f", Test.CountSum)
<< "\n";
for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
if (Base.ValueCounts[I] < 1.0f && Test.ValueCounts[I] < 1.0f)
continue;
char ProfileKindName[20];
switch (I) {
case IPVK_IndirectCallTarget:
strncpy(ProfileKindName, "IndirectCall", 19);
break;
case IPVK_MemOPSize:
strncpy(ProfileKindName, "MemOP", 19);
break;
default:
snprintf(ProfileKindName, 19, "VP[%d]", I);
break;
}
OS << " " << ProfileKindName
<< " profile overlap: " << format("%.3f%%", Overlap.ValueCounts[I] * 100)
<< "\n";
if (Mismatch.NumEntries)
OS << " Mismatched count percentage (" << ProfileKindName
<< "): " << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n";
if (Unique.NumEntries)
OS << " Percentage of " << ProfileKindName
<< " profile only in test_profile: "
<< format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n";
OS << " " << ProfileKindName
<< " profile base count sum: " << format("%.0f", Base.ValueCounts[I])
<< "\n"
<< " " << ProfileKindName
<< " profile test count sum: " << format("%.0f", Test.ValueCounts[I])
<< "\n";
}
}
} // end namespace llvm

View File

@ -900,3 +900,17 @@ Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
}
return success();
}
void InstrProfReader::accumuateCounts(CountSumOrPercent &Sum, bool IsCS) {
uint64_t NumFuncs = 0;
for (const auto &Func : *this) {
if (isIRLevelProfile()) {
bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
if (FuncIsCS != IsCS)
continue;
}
Func.accumuateCounts(Sum);
++NumFuncs;
}
Sum.NumEntries = NumFuncs;
}

View File

@ -187,6 +187,40 @@ void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
addRecord(Name, Hash, std::move(I), Weight, Warn);
}
void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
OverlapStats &Overlap,
OverlapStats &FuncLevelOverlap,
const OverlapFuncFilters &FuncFilter) {
auto Name = Other.Name;
auto Hash = Other.Hash;
Other.accumuateCounts(FuncLevelOverlap.Test);
if (FunctionData.find(Name) == FunctionData.end()) {
Overlap.addOneUnique(FuncLevelOverlap.Test);
return;
}
if (FuncLevelOverlap.Test.CountSum < 1.0f) {
Overlap.Overlap.NumEntries += 1;
return;
}
auto &ProfileDataMap = FunctionData[Name];
bool NewFunc;
ProfilingData::iterator Where;
std::tie(Where, NewFunc) =
ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
if (NewFunc) {
Overlap.addOneMismatch(FuncLevelOverlap.Test);
return;
}
InstrProfRecord &Dest = Where->second;
uint64_t ValueCutoff = FuncFilter.ValueCutoff;
if (!FuncFilter.NameFilter.empty() &&
Name.find(FuncFilter.NameFilter) != Name.npos)
ValueCutoff = 0;
Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
}
void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
InstrProfRecord &&I, uint64_t Weight,
function_ref<void(Error)> Warn) {

View File

@ -0,0 +1,36 @@
# IR level Instrumentation Flag
:ir
bar
# Func Hash:
12884901887
# Num Counters:
1
# Counter Values:
100000
bar1
# Func Hash:
12884901887
# Num Counters:
1
# Counter Values:
100000
foo
# Func Hash:
25571299074
# Num Counters:
2
# Counter Values:
40000
60000
main
# Func Hash:
29212902728
# Num Counters:
2
# Counter Values:
200000
0

View File

@ -0,0 +1,11 @@
# CSIR level Instrumentation Flag
:csir
bar
# Func Hash:
1152921534274394772
# Num Counters:
2
# Counter Values:
6000
4000

View File

@ -0,0 +1,25 @@
:IR
foo
# Func Hash:
72057649435042473
# Num Counters:
2
# Counter Values:
40000
60000
# Num Value Kinds:
2
# ValueKind = IPVK_IndirectCallTarget:
0
# NumValueSites:
1
2
bar1:40000
bar2:60000
# ValueKind = IPVK_MemOPSize:
1
# NumValueSites:
1
2
1:40000
4:60000

View File

@ -0,0 +1,36 @@
# IR level Instrumentation Flag
:ir
bar
# Func Hash:
12884901887
# Num Counters:
1
# Counter Values:
10000
bar2
# Func Hash:
12884901887
# Num Counters:
1
# Counter Values:
10000
foo
# Func Hash:
25571299075
# Num Counters:
2
# Counter Values:
4000
6000
main
# Func Hash:
29212902728
# Num Counters:
2
# Counter Values:
20000
0

View File

@ -0,0 +1,11 @@
# CSIR level Instrumentation Flag
:csir
bar
# Func Hash:
1152921534274394772
# Num Counters:
2
# Counter Values:
4000
6000

View File

@ -0,0 +1,25 @@
:IR
foo
# Func Hash:
72057649435042473
# Num Counters:
2
# Counter Values:
30000
20000
# Num Value Kinds:
2
# ValueKind = IPVK_IndirectCallTarget:
0
# NumValueSites:
1
2
bar1:30000
bar2:20000
# ValueKind = IPVK_MemOPSize:
1
# NumValueSites:
1
2
1:3000
4:2000

View File

@ -0,0 +1,21 @@
RUN: llvm-profdata overlap %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=OVERLAP
RUN: llvm-profdata overlap -function=main %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
RUN: llvm-profdata overlap -value-cutoff=15000 %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
RUN: llvm-profdata merge %p/Inputs/overlap_1.proftext -o %t_1.profdata
RUN: llvm-profdata merge %p/Inputs/overlap_2.proftext -o %t_2.profdata
RUN: llvm-profdata overlap %t_1.profdata %t_2.profdata | FileCheck %s -check-prefix=OVERLAP
MAINFUNC: Function: main (Hash=29212902728)
MAINFUNC: # of edge counters overlap: 2
MAINFUNC: Edge profile overlap: 100.000%
MAINFUNC: Edge profile base count sum: 200000
MAINFUNC: Edge profile test count sum: 20000
OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
OVERLAP: Program level:
OVERLAP: # of functions overlap: 2
OVERLAP: # of functions mismatch: 1
OVERLAP: # of functions only in test_profile: 1
OVERLAP: Edge profile overlap: 60.000%
OVERLAP: Mismatched count percentage (Edge): 20.000%
OVERLAP: Percentage of Edge profile only in test_profile: 20.000%
OVERLAP: Edge profile base count sum: 500000
OVERLAP: Edge profile test count sum: 50000

View File

@ -0,0 +1,10 @@
RUN: llvm-profdata overlap -cs %p/Inputs/overlap_1_cs.proftext %p/Inputs/overlap_2_cs.proftext | FileCheck %s -check-prefix=OVERLAP
RUN: llvm-profdata merge %p/Inputs/overlap_1_cs.proftext -o %t_1_cs.profdata
RUN: llvm-profdata merge %p/Inputs/overlap_2_cs.proftext -o %t_2_cs.profdata
RUN: llvm-profdata overlap -cs %t_1_cs.profdata %t_2_cs.profdata | FileCheck %s -check-prefix=OVERLAP
OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
OVERLAP: Program level:
OVERLAP: # of functions overlap: 1
OVERLAP: Edge profile overlap: 80.000%
OVERLAP: Edge profile base count sum: 10000
OVERLAP: Edge profile test count sum: 10000

View File

@ -0,0 +1,16 @@
RUN: llvm-profdata overlap %p/Inputs/overlap_1_vp.proftext %p/Inputs/overlap_2_vp.proftext | FileCheck %s -check-prefix=OVERLAP
RUN: llvm-profdata merge %p/Inputs/overlap_1_vp.proftext -o %t_1_vp.profdata
RUN: llvm-profdata merge %p/Inputs/overlap_2_vp.proftext -o %t_2_vp.profdata
RUN: llvm-profdata overlap %t_1_vp.profdata %t_2_vp.profdata | FileCheck %s -check-prefix=OVERLAP
OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
OVERLAP: Program level:
OVERLAP: # of functions overlap: 1
OVERLAP: Edge profile overlap: 80.000%
OVERLAP: Edge profile base count sum: 100000
OVERLAP: Edge profile test count sum: 50000
OVERLAP: IndirectCall profile overlap: 80.000%
OVERLAP: IndirectCall profile base count sum: 100000
OVERLAP: IndirectCall profile test count sum: 50000
OVERLAP: MemOP profile overlap: 80.000%
OVERLAP: MemOP profile base count sum: 100000
OVERLAP: MemOP profile test count sum: 5000

View File

@ -200,6 +200,32 @@ static bool isFatalError(instrprof_error IPE) {
}
}
/// Computer the overlap b/w profile BaseFilename and TestFileName,
/// and store the program level result to Overlap.
static void overlapInput(const std::string &BaseFilename,
const std::string &TestFilename, WriterContext *WC,
OverlapStats &Overlap,
const OverlapFuncFilters &FuncFilter,
raw_fd_ostream &OS, bool IsCS) {
auto ReaderOrErr = InstrProfReader::create(TestFilename);
if (Error E = ReaderOrErr.takeError()) {
// Skip the empty profiles by returning sliently.
instrprof_error IPE = InstrProfError::take(std::move(E));
if (IPE != instrprof_error::empty_raw_profile)
WC->Err = make_error<InstrProfError>(IPE);
return;
}
auto Reader = std::move(ReaderOrErr.get());
for (auto &I : *Reader) {
OverlapStats FuncOverlap(OverlapStats::FunctionLevel);
FuncOverlap.setFuncInfo(I.Name, I.Hash);
WC->Writer.overlapRecord(std::move(I), Overlap, FuncOverlap, FuncFilter);
FuncOverlap.dump(OS);
}
}
/// Load an input into a writer context.
static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
WriterContext *WC) {
@ -608,6 +634,65 @@ static int merge_main(int argc, const char *argv[]) {
return 0;
}
/// Computer the overlap b/w profile BaseFilename and profile TestFilename.
static void overlapInstrProfile(const std::string &BaseFilename,
const std::string &TestFilename,
const OverlapFuncFilters &FuncFilter,
raw_fd_ostream &OS, bool IsCS) {
std::mutex ErrorLock;
SmallSet<instrprof_error, 4> WriterErrorCodes;
WriterContext Context(false, ErrorLock, WriterErrorCodes);
WeightedFile WeightedInput{BaseFilename, 1};
OverlapStats Overlap;
Error E = Overlap.accumuateCounts(BaseFilename, TestFilename, IsCS);
if (E)
exitWithError(std::move(E), "Error in getting profile count sums");
if (Overlap.Base.CountSum < 1.0f) {
OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
exit(0);
}
if (Overlap.Test.CountSum < 1.0f) {
OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
exit(0);
}
loadInput(WeightedInput, nullptr, &Context);
overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
IsCS);
Overlap.dump(OS);
}
static int overlap_main(int argc, const char *argv[]) {
cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
cl::desc("<base profile file>"));
cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
cl::desc("<test profile file>"));
cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
cl::desc("Output file"));
cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
cl::opt<bool> IsCS("cs", cl::init(false),
cl::desc("For context sensitive counts"));
cl::opt<unsigned long long> ValueCutoff(
"value-cutoff", cl::init(-1),
cl::desc(
"Function level overlap information for every function in test "
"profile with max count value greater then the parameter value"));
cl::opt<std::string> FuncNameFilter(
"function",
cl::desc("Function level overlap information for matching functions"));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
std::error_code EC;
raw_fd_ostream OS(Output.data(), EC, sys::fs::F_Text);
if (EC)
exitWithErrorCode(EC, Output);
overlapInstrProfile(BaseFilename, TestFilename,
OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
IsCS);
return 0;
}
typedef struct ValueSitesStats {
ValueSitesStats()
: TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
@ -965,6 +1050,8 @@ int main(int argc, const char *argv[]) {
func = merge_main;
else if (strcmp(argv[1], "show") == 0)
func = show_main;
else if (strcmp(argv[1], "overlap") == 0)
func = overlap_main;
if (func) {
std::string Invocation(ProgName.str() + " " + argv[1]);
@ -979,7 +1066,7 @@ int main(int argc, const char *argv[]) {
<< "USAGE: " << ProgName << " <command> [args...]\n"
<< "USAGE: " << ProgName << " <command> -help\n\n"
<< "See each individual command --help for more details.\n"
<< "Available commands: merge, show\n";
<< "Available commands: merge, show, overlap\n";
return 0;
}
}
@ -989,6 +1076,6 @@ int main(int argc, const char *argv[]) {
else
errs() << ProgName << ": Unknown command!\n";
errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n";
return 1;
}