[BOLT] Make hfsort+ deterministic and add test case

Summary:
Make hfsort+ algorithm deterministic.
We only had a test for hfsort.  Since hfsort+ is going to be the default, I've added a test for that too.

(cherry picked from FBD5143143)
This commit is contained in:
Bill Nell 2017-05-26 17:42:39 -07:00 committed by Maksim Panchenko
parent 5feee9f1d8
commit 382c660ee5
3 changed files with 34 additions and 17 deletions

View File

@ -67,12 +67,11 @@ constexpr int CallerDegradeFactor = 8;
////////////////////////////////////////////////////////////////////////////////
Cluster::Cluster(NodeId Id, const Node &Func) {
Cluster::Cluster(NodeId Id, const Node &Func)
: Samples(Func.samples()),
Size(Func.size()),
Density((double)Samples / Size) {
Targets.push_back(Id);
Size = Func.size();
Samples = Func.samples();
Density = (double)Samples / Size;
Frozen = false;
}
std::string Cluster::toString() const {

View File

@ -66,12 +66,21 @@ public:
return Targets[N];
}
void reverseTargets();
void setId(uint32_t NewId) {
assert(Id == -1u);
Id = NewId;
}
uint32_t id() const {
assert(Id != -1u);
return Id;
}
private:
uint32_t Id{-1u};
std::vector<CallGraph::NodeId> Targets;
uint64_t Samples;
uint32_t Size;
double Density;
bool Frozen; // not a candidate for merging
uint64_t Samples{0};
uint32_t Size{0};
double Density{0.0};
bool Frozen{false}; // not a candidate for merging
};
// Maximum size of a cluster, in bytes.

View File

@ -128,6 +128,8 @@ struct AlgoState {
std::vector<Cluster *> FuncCluster;
// current address of the function from the beginning of its cluster
std::vector<size_t> Addr;
// maximum cluster id.
size_t MaxClusterId;
};
}
@ -136,7 +138,7 @@ struct AlgoState {
* Sorting clusters by their density in decreasing order
*/
void sortByDensity(std::vector<Cluster *> &Clusters) {
std::sort(
std::stable_sort(
Clusters.begin(),
Clusters.end(),
[&] (const Cluster *C1, const Cluster *C2) {
@ -248,23 +250,29 @@ double expectedCacheHitRatio(const AlgoState &State,
/*
* Get adjacent clusters (the ones that share an arc) with the given one
*/
std::unordered_set<Cluster *> adjacentClusters(const AlgoState &State,
Cluster *C) {
std::unordered_set<Cluster *> Result;
std::vector<Cluster *> adjacentClusters(const AlgoState &State, Cluster *C) {
std::vector<Cluster *> Result;
Result.reserve(State.MaxClusterId);
for (auto TargetId : C->targets()) {
for (auto Succ : State.Cg->successors(TargetId)) {
auto SuccCluster = State.FuncCluster[Succ];
if (SuccCluster != nullptr && SuccCluster != C) {
Result.insert(SuccCluster);
Result.push_back(SuccCluster);
}
}
for (auto Pred : State.Cg->predecessors(TargetId)) {
auto PredCluster = State.FuncCluster[Pred];
if (PredCluster != nullptr && PredCluster != C) {
Result.insert(PredCluster);
Result.push_back(PredCluster);
}
}
}
std::sort(Result.begin(), Result.end(),
[](const Cluster *A, const Cluster *B) {
return A->id() < B->id();
});
auto Last = std::unique(Result.begin(), Result.end());
Result.erase(Last, Result.end());
return Result;
}
@ -385,6 +393,7 @@ std::vector<Cluster> hfsortPlus(const CallGraph &Cg) {
AllClusters.reserve(Cg.numNodes());
for (NodeId F = 0; F < Cg.numNodes(); F++) {
AllClusters.emplace_back(F, Cg.getNode(F));
AllClusters.back().setId(F);
}
// initialize objects used by the algorithm
@ -395,9 +404,9 @@ std::vector<Cluster> hfsortPlus(const CallGraph &Cg) {
State.TotalSamples = 0;
State.FuncCluster = std::vector<Cluster *>(Cg.numNodes(), nullptr);
State.Addr = std::vector<size_t>(Cg.numNodes(), InvalidAddr);
State.MaxClusterId = AllClusters.back().id();
for (NodeId F = 0; F < Cg.numNodes(); F++) {
if (Cg.samples(F) == 0) continue;
Clusters.push_back(&AllClusters[F]);
State.FuncCluster[F] = &AllClusters[F];
State.Addr[F] = 0;
@ -487,7 +496,7 @@ std::vector<Cluster> hfsortPlus(const CallGraph &Cg) {
Result.emplace_back(std::move(*Cluster));
}
std::sort(Result.begin(), Result.end(), compareClustersDensity);
assert(std::is_sorted(Result.begin(), Result.end(), compareClustersDensity));
return Result;
}