forked from OSchip/llvm-project
[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:
parent
5642c3feb0
commit
998b97f6f1
|
@ -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
|
||||
-----------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# CSIR level Instrumentation Flag
|
||||
:csir
|
||||
bar
|
||||
# Func Hash:
|
||||
1152921534274394772
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
6000
|
||||
4000
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# CSIR level Instrumentation Flag
|
||||
:csir
|
||||
bar
|
||||
# Func Hash:
|
||||
1152921534274394772
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
4000
|
||||
6000
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue