14824e7fdSDimitry Andric //===- SampleProfileInference.cpp - Adjust sample profiles in the IR ------===// 24824e7fdSDimitry Andric // 34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64824e7fdSDimitry Andric // 74824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 84824e7fdSDimitry Andric // 94824e7fdSDimitry Andric // This file implements a profile inference algorithm. Given an incomplete and 104824e7fdSDimitry Andric // possibly imprecise block counts, the algorithm reconstructs realistic block 114824e7fdSDimitry Andric // and edge counts that satisfy flow conservation rules, while minimally modify 124824e7fdSDimitry Andric // input block counts. 134824e7fdSDimitry Andric // 144824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 154824e7fdSDimitry Andric 164824e7fdSDimitry Andric #include "llvm/Transforms/Utils/SampleProfileInference.h" 1704eeddc0SDimitry Andric #include "llvm/ADT/BitVector.h" 1881ad6265SDimitry Andric #include "llvm/Support/CommandLine.h" 194824e7fdSDimitry Andric #include "llvm/Support/Debug.h" 204824e7fdSDimitry Andric #include <queue> 214824e7fdSDimitry Andric #include <set> 2281ad6265SDimitry Andric #include <stack> 234824e7fdSDimitry Andric 244824e7fdSDimitry Andric using namespace llvm; 254824e7fdSDimitry Andric #define DEBUG_TYPE "sample-profile-inference" 264824e7fdSDimitry Andric 274824e7fdSDimitry Andric namespace { 284824e7fdSDimitry Andric 29*bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileEvenFlowDistribution( 30*bdd1243dSDimitry Andric "sample-profile-even-flow-distribution", cl::init(true), cl::Hidden, 31*bdd1243dSDimitry Andric cl::desc("Try to evenly distribute flow when there are multiple equally " 3281ad6265SDimitry Andric "likely options.")); 3381ad6265SDimitry Andric 34*bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileRebalanceUnknown( 35*bdd1243dSDimitry Andric "sample-profile-rebalance-unknown", cl::init(true), cl::Hidden, 36*bdd1243dSDimitry Andric cl::desc("Evenly re-distribute flow among unknown subgraphs.")); 3781ad6265SDimitry Andric 38*bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileJoinIslands( 39*bdd1243dSDimitry Andric "sample-profile-join-islands", cl::init(true), cl::Hidden, 40*bdd1243dSDimitry Andric cl::desc("Join isolated components having positive flow.")); 4181ad6265SDimitry Andric 42*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockInc( 43*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-inc", cl::init(10), cl::Hidden, 44*bdd1243dSDimitry Andric cl::desc("The cost of increasing a block's count by one.")); 4581ad6265SDimitry Andric 46*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockDec( 47*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-dec", cl::init(20), cl::Hidden, 48*bdd1243dSDimitry Andric cl::desc("The cost of decreasing a block's count by one.")); 4981ad6265SDimitry Andric 50*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockEntryInc( 51*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-entry-inc", cl::init(40), cl::Hidden, 52*bdd1243dSDimitry Andric cl::desc("The cost of increasing the entry block's count by one.")); 5381ad6265SDimitry Andric 54*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockEntryDec( 55*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-entry-dec", cl::init(10), cl::Hidden, 56*bdd1243dSDimitry Andric cl::desc("The cost of decreasing the entry block's count by one.")); 57*bdd1243dSDimitry Andric 58*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockZeroInc( 59*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-zero-inc", cl::init(11), cl::Hidden, 60*bdd1243dSDimitry Andric cl::desc("The cost of increasing a count of zero-weight block by one.")); 61*bdd1243dSDimitry Andric 62*bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockUnknownInc( 63*bdd1243dSDimitry Andric "sample-profile-profi-cost-block-unknown-inc", cl::init(0), cl::Hidden, 64*bdd1243dSDimitry Andric cl::desc("The cost of increasing an unknown block's count by one.")); 6581ad6265SDimitry Andric 664824e7fdSDimitry Andric /// A value indicating an infinite flow/capacity/weight of a block/edge. 674824e7fdSDimitry Andric /// Not using numeric_limits<int64_t>::max(), as the values can be summed up 684824e7fdSDimitry Andric /// during the execution. 694824e7fdSDimitry Andric static constexpr int64_t INF = ((int64_t)1) << 50; 704824e7fdSDimitry Andric 714824e7fdSDimitry Andric /// The minimum-cost maximum flow algorithm. 724824e7fdSDimitry Andric /// 734824e7fdSDimitry Andric /// The algorithm finds the maximum flow of minimum cost on a given (directed) 744824e7fdSDimitry Andric /// network using a modified version of the classical Moore-Bellman-Ford 754824e7fdSDimitry Andric /// approach. The algorithm applies a number of augmentation iterations in which 764824e7fdSDimitry Andric /// flow is sent along paths of positive capacity from the source to the sink. 774824e7fdSDimitry Andric /// The worst-case time complexity of the implementation is O(v(f)*m*n), where 784824e7fdSDimitry Andric /// where m is the number of edges, n is the number of vertices, and v(f) is the 794824e7fdSDimitry Andric /// value of the maximum flow. However, the observed running time on typical 804824e7fdSDimitry Andric /// instances is sub-quadratic, that is, o(n^2). 814824e7fdSDimitry Andric /// 824824e7fdSDimitry Andric /// The input is a set of edges with specified costs and capacities, and a pair 834824e7fdSDimitry Andric /// of nodes (source and sink). The output is the flow along each edge of the 844824e7fdSDimitry Andric /// minimum total cost respecting the given edge capacities. 854824e7fdSDimitry Andric class MinCostMaxFlow { 864824e7fdSDimitry Andric public: 87*bdd1243dSDimitry Andric MinCostMaxFlow(const ProfiParams &Params) : Params(Params) {} 88*bdd1243dSDimitry Andric 894824e7fdSDimitry Andric // Initialize algorithm's data structures for a network of a given size. 904824e7fdSDimitry Andric void initialize(uint64_t NodeCount, uint64_t SourceNode, uint64_t SinkNode) { 914824e7fdSDimitry Andric Source = SourceNode; 924824e7fdSDimitry Andric Target = SinkNode; 934824e7fdSDimitry Andric 944824e7fdSDimitry Andric Nodes = std::vector<Node>(NodeCount); 954824e7fdSDimitry Andric Edges = std::vector<std::vector<Edge>>(NodeCount, std::vector<Edge>()); 96*bdd1243dSDimitry Andric if (Params.EvenFlowDistribution) 9781ad6265SDimitry Andric AugmentingEdges = 9881ad6265SDimitry Andric std::vector<std::vector<Edge *>>(NodeCount, std::vector<Edge *>()); 994824e7fdSDimitry Andric } 1004824e7fdSDimitry Andric 1014824e7fdSDimitry Andric // Run the algorithm. 1024824e7fdSDimitry Andric int64_t run() { 103*bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Starting profi for " << Nodes.size() << " nodes\n"); 104*bdd1243dSDimitry Andric 10581ad6265SDimitry Andric // Iteratively find an augmentation path/dag in the network and send the 10681ad6265SDimitry Andric // flow along its edges 10781ad6265SDimitry Andric size_t AugmentationIters = applyFlowAugmentation(); 1084824e7fdSDimitry Andric 1094824e7fdSDimitry Andric // Compute the total flow and its cost 1104824e7fdSDimitry Andric int64_t TotalCost = 0; 1114824e7fdSDimitry Andric int64_t TotalFlow = 0; 1124824e7fdSDimitry Andric for (uint64_t Src = 0; Src < Nodes.size(); Src++) { 1134824e7fdSDimitry Andric for (auto &Edge : Edges[Src]) { 1144824e7fdSDimitry Andric if (Edge.Flow > 0) { 1154824e7fdSDimitry Andric TotalCost += Edge.Cost * Edge.Flow; 1164824e7fdSDimitry Andric if (Src == Source) 1174824e7fdSDimitry Andric TotalFlow += Edge.Flow; 1184824e7fdSDimitry Andric } 1194824e7fdSDimitry Andric } 1204824e7fdSDimitry Andric } 1214824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Completed profi after " << AugmentationIters 1224824e7fdSDimitry Andric << " iterations with " << TotalFlow << " total flow" 1234824e7fdSDimitry Andric << " of " << TotalCost << " cost\n"); 1244824e7fdSDimitry Andric (void)TotalFlow; 12581ad6265SDimitry Andric (void)AugmentationIters; 1264824e7fdSDimitry Andric return TotalCost; 1274824e7fdSDimitry Andric } 1284824e7fdSDimitry Andric 1294824e7fdSDimitry Andric /// Adding an edge to the network with a specified capacity and a cost. 1304824e7fdSDimitry Andric /// Multiple edges between a pair of nodes are allowed but self-edges 1314824e7fdSDimitry Andric /// are not supported. 1324824e7fdSDimitry Andric void addEdge(uint64_t Src, uint64_t Dst, int64_t Capacity, int64_t Cost) { 1334824e7fdSDimitry Andric assert(Capacity > 0 && "adding an edge of zero capacity"); 1344824e7fdSDimitry Andric assert(Src != Dst && "loop edge are not supported"); 1354824e7fdSDimitry Andric 1364824e7fdSDimitry Andric Edge SrcEdge; 1374824e7fdSDimitry Andric SrcEdge.Dst = Dst; 1384824e7fdSDimitry Andric SrcEdge.Cost = Cost; 1394824e7fdSDimitry Andric SrcEdge.Capacity = Capacity; 1404824e7fdSDimitry Andric SrcEdge.Flow = 0; 1414824e7fdSDimitry Andric SrcEdge.RevEdgeIndex = Edges[Dst].size(); 1424824e7fdSDimitry Andric 1434824e7fdSDimitry Andric Edge DstEdge; 1444824e7fdSDimitry Andric DstEdge.Dst = Src; 1454824e7fdSDimitry Andric DstEdge.Cost = -Cost; 1464824e7fdSDimitry Andric DstEdge.Capacity = 0; 1474824e7fdSDimitry Andric DstEdge.Flow = 0; 1484824e7fdSDimitry Andric DstEdge.RevEdgeIndex = Edges[Src].size(); 1494824e7fdSDimitry Andric 1504824e7fdSDimitry Andric Edges[Src].push_back(SrcEdge); 1514824e7fdSDimitry Andric Edges[Dst].push_back(DstEdge); 1524824e7fdSDimitry Andric } 1534824e7fdSDimitry Andric 1544824e7fdSDimitry Andric /// Adding an edge to the network of infinite capacity and a given cost. 1554824e7fdSDimitry Andric void addEdge(uint64_t Src, uint64_t Dst, int64_t Cost) { 1564824e7fdSDimitry Andric addEdge(Src, Dst, INF, Cost); 1574824e7fdSDimitry Andric } 1584824e7fdSDimitry Andric 1594824e7fdSDimitry Andric /// Get the total flow from a given source node. 1604824e7fdSDimitry Andric /// Returns a list of pairs (target node, amount of flow to the target). 1614824e7fdSDimitry Andric const std::vector<std::pair<uint64_t, int64_t>> getFlow(uint64_t Src) const { 1624824e7fdSDimitry Andric std::vector<std::pair<uint64_t, int64_t>> Flow; 163*bdd1243dSDimitry Andric for (const auto &Edge : Edges[Src]) { 1644824e7fdSDimitry Andric if (Edge.Flow > 0) 1654824e7fdSDimitry Andric Flow.push_back(std::make_pair(Edge.Dst, Edge.Flow)); 1664824e7fdSDimitry Andric } 1674824e7fdSDimitry Andric return Flow; 1684824e7fdSDimitry Andric } 1694824e7fdSDimitry Andric 1704824e7fdSDimitry Andric /// Get the total flow between a pair of nodes. 1714824e7fdSDimitry Andric int64_t getFlow(uint64_t Src, uint64_t Dst) const { 1724824e7fdSDimitry Andric int64_t Flow = 0; 173*bdd1243dSDimitry Andric for (const auto &Edge : Edges[Src]) { 1744824e7fdSDimitry Andric if (Edge.Dst == Dst) { 1754824e7fdSDimitry Andric Flow += Edge.Flow; 1764824e7fdSDimitry Andric } 1774824e7fdSDimitry Andric } 1784824e7fdSDimitry Andric return Flow; 1794824e7fdSDimitry Andric } 1804824e7fdSDimitry Andric 1814824e7fdSDimitry Andric private: 18281ad6265SDimitry Andric /// Iteratively find an augmentation path/dag in the network and send the 18381ad6265SDimitry Andric /// flow along its edges. The method returns the number of applied iterations. 18481ad6265SDimitry Andric size_t applyFlowAugmentation() { 18581ad6265SDimitry Andric size_t AugmentationIters = 0; 18681ad6265SDimitry Andric while (findAugmentingPath()) { 18781ad6265SDimitry Andric uint64_t PathCapacity = computeAugmentingPathCapacity(); 18881ad6265SDimitry Andric while (PathCapacity > 0) { 18981ad6265SDimitry Andric bool Progress = false; 190*bdd1243dSDimitry Andric if (Params.EvenFlowDistribution) { 19181ad6265SDimitry Andric // Identify node/edge candidates for augmentation 19281ad6265SDimitry Andric identifyShortestEdges(PathCapacity); 19381ad6265SDimitry Andric 19481ad6265SDimitry Andric // Find an augmenting DAG 19581ad6265SDimitry Andric auto AugmentingOrder = findAugmentingDAG(); 19681ad6265SDimitry Andric 19781ad6265SDimitry Andric // Apply the DAG augmentation 19881ad6265SDimitry Andric Progress = augmentFlowAlongDAG(AugmentingOrder); 19981ad6265SDimitry Andric PathCapacity = computeAugmentingPathCapacity(); 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric if (!Progress) { 20381ad6265SDimitry Andric augmentFlowAlongPath(PathCapacity); 20481ad6265SDimitry Andric PathCapacity = 0; 20581ad6265SDimitry Andric } 20681ad6265SDimitry Andric 20781ad6265SDimitry Andric AugmentationIters++; 20881ad6265SDimitry Andric } 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric return AugmentationIters; 21181ad6265SDimitry Andric } 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric /// Compute the capacity of the cannonical augmenting path. If the path is 21481ad6265SDimitry Andric /// saturated (that is, no flow can be sent along the path), then return 0. 21581ad6265SDimitry Andric uint64_t computeAugmentingPathCapacity() { 21681ad6265SDimitry Andric uint64_t PathCapacity = INF; 21781ad6265SDimitry Andric uint64_t Now = Target; 21881ad6265SDimitry Andric while (Now != Source) { 21981ad6265SDimitry Andric uint64_t Pred = Nodes[Now].ParentNode; 22081ad6265SDimitry Andric auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex]; 22181ad6265SDimitry Andric 22281ad6265SDimitry Andric assert(Edge.Capacity >= Edge.Flow && "incorrect edge flow"); 22381ad6265SDimitry Andric uint64_t EdgeCapacity = uint64_t(Edge.Capacity - Edge.Flow); 22481ad6265SDimitry Andric PathCapacity = std::min(PathCapacity, EdgeCapacity); 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric Now = Pred; 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric return PathCapacity; 22981ad6265SDimitry Andric } 23081ad6265SDimitry Andric 2314824e7fdSDimitry Andric /// Check for existence of an augmenting path with a positive capacity. 2324824e7fdSDimitry Andric bool findAugmentingPath() { 2334824e7fdSDimitry Andric // Initialize data structures 2344824e7fdSDimitry Andric for (auto &Node : Nodes) { 2354824e7fdSDimitry Andric Node.Distance = INF; 2364824e7fdSDimitry Andric Node.ParentNode = uint64_t(-1); 2374824e7fdSDimitry Andric Node.ParentEdgeIndex = uint64_t(-1); 2384824e7fdSDimitry Andric Node.Taken = false; 2394824e7fdSDimitry Andric } 2404824e7fdSDimitry Andric 2414824e7fdSDimitry Andric std::queue<uint64_t> Queue; 2424824e7fdSDimitry Andric Queue.push(Source); 2434824e7fdSDimitry Andric Nodes[Source].Distance = 0; 2444824e7fdSDimitry Andric Nodes[Source].Taken = true; 2454824e7fdSDimitry Andric while (!Queue.empty()) { 2464824e7fdSDimitry Andric uint64_t Src = Queue.front(); 2474824e7fdSDimitry Andric Queue.pop(); 2484824e7fdSDimitry Andric Nodes[Src].Taken = false; 2494824e7fdSDimitry Andric // Although the residual network contains edges with negative costs 2504824e7fdSDimitry Andric // (in particular, backward edges), it can be shown that there are no 2514824e7fdSDimitry Andric // negative-weight cycles and the following two invariants are maintained: 2524824e7fdSDimitry Andric // (i) Dist[Source, V] >= 0 and (ii) Dist[V, Target] >= 0 for all nodes V, 2534824e7fdSDimitry Andric // where Dist is the length of the shortest path between two nodes. This 2544824e7fdSDimitry Andric // allows to prune the search-space of the path-finding algorithm using 2554824e7fdSDimitry Andric // the following early-stop criteria: 2564824e7fdSDimitry Andric // -- If we find a path with zero-distance from Source to Target, stop the 2574824e7fdSDimitry Andric // search, as the path is the shortest since Dist[Source, Target] >= 0; 2584824e7fdSDimitry Andric // -- If we have Dist[Source, V] > Dist[Source, Target], then do not 2594824e7fdSDimitry Andric // process node V, as it is guaranteed _not_ to be on a shortest path 2604824e7fdSDimitry Andric // from Source to Target; it follows from inequalities 2614824e7fdSDimitry Andric // Dist[Source, Target] >= Dist[Source, V] + Dist[V, Target] 2624824e7fdSDimitry Andric // >= Dist[Source, V] 263*bdd1243dSDimitry Andric if (!Params.EvenFlowDistribution && Nodes[Target].Distance == 0) 2644824e7fdSDimitry Andric break; 2654824e7fdSDimitry Andric if (Nodes[Src].Distance > Nodes[Target].Distance) 2664824e7fdSDimitry Andric continue; 2674824e7fdSDimitry Andric 2684824e7fdSDimitry Andric // Process adjacent edges 2694824e7fdSDimitry Andric for (uint64_t EdgeIdx = 0; EdgeIdx < Edges[Src].size(); EdgeIdx++) { 2704824e7fdSDimitry Andric auto &Edge = Edges[Src][EdgeIdx]; 2714824e7fdSDimitry Andric if (Edge.Flow < Edge.Capacity) { 2724824e7fdSDimitry Andric uint64_t Dst = Edge.Dst; 2734824e7fdSDimitry Andric int64_t NewDistance = Nodes[Src].Distance + Edge.Cost; 2744824e7fdSDimitry Andric if (Nodes[Dst].Distance > NewDistance) { 2754824e7fdSDimitry Andric // Update the distance and the parent node/edge 2764824e7fdSDimitry Andric Nodes[Dst].Distance = NewDistance; 2774824e7fdSDimitry Andric Nodes[Dst].ParentNode = Src; 2784824e7fdSDimitry Andric Nodes[Dst].ParentEdgeIndex = EdgeIdx; 2794824e7fdSDimitry Andric // Add the node to the queue, if it is not there yet 2804824e7fdSDimitry Andric if (!Nodes[Dst].Taken) { 2814824e7fdSDimitry Andric Queue.push(Dst); 2824824e7fdSDimitry Andric Nodes[Dst].Taken = true; 2834824e7fdSDimitry Andric } 2844824e7fdSDimitry Andric } 2854824e7fdSDimitry Andric } 2864824e7fdSDimitry Andric } 2874824e7fdSDimitry Andric } 2884824e7fdSDimitry Andric 2894824e7fdSDimitry Andric return Nodes[Target].Distance != INF; 2904824e7fdSDimitry Andric } 2914824e7fdSDimitry Andric 2924824e7fdSDimitry Andric /// Update the current flow along the augmenting path. 29381ad6265SDimitry Andric void augmentFlowAlongPath(uint64_t PathCapacity) { 2940eae32dcSDimitry Andric assert(PathCapacity > 0 && "found an incorrect augmenting path"); 29581ad6265SDimitry Andric uint64_t Now = Target; 2964824e7fdSDimitry Andric while (Now != Source) { 2974824e7fdSDimitry Andric uint64_t Pred = Nodes[Now].ParentNode; 2984824e7fdSDimitry Andric auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex]; 2994824e7fdSDimitry Andric auto &RevEdge = Edges[Now][Edge.RevEdgeIndex]; 3004824e7fdSDimitry Andric 3014824e7fdSDimitry Andric Edge.Flow += PathCapacity; 3024824e7fdSDimitry Andric RevEdge.Flow -= PathCapacity; 3034824e7fdSDimitry Andric 3044824e7fdSDimitry Andric Now = Pred; 3054824e7fdSDimitry Andric } 3064824e7fdSDimitry Andric } 3074824e7fdSDimitry Andric 30881ad6265SDimitry Andric /// Find an Augmenting DAG order using a modified version of DFS in which we 30981ad6265SDimitry Andric /// can visit a node multiple times. In the DFS search, when scanning each 31081ad6265SDimitry Andric /// edge out of a node, continue search at Edge.Dst endpoint if it has not 31181ad6265SDimitry Andric /// been discovered yet and its NumCalls < MaxDfsCalls. The algorithm 31281ad6265SDimitry Andric /// runs in O(MaxDfsCalls * |Edges| + |Nodes|) time. 31381ad6265SDimitry Andric /// It returns an Augmenting Order (Taken nodes in decreasing Finish time) 31481ad6265SDimitry Andric /// that starts with Source and ends with Target. 31581ad6265SDimitry Andric std::vector<uint64_t> findAugmentingDAG() { 31681ad6265SDimitry Andric // We use a stack based implemenation of DFS to avoid recursion. 31781ad6265SDimitry Andric // Defining DFS data structures: 31881ad6265SDimitry Andric // A pair (NodeIdx, EdgeIdx) at the top of the Stack denotes that 31981ad6265SDimitry Andric // - we are currently visiting Nodes[NodeIdx] and 32081ad6265SDimitry Andric // - the next edge to scan is Edges[NodeIdx][EdgeIdx] 32181ad6265SDimitry Andric typedef std::pair<uint64_t, uint64_t> StackItemType; 32281ad6265SDimitry Andric std::stack<StackItemType> Stack; 32381ad6265SDimitry Andric std::vector<uint64_t> AugmentingOrder; 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric // Phase 0: Initialize Node attributes and Time for DFS run 32681ad6265SDimitry Andric for (auto &Node : Nodes) { 32781ad6265SDimitry Andric Node.Discovery = 0; 32881ad6265SDimitry Andric Node.Finish = 0; 32981ad6265SDimitry Andric Node.NumCalls = 0; 33081ad6265SDimitry Andric Node.Taken = false; 33181ad6265SDimitry Andric } 33281ad6265SDimitry Andric uint64_t Time = 0; 33381ad6265SDimitry Andric // Mark Target as Taken 33481ad6265SDimitry Andric // Taken attribute will be propagated backwards from Target towards Source 33581ad6265SDimitry Andric Nodes[Target].Taken = true; 33681ad6265SDimitry Andric 33781ad6265SDimitry Andric // Phase 1: Start DFS traversal from Source 33881ad6265SDimitry Andric Stack.emplace(Source, 0); 33981ad6265SDimitry Andric Nodes[Source].Discovery = ++Time; 34081ad6265SDimitry Andric while (!Stack.empty()) { 34181ad6265SDimitry Andric auto NodeIdx = Stack.top().first; 34281ad6265SDimitry Andric auto EdgeIdx = Stack.top().second; 34381ad6265SDimitry Andric 34481ad6265SDimitry Andric // If we haven't scanned all edges out of NodeIdx, continue scanning 34581ad6265SDimitry Andric if (EdgeIdx < Edges[NodeIdx].size()) { 34681ad6265SDimitry Andric auto &Edge = Edges[NodeIdx][EdgeIdx]; 34781ad6265SDimitry Andric auto &Dst = Nodes[Edge.Dst]; 34881ad6265SDimitry Andric Stack.top().second++; 34981ad6265SDimitry Andric 35081ad6265SDimitry Andric if (Edge.OnShortestPath) { 35181ad6265SDimitry Andric // If we haven't seen Edge.Dst so far, continue DFS search there 352*bdd1243dSDimitry Andric if (Dst.Discovery == 0 && Dst.NumCalls < MaxDfsCalls) { 35381ad6265SDimitry Andric Dst.Discovery = ++Time; 35481ad6265SDimitry Andric Stack.emplace(Edge.Dst, 0); 35581ad6265SDimitry Andric Dst.NumCalls++; 35681ad6265SDimitry Andric } else if (Dst.Taken && Dst.Finish != 0) { 35781ad6265SDimitry Andric // Else, if Edge.Dst already have a path to Target, so that NodeIdx 35881ad6265SDimitry Andric Nodes[NodeIdx].Taken = true; 35981ad6265SDimitry Andric } 36081ad6265SDimitry Andric } 36181ad6265SDimitry Andric } else { 36281ad6265SDimitry Andric // If we are done scanning all edge out of NodeIdx 36381ad6265SDimitry Andric Stack.pop(); 36481ad6265SDimitry Andric // If we haven't found a path from NodeIdx to Target, forget about it 36581ad6265SDimitry Andric if (!Nodes[NodeIdx].Taken) { 36681ad6265SDimitry Andric Nodes[NodeIdx].Discovery = 0; 36781ad6265SDimitry Andric } else { 36881ad6265SDimitry Andric // If we have found a path from NodeIdx to Target, then finish NodeIdx 36981ad6265SDimitry Andric // and propagate Taken flag to DFS parent unless at the Source 37081ad6265SDimitry Andric Nodes[NodeIdx].Finish = ++Time; 37181ad6265SDimitry Andric // NodeIdx == Source if and only if the stack is empty 37281ad6265SDimitry Andric if (NodeIdx != Source) { 37381ad6265SDimitry Andric assert(!Stack.empty() && "empty stack while running dfs"); 37481ad6265SDimitry Andric Nodes[Stack.top().first].Taken = true; 37581ad6265SDimitry Andric } 37681ad6265SDimitry Andric AugmentingOrder.push_back(NodeIdx); 37781ad6265SDimitry Andric } 37881ad6265SDimitry Andric } 37981ad6265SDimitry Andric } 38081ad6265SDimitry Andric // Nodes are collected decreasing Finish time, so the order is reversed 38181ad6265SDimitry Andric std::reverse(AugmentingOrder.begin(), AugmentingOrder.end()); 38281ad6265SDimitry Andric 38381ad6265SDimitry Andric // Phase 2: Extract all forward (DAG) edges and fill in AugmentingEdges 38481ad6265SDimitry Andric for (size_t Src : AugmentingOrder) { 38581ad6265SDimitry Andric AugmentingEdges[Src].clear(); 38681ad6265SDimitry Andric for (auto &Edge : Edges[Src]) { 38781ad6265SDimitry Andric uint64_t Dst = Edge.Dst; 38881ad6265SDimitry Andric if (Edge.OnShortestPath && Nodes[Src].Taken && Nodes[Dst].Taken && 38981ad6265SDimitry Andric Nodes[Dst].Finish < Nodes[Src].Finish) { 39081ad6265SDimitry Andric AugmentingEdges[Src].push_back(&Edge); 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric } 39381ad6265SDimitry Andric assert((Src == Target || !AugmentingEdges[Src].empty()) && 39481ad6265SDimitry Andric "incorrectly constructed augmenting edges"); 39581ad6265SDimitry Andric } 39681ad6265SDimitry Andric 39781ad6265SDimitry Andric return AugmentingOrder; 39881ad6265SDimitry Andric } 39981ad6265SDimitry Andric 40081ad6265SDimitry Andric /// Update the current flow along the given (acyclic) subgraph specified by 40181ad6265SDimitry Andric /// the vertex order, AugmentingOrder. The objective is to send as much flow 40281ad6265SDimitry Andric /// as possible while evenly distributing flow among successors of each node. 40381ad6265SDimitry Andric /// After the update at least one edge is saturated. 40481ad6265SDimitry Andric bool augmentFlowAlongDAG(const std::vector<uint64_t> &AugmentingOrder) { 40581ad6265SDimitry Andric // Phase 0: Initialization 40681ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 40781ad6265SDimitry Andric Nodes[Src].FracFlow = 0; 40881ad6265SDimitry Andric Nodes[Src].IntFlow = 0; 40981ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 41081ad6265SDimitry Andric Edge->AugmentedFlow = 0; 41181ad6265SDimitry Andric } 41281ad6265SDimitry Andric } 41381ad6265SDimitry Andric 41481ad6265SDimitry Andric // Phase 1: Send a unit of fractional flow along the DAG 41581ad6265SDimitry Andric uint64_t MaxFlowAmount = INF; 41681ad6265SDimitry Andric Nodes[Source].FracFlow = 1.0; 41781ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 41881ad6265SDimitry Andric assert((Src == Target || Nodes[Src].FracFlow > 0.0) && 41981ad6265SDimitry Andric "incorrectly computed fractional flow"); 42081ad6265SDimitry Andric // Distribute flow evenly among successors of Src 42181ad6265SDimitry Andric uint64_t Degree = AugmentingEdges[Src].size(); 42281ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 42381ad6265SDimitry Andric double EdgeFlow = Nodes[Src].FracFlow / Degree; 42481ad6265SDimitry Andric Nodes[Edge->Dst].FracFlow += EdgeFlow; 42581ad6265SDimitry Andric if (Edge->Capacity == INF) 42681ad6265SDimitry Andric continue; 42781ad6265SDimitry Andric uint64_t MaxIntFlow = double(Edge->Capacity - Edge->Flow) / EdgeFlow; 42881ad6265SDimitry Andric MaxFlowAmount = std::min(MaxFlowAmount, MaxIntFlow); 42981ad6265SDimitry Andric } 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric // Stop early if we cannot send any (integral) flow from Source to Target 43281ad6265SDimitry Andric if (MaxFlowAmount == 0) 43381ad6265SDimitry Andric return false; 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric // Phase 2: Send an integral flow of MaxFlowAmount 43681ad6265SDimitry Andric Nodes[Source].IntFlow = MaxFlowAmount; 43781ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 43881ad6265SDimitry Andric if (Src == Target) 43981ad6265SDimitry Andric break; 44081ad6265SDimitry Andric // Distribute flow evenly among successors of Src, rounding up to make 44181ad6265SDimitry Andric // sure all flow is sent 44281ad6265SDimitry Andric uint64_t Degree = AugmentingEdges[Src].size(); 44381ad6265SDimitry Andric // We are guaranteeed that Node[Src].IntFlow <= SuccFlow * Degree 44481ad6265SDimitry Andric uint64_t SuccFlow = (Nodes[Src].IntFlow + Degree - 1) / Degree; 44581ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 44681ad6265SDimitry Andric uint64_t Dst = Edge->Dst; 44781ad6265SDimitry Andric uint64_t EdgeFlow = std::min(Nodes[Src].IntFlow, SuccFlow); 44881ad6265SDimitry Andric EdgeFlow = std::min(EdgeFlow, uint64_t(Edge->Capacity - Edge->Flow)); 44981ad6265SDimitry Andric Nodes[Dst].IntFlow += EdgeFlow; 45081ad6265SDimitry Andric Nodes[Src].IntFlow -= EdgeFlow; 45181ad6265SDimitry Andric Edge->AugmentedFlow += EdgeFlow; 45281ad6265SDimitry Andric } 45381ad6265SDimitry Andric } 45481ad6265SDimitry Andric assert(Nodes[Target].IntFlow <= MaxFlowAmount); 45581ad6265SDimitry Andric Nodes[Target].IntFlow = 0; 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric // Phase 3: Send excess flow back traversing the nodes backwards. 45881ad6265SDimitry Andric // Because of rounding, not all flow can be sent along the edges of Src. 45981ad6265SDimitry Andric // Hence, sending the remaining flow back to maintain flow conservation 46081ad6265SDimitry Andric for (size_t Idx = AugmentingOrder.size() - 1; Idx > 0; Idx--) { 46181ad6265SDimitry Andric uint64_t Src = AugmentingOrder[Idx - 1]; 46281ad6265SDimitry Andric // Try to send excess flow back along each edge. 46381ad6265SDimitry Andric // Make sure we only send back flow we just augmented (AugmentedFlow). 46481ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 46581ad6265SDimitry Andric uint64_t Dst = Edge->Dst; 46681ad6265SDimitry Andric if (Nodes[Dst].IntFlow == 0) 46781ad6265SDimitry Andric continue; 46881ad6265SDimitry Andric uint64_t EdgeFlow = std::min(Nodes[Dst].IntFlow, Edge->AugmentedFlow); 46981ad6265SDimitry Andric Nodes[Dst].IntFlow -= EdgeFlow; 47081ad6265SDimitry Andric Nodes[Src].IntFlow += EdgeFlow; 47181ad6265SDimitry Andric Edge->AugmentedFlow -= EdgeFlow; 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric } 47481ad6265SDimitry Andric 47581ad6265SDimitry Andric // Phase 4: Update flow values along all edges 47681ad6265SDimitry Andric bool HasSaturatedEdges = false; 47781ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 47881ad6265SDimitry Andric // Verify that we have sent all the excess flow from the node 47981ad6265SDimitry Andric assert(Src == Source || Nodes[Src].IntFlow == 0); 48081ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 48181ad6265SDimitry Andric assert(uint64_t(Edge->Capacity - Edge->Flow) >= Edge->AugmentedFlow); 48281ad6265SDimitry Andric // Update flow values along the edge and its reverse copy 48381ad6265SDimitry Andric auto &RevEdge = Edges[Edge->Dst][Edge->RevEdgeIndex]; 48481ad6265SDimitry Andric Edge->Flow += Edge->AugmentedFlow; 48581ad6265SDimitry Andric RevEdge.Flow -= Edge->AugmentedFlow; 48681ad6265SDimitry Andric if (Edge->Capacity == Edge->Flow && Edge->AugmentedFlow > 0) 48781ad6265SDimitry Andric HasSaturatedEdges = true; 48881ad6265SDimitry Andric } 48981ad6265SDimitry Andric } 49081ad6265SDimitry Andric 49181ad6265SDimitry Andric // The augmentation is successful iff at least one edge becomes saturated 49281ad6265SDimitry Andric return HasSaturatedEdges; 49381ad6265SDimitry Andric } 49481ad6265SDimitry Andric 49581ad6265SDimitry Andric /// Identify candidate (shortest) edges for augmentation. 49681ad6265SDimitry Andric void identifyShortestEdges(uint64_t PathCapacity) { 49781ad6265SDimitry Andric assert(PathCapacity > 0 && "found an incorrect augmenting DAG"); 49881ad6265SDimitry Andric // To make sure the augmentation DAG contains only edges with large residual 49981ad6265SDimitry Andric // capacity, we prune all edges whose capacity is below a fraction of 50081ad6265SDimitry Andric // the capacity of the augmented path. 50181ad6265SDimitry Andric // (All edges of the path itself are always in the DAG) 50281ad6265SDimitry Andric uint64_t MinCapacity = std::max(PathCapacity / 2, uint64_t(1)); 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric // Decide which edges are on a shortest path from Source to Target 50581ad6265SDimitry Andric for (size_t Src = 0; Src < Nodes.size(); Src++) { 50681ad6265SDimitry Andric // An edge cannot be augmenting if the endpoint has large distance 50781ad6265SDimitry Andric if (Nodes[Src].Distance > Nodes[Target].Distance) 50881ad6265SDimitry Andric continue; 50981ad6265SDimitry Andric 51081ad6265SDimitry Andric for (auto &Edge : Edges[Src]) { 51181ad6265SDimitry Andric uint64_t Dst = Edge.Dst; 51281ad6265SDimitry Andric Edge.OnShortestPath = 51381ad6265SDimitry Andric Src != Target && Dst != Source && 51481ad6265SDimitry Andric Nodes[Dst].Distance <= Nodes[Target].Distance && 51581ad6265SDimitry Andric Nodes[Dst].Distance == Nodes[Src].Distance + Edge.Cost && 51681ad6265SDimitry Andric Edge.Capacity > Edge.Flow && 51781ad6265SDimitry Andric uint64_t(Edge.Capacity - Edge.Flow) >= MinCapacity; 51881ad6265SDimitry Andric } 51981ad6265SDimitry Andric } 52081ad6265SDimitry Andric } 52181ad6265SDimitry Andric 522*bdd1243dSDimitry Andric /// Maximum number of DFS iterations for DAG finding. 523*bdd1243dSDimitry Andric static constexpr uint64_t MaxDfsCalls = 10; 524*bdd1243dSDimitry Andric 52504eeddc0SDimitry Andric /// A node in a flow network. 5264824e7fdSDimitry Andric struct Node { 5274824e7fdSDimitry Andric /// The cost of the cheapest path from the source to the current node. 5284824e7fdSDimitry Andric int64_t Distance; 5294824e7fdSDimitry Andric /// The node preceding the current one in the path. 5304824e7fdSDimitry Andric uint64_t ParentNode; 5314824e7fdSDimitry Andric /// The index of the edge between ParentNode and the current node. 5324824e7fdSDimitry Andric uint64_t ParentEdgeIndex; 5334824e7fdSDimitry Andric /// An indicator of whether the current node is in a queue. 5344824e7fdSDimitry Andric bool Taken; 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric /// Data fields utilized in DAG-augmentation: 53781ad6265SDimitry Andric /// Fractional flow. 53881ad6265SDimitry Andric double FracFlow; 53981ad6265SDimitry Andric /// Integral flow. 54081ad6265SDimitry Andric uint64_t IntFlow; 54181ad6265SDimitry Andric /// Discovery time. 54281ad6265SDimitry Andric uint64_t Discovery; 54381ad6265SDimitry Andric /// Finish time. 54481ad6265SDimitry Andric uint64_t Finish; 54581ad6265SDimitry Andric /// NumCalls. 54681ad6265SDimitry Andric uint64_t NumCalls; 5474824e7fdSDimitry Andric }; 54881ad6265SDimitry Andric 5494824e7fdSDimitry Andric /// An edge in a flow network. 5504824e7fdSDimitry Andric struct Edge { 5514824e7fdSDimitry Andric /// The cost of the edge. 5524824e7fdSDimitry Andric int64_t Cost; 5534824e7fdSDimitry Andric /// The capacity of the edge. 5544824e7fdSDimitry Andric int64_t Capacity; 5554824e7fdSDimitry Andric /// The current flow on the edge. 5564824e7fdSDimitry Andric int64_t Flow; 5574824e7fdSDimitry Andric /// The destination node of the edge. 5584824e7fdSDimitry Andric uint64_t Dst; 5594824e7fdSDimitry Andric /// The index of the reverse edge between Dst and the current node. 5604824e7fdSDimitry Andric uint64_t RevEdgeIndex; 56181ad6265SDimitry Andric 56281ad6265SDimitry Andric /// Data fields utilized in DAG-augmentation: 56381ad6265SDimitry Andric /// Whether the edge is currently on a shortest path from Source to Target. 56481ad6265SDimitry Andric bool OnShortestPath; 56581ad6265SDimitry Andric /// Extra flow along the edge. 56681ad6265SDimitry Andric uint64_t AugmentedFlow; 5674824e7fdSDimitry Andric }; 5684824e7fdSDimitry Andric 5694824e7fdSDimitry Andric /// The set of network nodes. 5704824e7fdSDimitry Andric std::vector<Node> Nodes; 5714824e7fdSDimitry Andric /// The set of network edges. 5724824e7fdSDimitry Andric std::vector<std::vector<Edge>> Edges; 5734824e7fdSDimitry Andric /// Source node of the flow. 5744824e7fdSDimitry Andric uint64_t Source; 5754824e7fdSDimitry Andric /// Target (sink) node of the flow. 5764824e7fdSDimitry Andric uint64_t Target; 57781ad6265SDimitry Andric /// Augmenting edges. 57881ad6265SDimitry Andric std::vector<std::vector<Edge *>> AugmentingEdges; 579*bdd1243dSDimitry Andric /// Params for flow computation. 580*bdd1243dSDimitry Andric const ProfiParams &Params; 5814824e7fdSDimitry Andric }; 5824824e7fdSDimitry Andric 583*bdd1243dSDimitry Andric /// A post-processing adjustment of the control flow. It applies two steps by 5840eae32dcSDimitry Andric /// rerouting some flow and making it more realistic: 5850eae32dcSDimitry Andric /// 5860eae32dcSDimitry Andric /// - First, it removes all isolated components ("islands") with a positive flow 5870eae32dcSDimitry Andric /// that are unreachable from the entry block. For every such component, we 5880eae32dcSDimitry Andric /// find the shortest from the entry to an exit passing through the component, 5890eae32dcSDimitry Andric /// and increase the flow by one unit along the path. 5900eae32dcSDimitry Andric /// 5910eae32dcSDimitry Andric /// - Second, it identifies all "unknown subgraphs" consisting of basic blocks 5920eae32dcSDimitry Andric /// with no sampled counts. Then it rebalnces the flow that goes through such 5930eae32dcSDimitry Andric /// a subgraph so that each branch is taken with probability 50%. 5940eae32dcSDimitry Andric /// An unknown subgraph is such that for every two nodes u and v: 5950eae32dcSDimitry Andric /// - u dominates v and u is not unknown; 5960eae32dcSDimitry Andric /// - v post-dominates u; and 5970eae32dcSDimitry Andric /// - all inner-nodes of all (u,v)-paths are unknown. 5980eae32dcSDimitry Andric /// 5990eae32dcSDimitry Andric class FlowAdjuster { 6000eae32dcSDimitry Andric public: 601*bdd1243dSDimitry Andric FlowAdjuster(const ProfiParams &Params, FlowFunction &Func) 602*bdd1243dSDimitry Andric : Params(Params), Func(Func) {} 603*bdd1243dSDimitry Andric 604*bdd1243dSDimitry Andric /// Apply the post-processing. 605*bdd1243dSDimitry Andric void run() { 606*bdd1243dSDimitry Andric if (Params.JoinIslands) { 607*bdd1243dSDimitry Andric // Adjust the flow to get rid of isolated components 608*bdd1243dSDimitry Andric joinIsolatedComponents(); 6090eae32dcSDimitry Andric } 6100eae32dcSDimitry Andric 611*bdd1243dSDimitry Andric if (Params.RebalanceUnknown) { 612*bdd1243dSDimitry Andric // Rebalance the flow inside unknown subgraphs 6130eae32dcSDimitry Andric rebalanceUnknownSubgraphs(); 6140eae32dcSDimitry Andric } 615*bdd1243dSDimitry Andric } 6160eae32dcSDimitry Andric 6170eae32dcSDimitry Andric private: 6180eae32dcSDimitry Andric void joinIsolatedComponents() { 6190eae32dcSDimitry Andric // Find blocks that are reachable from the source 62004eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks(), false); 6210eae32dcSDimitry Andric findReachable(Func.Entry, Visited); 6220eae32dcSDimitry Andric 6230eae32dcSDimitry Andric // Iterate over all non-reachable blocks and adjust their weights 6240eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks(); I++) { 6250eae32dcSDimitry Andric auto &Block = Func.Blocks[I]; 6260eae32dcSDimitry Andric if (Block.Flow > 0 && !Visited[I]) { 6270eae32dcSDimitry Andric // Find a path from the entry to an exit passing through the block I 6280eae32dcSDimitry Andric auto Path = findShortestPath(I); 6290eae32dcSDimitry Andric // Increase the flow along the path 6300eae32dcSDimitry Andric assert(Path.size() > 0 && Path[0]->Source == Func.Entry && 6310eae32dcSDimitry Andric "incorrectly computed path adjusting control flow"); 6320eae32dcSDimitry Andric Func.Blocks[Func.Entry].Flow += 1; 6330eae32dcSDimitry Andric for (auto &Jump : Path) { 6340eae32dcSDimitry Andric Jump->Flow += 1; 6350eae32dcSDimitry Andric Func.Blocks[Jump->Target].Flow += 1; 6360eae32dcSDimitry Andric // Update reachability 6370eae32dcSDimitry Andric findReachable(Jump->Target, Visited); 6380eae32dcSDimitry Andric } 6390eae32dcSDimitry Andric } 6400eae32dcSDimitry Andric } 6410eae32dcSDimitry Andric } 6420eae32dcSDimitry Andric 6430eae32dcSDimitry Andric /// Run BFS from a given block along the jumps with a positive flow and mark 6440eae32dcSDimitry Andric /// all reachable blocks. 64504eeddc0SDimitry Andric void findReachable(uint64_t Src, BitVector &Visited) { 6460eae32dcSDimitry Andric if (Visited[Src]) 6470eae32dcSDimitry Andric return; 6480eae32dcSDimitry Andric std::queue<uint64_t> Queue; 6490eae32dcSDimitry Andric Queue.push(Src); 6500eae32dcSDimitry Andric Visited[Src] = true; 6510eae32dcSDimitry Andric while (!Queue.empty()) { 6520eae32dcSDimitry Andric Src = Queue.front(); 6530eae32dcSDimitry Andric Queue.pop(); 654*bdd1243dSDimitry Andric for (auto *Jump : Func.Blocks[Src].SuccJumps) { 6550eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 6560eae32dcSDimitry Andric if (Jump->Flow > 0 && !Visited[Dst]) { 6570eae32dcSDimitry Andric Queue.push(Dst); 6580eae32dcSDimitry Andric Visited[Dst] = true; 6590eae32dcSDimitry Andric } 6600eae32dcSDimitry Andric } 6610eae32dcSDimitry Andric } 6620eae32dcSDimitry Andric } 6630eae32dcSDimitry Andric 6640eae32dcSDimitry Andric /// Find the shortest path from the entry block to an exit block passing 6650eae32dcSDimitry Andric /// through a given block. 6660eae32dcSDimitry Andric std::vector<FlowJump *> findShortestPath(uint64_t BlockIdx) { 6670eae32dcSDimitry Andric // A path from the entry block to BlockIdx 6680eae32dcSDimitry Andric auto ForwardPath = findShortestPath(Func.Entry, BlockIdx); 6690eae32dcSDimitry Andric // A path from BlockIdx to an exit block 6700eae32dcSDimitry Andric auto BackwardPath = findShortestPath(BlockIdx, AnyExitBlock); 6710eae32dcSDimitry Andric 6720eae32dcSDimitry Andric // Concatenate the two paths 6730eae32dcSDimitry Andric std::vector<FlowJump *> Result; 6740eae32dcSDimitry Andric Result.insert(Result.end(), ForwardPath.begin(), ForwardPath.end()); 6750eae32dcSDimitry Andric Result.insert(Result.end(), BackwardPath.begin(), BackwardPath.end()); 6760eae32dcSDimitry Andric return Result; 6770eae32dcSDimitry Andric } 6780eae32dcSDimitry Andric 6790eae32dcSDimitry Andric /// Apply the Dijkstra algorithm to find the shortest path from a given 6800eae32dcSDimitry Andric /// Source to a given Target block. 6810eae32dcSDimitry Andric /// If Target == -1, then the path ends at an exit block. 6820eae32dcSDimitry Andric std::vector<FlowJump *> findShortestPath(uint64_t Source, uint64_t Target) { 6830eae32dcSDimitry Andric // Quit early, if possible 6840eae32dcSDimitry Andric if (Source == Target) 6850eae32dcSDimitry Andric return std::vector<FlowJump *>(); 6860eae32dcSDimitry Andric if (Func.Blocks[Source].isExit() && Target == AnyExitBlock) 6870eae32dcSDimitry Andric return std::vector<FlowJump *>(); 6880eae32dcSDimitry Andric 6890eae32dcSDimitry Andric // Initialize data structures 6900eae32dcSDimitry Andric auto Distance = std::vector<int64_t>(NumBlocks(), INF); 6910eae32dcSDimitry Andric auto Parent = std::vector<FlowJump *>(NumBlocks(), nullptr); 6920eae32dcSDimitry Andric Distance[Source] = 0; 6930eae32dcSDimitry Andric std::set<std::pair<uint64_t, uint64_t>> Queue; 6940eae32dcSDimitry Andric Queue.insert(std::make_pair(Distance[Source], Source)); 6950eae32dcSDimitry Andric 6960eae32dcSDimitry Andric // Run the Dijkstra algorithm 6970eae32dcSDimitry Andric while (!Queue.empty()) { 6980eae32dcSDimitry Andric uint64_t Src = Queue.begin()->second; 6990eae32dcSDimitry Andric Queue.erase(Queue.begin()); 7000eae32dcSDimitry Andric // If we found a solution, quit early 7010eae32dcSDimitry Andric if (Src == Target || 7020eae32dcSDimitry Andric (Func.Blocks[Src].isExit() && Target == AnyExitBlock)) 7030eae32dcSDimitry Andric break; 7040eae32dcSDimitry Andric 705*bdd1243dSDimitry Andric for (auto *Jump : Func.Blocks[Src].SuccJumps) { 7060eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 7070eae32dcSDimitry Andric int64_t JumpDist = jumpDistance(Jump); 7080eae32dcSDimitry Andric if (Distance[Dst] > Distance[Src] + JumpDist) { 7090eae32dcSDimitry Andric Queue.erase(std::make_pair(Distance[Dst], Dst)); 7100eae32dcSDimitry Andric 7110eae32dcSDimitry Andric Distance[Dst] = Distance[Src] + JumpDist; 7120eae32dcSDimitry Andric Parent[Dst] = Jump; 7130eae32dcSDimitry Andric 7140eae32dcSDimitry Andric Queue.insert(std::make_pair(Distance[Dst], Dst)); 7150eae32dcSDimitry Andric } 7160eae32dcSDimitry Andric } 7170eae32dcSDimitry Andric } 7180eae32dcSDimitry Andric // If Target is not provided, find the closest exit block 7190eae32dcSDimitry Andric if (Target == AnyExitBlock) { 7200eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks(); I++) { 7210eae32dcSDimitry Andric if (Func.Blocks[I].isExit() && Parent[I] != nullptr) { 7220eae32dcSDimitry Andric if (Target == AnyExitBlock || Distance[Target] > Distance[I]) { 7230eae32dcSDimitry Andric Target = I; 7240eae32dcSDimitry Andric } 7250eae32dcSDimitry Andric } 7260eae32dcSDimitry Andric } 7270eae32dcSDimitry Andric } 7280eae32dcSDimitry Andric assert(Parent[Target] != nullptr && "a path does not exist"); 7290eae32dcSDimitry Andric 7300eae32dcSDimitry Andric // Extract the constructed path 7310eae32dcSDimitry Andric std::vector<FlowJump *> Result; 7320eae32dcSDimitry Andric uint64_t Now = Target; 7330eae32dcSDimitry Andric while (Now != Source) { 7340eae32dcSDimitry Andric assert(Now == Parent[Now]->Target && "incorrect parent jump"); 7350eae32dcSDimitry Andric Result.push_back(Parent[Now]); 7360eae32dcSDimitry Andric Now = Parent[Now]->Source; 7370eae32dcSDimitry Andric } 7380eae32dcSDimitry Andric // Reverse the path, since it is extracted from Target to Source 7390eae32dcSDimitry Andric std::reverse(Result.begin(), Result.end()); 7400eae32dcSDimitry Andric return Result; 7410eae32dcSDimitry Andric } 7420eae32dcSDimitry Andric 7430eae32dcSDimitry Andric /// A distance of a path for a given jump. 7440eae32dcSDimitry Andric /// In order to incite the path to use blocks/jumps with large positive flow, 7450eae32dcSDimitry Andric /// and avoid changing branch probability of outgoing edges drastically, 74681ad6265SDimitry Andric /// set the jump distance so as: 74781ad6265SDimitry Andric /// - to minimize the number of unlikely jumps used and subject to that, 74881ad6265SDimitry Andric /// - to minimize the number of Flow == 0 jumps used and subject to that, 74981ad6265SDimitry Andric /// - minimizes total multiplicative Flow increase for the remaining edges. 75081ad6265SDimitry Andric /// To capture this objective with integer distances, we round off fractional 75181ad6265SDimitry Andric /// parts to a multiple of 1 / BaseDistance. 7520eae32dcSDimitry Andric int64_t jumpDistance(FlowJump *Jump) const { 7530eae32dcSDimitry Andric if (Jump->IsUnlikely) 754*bdd1243dSDimitry Andric return Params.CostUnlikely; 755*bdd1243dSDimitry Andric uint64_t BaseDistance = 756*bdd1243dSDimitry Andric std::max(FlowAdjuster::MinBaseDistance, 757*bdd1243dSDimitry Andric std::min(Func.Blocks[Func.Entry].Flow, 758*bdd1243dSDimitry Andric Params.CostUnlikely / (2 * (NumBlocks() + 1)))); 7590eae32dcSDimitry Andric if (Jump->Flow > 0) 76081ad6265SDimitry Andric return BaseDistance + BaseDistance / Jump->Flow; 761*bdd1243dSDimitry Andric return 2 * BaseDistance * (NumBlocks() + 1); 7620eae32dcSDimitry Andric }; 7630eae32dcSDimitry Andric 7640eae32dcSDimitry Andric uint64_t NumBlocks() const { return Func.Blocks.size(); } 7650eae32dcSDimitry Andric 76604eeddc0SDimitry Andric /// Rebalance unknown subgraphs so that the flow is split evenly across the 76704eeddc0SDimitry Andric /// outgoing branches of every block of the subgraph. The method iterates over 76804eeddc0SDimitry Andric /// blocks with known weight and identifies unknown subgraphs rooted at the 76904eeddc0SDimitry Andric /// blocks. Then it verifies if flow rebalancing is feasible and applies it. 7700eae32dcSDimitry Andric void rebalanceUnknownSubgraphs() { 77104eeddc0SDimitry Andric // Try to find unknown subgraphs from each block 772*bdd1243dSDimitry Andric for (const FlowBlock &SrcBlock : Func.Blocks) { 77304eeddc0SDimitry Andric // Verify if rebalancing rooted at SrcBlock is feasible 774*bdd1243dSDimitry Andric if (!canRebalanceAtRoot(&SrcBlock)) 7750eae32dcSDimitry Andric continue; 7760eae32dcSDimitry Andric 77704eeddc0SDimitry Andric // Find an unknown subgraphs starting at SrcBlock. Along the way, 77804eeddc0SDimitry Andric // fill in known destinations and intermediate unknown blocks. 77904eeddc0SDimitry Andric std::vector<FlowBlock *> UnknownBlocks; 78004eeddc0SDimitry Andric std::vector<FlowBlock *> KnownDstBlocks; 781*bdd1243dSDimitry Andric findUnknownSubgraph(&SrcBlock, KnownDstBlocks, UnknownBlocks); 78204eeddc0SDimitry Andric 78304eeddc0SDimitry Andric // Verify if rebalancing of the subgraph is feasible. If the search is 78404eeddc0SDimitry Andric // successful, find the unique destination block (which can be null) 7850eae32dcSDimitry Andric FlowBlock *DstBlock = nullptr; 786*bdd1243dSDimitry Andric if (!canRebalanceSubgraph(&SrcBlock, KnownDstBlocks, UnknownBlocks, 78704eeddc0SDimitry Andric DstBlock)) 7880eae32dcSDimitry Andric continue; 78904eeddc0SDimitry Andric 79004eeddc0SDimitry Andric // We cannot rebalance subgraphs containing cycles among unknown blocks 791*bdd1243dSDimitry Andric if (!isAcyclicSubgraph(&SrcBlock, DstBlock, UnknownBlocks)) 7920eae32dcSDimitry Andric continue; 7930eae32dcSDimitry Andric 7940eae32dcSDimitry Andric // Rebalance the flow 795*bdd1243dSDimitry Andric rebalanceUnknownSubgraph(&SrcBlock, DstBlock, UnknownBlocks); 7960eae32dcSDimitry Andric } 7970eae32dcSDimitry Andric } 7980eae32dcSDimitry Andric 79904eeddc0SDimitry Andric /// Verify if rebalancing rooted at a given block is possible. 80004eeddc0SDimitry Andric bool canRebalanceAtRoot(const FlowBlock *SrcBlock) { 80104eeddc0SDimitry Andric // Do not attempt to find unknown subgraphs from an unknown or a 80204eeddc0SDimitry Andric // zero-flow block 803*bdd1243dSDimitry Andric if (SrcBlock->HasUnknownWeight || SrcBlock->Flow == 0) 80404eeddc0SDimitry Andric return false; 80504eeddc0SDimitry Andric 80604eeddc0SDimitry Andric // Do not attempt to process subgraphs from a block w/o unknown sucessors 80704eeddc0SDimitry Andric bool HasUnknownSuccs = false; 808*bdd1243dSDimitry Andric for (auto *Jump : SrcBlock->SuccJumps) { 809*bdd1243dSDimitry Andric if (Func.Blocks[Jump->Target].HasUnknownWeight) { 81004eeddc0SDimitry Andric HasUnknownSuccs = true; 81104eeddc0SDimitry Andric break; 81204eeddc0SDimitry Andric } 81304eeddc0SDimitry Andric } 81404eeddc0SDimitry Andric if (!HasUnknownSuccs) 81504eeddc0SDimitry Andric return false; 81604eeddc0SDimitry Andric 81704eeddc0SDimitry Andric return true; 81804eeddc0SDimitry Andric } 81904eeddc0SDimitry Andric 82004eeddc0SDimitry Andric /// Find an unknown subgraph starting at block SrcBlock. The method sets 82104eeddc0SDimitry Andric /// identified destinations, KnownDstBlocks, and intermediate UnknownBlocks. 82204eeddc0SDimitry Andric void findUnknownSubgraph(const FlowBlock *SrcBlock, 82304eeddc0SDimitry Andric std::vector<FlowBlock *> &KnownDstBlocks, 82404eeddc0SDimitry Andric std::vector<FlowBlock *> &UnknownBlocks) { 8250eae32dcSDimitry Andric // Run BFS from SrcBlock and make sure all paths are going through unknown 82681ad6265SDimitry Andric // blocks and end at a known DstBlock 82704eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks(), false); 8280eae32dcSDimitry Andric std::queue<uint64_t> Queue; 8290eae32dcSDimitry Andric 8300eae32dcSDimitry Andric Queue.push(SrcBlock->Index); 8310eae32dcSDimitry Andric Visited[SrcBlock->Index] = true; 8320eae32dcSDimitry Andric while (!Queue.empty()) { 8330eae32dcSDimitry Andric auto &Block = Func.Blocks[Queue.front()]; 8340eae32dcSDimitry Andric Queue.pop(); 8350eae32dcSDimitry Andric // Process blocks reachable from Block 836*bdd1243dSDimitry Andric for (auto *Jump : Block.SuccJumps) { 83704eeddc0SDimitry Andric // If Jump can be ignored, skip it 83804eeddc0SDimitry Andric if (ignoreJump(SrcBlock, nullptr, Jump)) 83904eeddc0SDimitry Andric continue; 84004eeddc0SDimitry Andric 8410eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 84204eeddc0SDimitry Andric // If Dst has been visited, skip Jump 8430eae32dcSDimitry Andric if (Visited[Dst]) 8440eae32dcSDimitry Andric continue; 84504eeddc0SDimitry Andric // Process block Dst 8460eae32dcSDimitry Andric Visited[Dst] = true; 847*bdd1243dSDimitry Andric if (!Func.Blocks[Dst].HasUnknownWeight) { 84804eeddc0SDimitry Andric KnownDstBlocks.push_back(&Func.Blocks[Dst]); 8490eae32dcSDimitry Andric } else { 8500eae32dcSDimitry Andric Queue.push(Dst); 85104eeddc0SDimitry Andric UnknownBlocks.push_back(&Func.Blocks[Dst]); 85204eeddc0SDimitry Andric } 8530eae32dcSDimitry Andric } 8540eae32dcSDimitry Andric } 8550eae32dcSDimitry Andric } 8560eae32dcSDimitry Andric 85704eeddc0SDimitry Andric /// Verify if rebalancing of the subgraph is feasible. If the checks are 85804eeddc0SDimitry Andric /// successful, set the unique destination block, DstBlock (can be null). 85904eeddc0SDimitry Andric bool canRebalanceSubgraph(const FlowBlock *SrcBlock, 86004eeddc0SDimitry Andric const std::vector<FlowBlock *> &KnownDstBlocks, 86104eeddc0SDimitry Andric const std::vector<FlowBlock *> &UnknownBlocks, 86204eeddc0SDimitry Andric FlowBlock *&DstBlock) { 8630eae32dcSDimitry Andric // If the list of unknown blocks is empty, we don't need rebalancing 86404eeddc0SDimitry Andric if (UnknownBlocks.empty()) 8650eae32dcSDimitry Andric return false; 86604eeddc0SDimitry Andric 86704eeddc0SDimitry Andric // If there are multiple known sinks, we can't rebalance 86804eeddc0SDimitry Andric if (KnownDstBlocks.size() > 1) 8690eae32dcSDimitry Andric return false; 87004eeddc0SDimitry Andric DstBlock = KnownDstBlocks.empty() ? nullptr : KnownDstBlocks.front(); 87104eeddc0SDimitry Andric 87204eeddc0SDimitry Andric // Verify sinks of the subgraph 873*bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 87404eeddc0SDimitry Andric if (Block->SuccJumps.empty()) { 87504eeddc0SDimitry Andric // If there are multiple (known and unknown) sinks, we can't rebalance 87604eeddc0SDimitry Andric if (DstBlock != nullptr) 87704eeddc0SDimitry Andric return false; 87804eeddc0SDimitry Andric continue; 87904eeddc0SDimitry Andric } 88004eeddc0SDimitry Andric size_t NumIgnoredJumps = 0; 881*bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 88204eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 88304eeddc0SDimitry Andric NumIgnoredJumps++; 88404eeddc0SDimitry Andric } 88504eeddc0SDimitry Andric // If there is a non-sink block in UnknownBlocks with all jumps ignored, 88604eeddc0SDimitry Andric // then we can't rebalance 88704eeddc0SDimitry Andric if (NumIgnoredJumps == Block->SuccJumps.size()) 8880eae32dcSDimitry Andric return false; 8890eae32dcSDimitry Andric } 8900eae32dcSDimitry Andric 8910eae32dcSDimitry Andric return true; 8920eae32dcSDimitry Andric } 8930eae32dcSDimitry Andric 89404eeddc0SDimitry Andric /// Decide whether the Jump is ignored while processing an unknown subgraphs 89504eeddc0SDimitry Andric /// rooted at basic block SrcBlock with the destination block, DstBlock. 89604eeddc0SDimitry Andric bool ignoreJump(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 89704eeddc0SDimitry Andric const FlowJump *Jump) { 89804eeddc0SDimitry Andric // Ignore unlikely jumps with zero flow 89904eeddc0SDimitry Andric if (Jump->IsUnlikely && Jump->Flow == 0) 90004eeddc0SDimitry Andric return true; 90104eeddc0SDimitry Andric 90204eeddc0SDimitry Andric auto JumpSource = &Func.Blocks[Jump->Source]; 90304eeddc0SDimitry Andric auto JumpTarget = &Func.Blocks[Jump->Target]; 90404eeddc0SDimitry Andric 90504eeddc0SDimitry Andric // Do not ignore jumps coming into DstBlock 90604eeddc0SDimitry Andric if (DstBlock != nullptr && JumpTarget == DstBlock) 90704eeddc0SDimitry Andric return false; 90804eeddc0SDimitry Andric 90904eeddc0SDimitry Andric // Ignore jumps out of SrcBlock to known blocks 910*bdd1243dSDimitry Andric if (!JumpTarget->HasUnknownWeight && JumpSource == SrcBlock) 91104eeddc0SDimitry Andric return true; 91204eeddc0SDimitry Andric 91304eeddc0SDimitry Andric // Ignore jumps to known blocks with zero flow 914*bdd1243dSDimitry Andric if (!JumpTarget->HasUnknownWeight && JumpTarget->Flow == 0) 91504eeddc0SDimitry Andric return true; 91604eeddc0SDimitry Andric 91704eeddc0SDimitry Andric return false; 91804eeddc0SDimitry Andric } 91904eeddc0SDimitry Andric 9200eae32dcSDimitry Andric /// Verify if the given unknown subgraph is acyclic, and if yes, reorder 92104eeddc0SDimitry Andric /// UnknownBlocks in the topological order (so that all jumps are "forward"). 92204eeddc0SDimitry Andric bool isAcyclicSubgraph(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 92304eeddc0SDimitry Andric std::vector<FlowBlock *> &UnknownBlocks) { 9240eae32dcSDimitry Andric // Extract local in-degrees in the considered subgraph 9250eae32dcSDimitry Andric auto LocalInDegree = std::vector<uint64_t>(NumBlocks(), 0); 92604eeddc0SDimitry Andric auto fillInDegree = [&](const FlowBlock *Block) { 927*bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 92804eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 92904eeddc0SDimitry Andric continue; 9300eae32dcSDimitry Andric LocalInDegree[Jump->Target]++; 9310eae32dcSDimitry Andric } 93204eeddc0SDimitry Andric }; 93304eeddc0SDimitry Andric fillInDegree(SrcBlock); 934*bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 93504eeddc0SDimitry Andric fillInDegree(Block); 9360eae32dcSDimitry Andric } 9370eae32dcSDimitry Andric // A loop containing SrcBlock 9380eae32dcSDimitry Andric if (LocalInDegree[SrcBlock->Index] > 0) 9390eae32dcSDimitry Andric return false; 9400eae32dcSDimitry Andric 9410eae32dcSDimitry Andric std::vector<FlowBlock *> AcyclicOrder; 9420eae32dcSDimitry Andric std::queue<uint64_t> Queue; 9430eae32dcSDimitry Andric Queue.push(SrcBlock->Index); 9440eae32dcSDimitry Andric while (!Queue.empty()) { 94504eeddc0SDimitry Andric FlowBlock *Block = &Func.Blocks[Queue.front()]; 9460eae32dcSDimitry Andric Queue.pop(); 94704eeddc0SDimitry Andric // Stop propagation once we reach DstBlock, if any 94804eeddc0SDimitry Andric if (DstBlock != nullptr && Block == DstBlock) 9490eae32dcSDimitry Andric break; 9500eae32dcSDimitry Andric 95104eeddc0SDimitry Andric // Keep an acyclic order of unknown blocks 952*bdd1243dSDimitry Andric if (Block->HasUnknownWeight && Block != SrcBlock) 95304eeddc0SDimitry Andric AcyclicOrder.push_back(Block); 95404eeddc0SDimitry Andric 9550eae32dcSDimitry Andric // Add to the queue all successors with zero local in-degree 956*bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 95704eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 95804eeddc0SDimitry Andric continue; 9590eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 9600eae32dcSDimitry Andric LocalInDegree[Dst]--; 9610eae32dcSDimitry Andric if (LocalInDegree[Dst] == 0) { 9620eae32dcSDimitry Andric Queue.push(Dst); 9630eae32dcSDimitry Andric } 9640eae32dcSDimitry Andric } 9650eae32dcSDimitry Andric } 9660eae32dcSDimitry Andric 9670eae32dcSDimitry Andric // If there is a cycle in the subgraph, AcyclicOrder contains only a subset 9680eae32dcSDimitry Andric // of all blocks 96904eeddc0SDimitry Andric if (UnknownBlocks.size() != AcyclicOrder.size()) 9700eae32dcSDimitry Andric return false; 97104eeddc0SDimitry Andric UnknownBlocks = AcyclicOrder; 9720eae32dcSDimitry Andric return true; 9730eae32dcSDimitry Andric } 9740eae32dcSDimitry Andric 97504eeddc0SDimitry Andric /// Rebalance a given subgraph rooted at SrcBlock, ending at DstBlock and 97604eeddc0SDimitry Andric /// having UnknownBlocks intermediate blocks. 97704eeddc0SDimitry Andric void rebalanceUnknownSubgraph(const FlowBlock *SrcBlock, 97804eeddc0SDimitry Andric const FlowBlock *DstBlock, 97904eeddc0SDimitry Andric const std::vector<FlowBlock *> &UnknownBlocks) { 9800eae32dcSDimitry Andric assert(SrcBlock->Flow > 0 && "zero-flow block in unknown subgraph"); 9810eae32dcSDimitry Andric 98204eeddc0SDimitry Andric // Ditribute flow from the source block 98304eeddc0SDimitry Andric uint64_t BlockFlow = 0; 98404eeddc0SDimitry Andric // SrcBlock's flow is the sum of outgoing flows along non-ignored jumps 985*bdd1243dSDimitry Andric for (auto *Jump : SrcBlock->SuccJumps) { 98604eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 9870eae32dcSDimitry Andric continue; 98804eeddc0SDimitry Andric BlockFlow += Jump->Flow; 9890eae32dcSDimitry Andric } 99004eeddc0SDimitry Andric rebalanceBlock(SrcBlock, DstBlock, SrcBlock, BlockFlow); 99104eeddc0SDimitry Andric 99204eeddc0SDimitry Andric // Ditribute flow from the remaining blocks 993*bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 994*bdd1243dSDimitry Andric assert(Block->HasUnknownWeight && "incorrect unknown subgraph"); 99504eeddc0SDimitry Andric uint64_t BlockFlow = 0; 99604eeddc0SDimitry Andric // Block's flow is the sum of incoming flows 997*bdd1243dSDimitry Andric for (auto *Jump : Block->PredJumps) { 99804eeddc0SDimitry Andric BlockFlow += Jump->Flow; 99904eeddc0SDimitry Andric } 100004eeddc0SDimitry Andric Block->Flow = BlockFlow; 100104eeddc0SDimitry Andric rebalanceBlock(SrcBlock, DstBlock, Block, BlockFlow); 100204eeddc0SDimitry Andric } 100304eeddc0SDimitry Andric } 100404eeddc0SDimitry Andric 100504eeddc0SDimitry Andric /// Redistribute flow for a block in a subgraph rooted at SrcBlock, 100604eeddc0SDimitry Andric /// and ending at DstBlock. 100704eeddc0SDimitry Andric void rebalanceBlock(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 100804eeddc0SDimitry Andric const FlowBlock *Block, uint64_t BlockFlow) { 100904eeddc0SDimitry Andric // Process all successor jumps and update corresponding flow values 101004eeddc0SDimitry Andric size_t BlockDegree = 0; 1011*bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 101204eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 101304eeddc0SDimitry Andric continue; 101404eeddc0SDimitry Andric BlockDegree++; 101504eeddc0SDimitry Andric } 101604eeddc0SDimitry Andric // If all successor jumps of the block are ignored, skip it 101704eeddc0SDimitry Andric if (DstBlock == nullptr && BlockDegree == 0) 101804eeddc0SDimitry Andric return; 101904eeddc0SDimitry Andric assert(BlockDegree > 0 && "all outgoing jumps are ignored"); 102004eeddc0SDimitry Andric 102104eeddc0SDimitry Andric // Each of the Block's successors gets the following amount of flow. 102204eeddc0SDimitry Andric // Rounding the value up so that all flow is propagated 102304eeddc0SDimitry Andric uint64_t SuccFlow = (BlockFlow + BlockDegree - 1) / BlockDegree; 1024*bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 102504eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 102604eeddc0SDimitry Andric continue; 102704eeddc0SDimitry Andric uint64_t Flow = std::min(SuccFlow, BlockFlow); 10280eae32dcSDimitry Andric Jump->Flow = Flow; 102904eeddc0SDimitry Andric BlockFlow -= Flow; 10300eae32dcSDimitry Andric } 103104eeddc0SDimitry Andric assert(BlockFlow == 0 && "not all flow is propagated"); 10320eae32dcSDimitry Andric } 10330eae32dcSDimitry Andric 10340eae32dcSDimitry Andric /// A constant indicating an arbitrary exit block of a function. 10350eae32dcSDimitry Andric static constexpr uint64_t AnyExitBlock = uint64_t(-1); 1036*bdd1243dSDimitry Andric /// Minimum BaseDistance for the jump distance values in island joining. 1037*bdd1243dSDimitry Andric static constexpr uint64_t MinBaseDistance = 10000; 10380eae32dcSDimitry Andric 1039*bdd1243dSDimitry Andric /// Params for flow computation. 1040*bdd1243dSDimitry Andric const ProfiParams &Params; 10410eae32dcSDimitry Andric /// The function. 10420eae32dcSDimitry Andric FlowFunction &Func; 10430eae32dcSDimitry Andric }; 10440eae32dcSDimitry Andric 1045*bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params, 1046*bdd1243dSDimitry Andric const FlowBlock &Block); 1047*bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params, 1048*bdd1243dSDimitry Andric const FlowJump &Jump); 1049*bdd1243dSDimitry Andric 10504824e7fdSDimitry Andric /// Initializing flow network for a given function. 10514824e7fdSDimitry Andric /// 1052*bdd1243dSDimitry Andric /// Every block is split into two nodes that are responsible for (i) an 1053*bdd1243dSDimitry Andric /// incoming flow, (ii) an outgoing flow; they penalize an increase or a 10544824e7fdSDimitry Andric /// reduction of the block weight. 1055*bdd1243dSDimitry Andric void initializeNetwork(const ProfiParams &Params, MinCostMaxFlow &Network, 1056*bdd1243dSDimitry Andric FlowFunction &Func) { 10574824e7fdSDimitry Andric uint64_t NumBlocks = Func.Blocks.size(); 10584824e7fdSDimitry Andric assert(NumBlocks > 1 && "Too few blocks in a function"); 1059*bdd1243dSDimitry Andric uint64_t NumJumps = Func.Jumps.size(); 1060*bdd1243dSDimitry Andric assert(NumJumps > 0 && "Too few jumps in a function"); 10614824e7fdSDimitry Andric 10624824e7fdSDimitry Andric // Introducing dummy source/sink pairs to allow flow circulation. 1063*bdd1243dSDimitry Andric // The nodes corresponding to blocks of the function have indicies in 1064*bdd1243dSDimitry Andric // the range [0 .. 2 * NumBlocks); the dummy sources/sinks are indexed by the 1065*bdd1243dSDimitry Andric // next four values. 1066*bdd1243dSDimitry Andric uint64_t S = 2 * NumBlocks; 10674824e7fdSDimitry Andric uint64_t T = S + 1; 10684824e7fdSDimitry Andric uint64_t S1 = S + 2; 10694824e7fdSDimitry Andric uint64_t T1 = S + 3; 10704824e7fdSDimitry Andric 1071*bdd1243dSDimitry Andric Network.initialize(2 * NumBlocks + 4, S1, T1); 10724824e7fdSDimitry Andric 1073*bdd1243dSDimitry Andric // Initialize nodes of the flow network 10744824e7fdSDimitry Andric for (uint64_t B = 0; B < NumBlocks; B++) { 10754824e7fdSDimitry Andric auto &Block = Func.Blocks[B]; 10764824e7fdSDimitry Andric 1077*bdd1243dSDimitry Andric // Split every block into two auxiliary nodes to allow 1078*bdd1243dSDimitry Andric // increase/reduction of the block count. 1079*bdd1243dSDimitry Andric uint64_t Bin = 2 * B; 1080*bdd1243dSDimitry Andric uint64_t Bout = 2 * B + 1; 10814824e7fdSDimitry Andric 10824824e7fdSDimitry Andric // Edges from S and to T 10834824e7fdSDimitry Andric if (Block.isEntry()) { 10844824e7fdSDimitry Andric Network.addEdge(S, Bin, 0); 10854824e7fdSDimitry Andric } else if (Block.isExit()) { 10864824e7fdSDimitry Andric Network.addEdge(Bout, T, 0); 10874824e7fdSDimitry Andric } 10884824e7fdSDimitry Andric 1089*bdd1243dSDimitry Andric // Assign costs for increasing/decreasing the block counts 1090*bdd1243dSDimitry Andric auto [AuxCostInc, AuxCostDec] = assignBlockCosts(Params, Block); 10914824e7fdSDimitry Andric 1092*bdd1243dSDimitry Andric // Add the corresponding edges to the network 1093*bdd1243dSDimitry Andric Network.addEdge(Bin, Bout, AuxCostInc); 10944824e7fdSDimitry Andric if (Block.Weight > 0) { 1095*bdd1243dSDimitry Andric Network.addEdge(Bout, Bin, Block.Weight, AuxCostDec); 1096*bdd1243dSDimitry Andric Network.addEdge(S1, Bout, Block.Weight, 0); 1097*bdd1243dSDimitry Andric Network.addEdge(Bin, T1, Block.Weight, 0); 10984824e7fdSDimitry Andric } 10994824e7fdSDimitry Andric } 11004824e7fdSDimitry Andric 1101*bdd1243dSDimitry Andric // Initialize edges of the flow network 1102*bdd1243dSDimitry Andric for (uint64_t J = 0; J < NumJumps; J++) { 1103*bdd1243dSDimitry Andric auto &Jump = Func.Jumps[J]; 1104*bdd1243dSDimitry Andric 1105*bdd1243dSDimitry Andric // Get the endpoints corresponding to the jump 1106*bdd1243dSDimitry Andric uint64_t Jin = 2 * Jump.Source + 1; 1107*bdd1243dSDimitry Andric uint64_t Jout = 2 * Jump.Target; 1108*bdd1243dSDimitry Andric 1109*bdd1243dSDimitry Andric // Assign costs for increasing/decreasing the jump counts 1110*bdd1243dSDimitry Andric auto [AuxCostInc, AuxCostDec] = assignJumpCosts(Params, Jump); 1111*bdd1243dSDimitry Andric 1112*bdd1243dSDimitry Andric // Add the corresponding edges to the network 1113*bdd1243dSDimitry Andric Network.addEdge(Jin, Jout, AuxCostInc); 1114*bdd1243dSDimitry Andric if (Jump.Weight > 0) { 1115*bdd1243dSDimitry Andric Network.addEdge(Jout, Jin, Jump.Weight, AuxCostDec); 1116*bdd1243dSDimitry Andric Network.addEdge(S1, Jout, Jump.Weight, 0); 1117*bdd1243dSDimitry Andric Network.addEdge(Jin, T1, Jump.Weight, 0); 11184824e7fdSDimitry Andric } 11194824e7fdSDimitry Andric } 11204824e7fdSDimitry Andric 11214824e7fdSDimitry Andric // Make sure we have a valid flow circulation 11224824e7fdSDimitry Andric Network.addEdge(T, S, 0); 11234824e7fdSDimitry Andric } 11244824e7fdSDimitry Andric 1125*bdd1243dSDimitry Andric /// Assign costs for increasing/decreasing the block counts. 1126*bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params, 1127*bdd1243dSDimitry Andric const FlowBlock &Block) { 1128*bdd1243dSDimitry Andric // Modifying the weight of an unlikely block is expensive 1129*bdd1243dSDimitry Andric if (Block.IsUnlikely) 1130*bdd1243dSDimitry Andric return std::make_pair(Params.CostUnlikely, Params.CostUnlikely); 11314824e7fdSDimitry Andric 1132*bdd1243dSDimitry Andric // Assign default values for the costs 1133*bdd1243dSDimitry Andric int64_t CostInc = Params.CostBlockInc; 1134*bdd1243dSDimitry Andric int64_t CostDec = Params.CostBlockDec; 1135*bdd1243dSDimitry Andric // Update the costs depending on the block metadata 1136*bdd1243dSDimitry Andric if (Block.HasUnknownWeight) { 1137*bdd1243dSDimitry Andric CostInc = Params.CostBlockUnknownInc; 1138*bdd1243dSDimitry Andric CostDec = 0; 1139*bdd1243dSDimitry Andric } else { 1140*bdd1243dSDimitry Andric // Increasing the count for "cold" blocks with zero initial count is more 1141*bdd1243dSDimitry Andric // expensive than for "hot" ones 1142*bdd1243dSDimitry Andric if (Block.Weight == 0) 1143*bdd1243dSDimitry Andric CostInc = Params.CostBlockZeroInc; 1144*bdd1243dSDimitry Andric // Modifying the count of the entry block is expensive 1145*bdd1243dSDimitry Andric if (Block.isEntry()) { 1146*bdd1243dSDimitry Andric CostInc = Params.CostBlockEntryInc; 1147*bdd1243dSDimitry Andric CostDec = Params.CostBlockEntryDec; 11484824e7fdSDimitry Andric } 11494824e7fdSDimitry Andric } 1150*bdd1243dSDimitry Andric return std::make_pair(CostInc, CostDec); 11514824e7fdSDimitry Andric } 11524824e7fdSDimitry Andric 1153*bdd1243dSDimitry Andric /// Assign costs for increasing/decreasing the jump counts. 1154*bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params, 1155*bdd1243dSDimitry Andric const FlowJump &Jump) { 1156*bdd1243dSDimitry Andric // Modifying the weight of an unlikely jump is expensive 1157*bdd1243dSDimitry Andric if (Jump.IsUnlikely) 1158*bdd1243dSDimitry Andric return std::make_pair(Params.CostUnlikely, Params.CostUnlikely); 1159*bdd1243dSDimitry Andric 1160*bdd1243dSDimitry Andric // Assign default values for the costs 1161*bdd1243dSDimitry Andric int64_t CostInc = Params.CostJumpInc; 1162*bdd1243dSDimitry Andric int64_t CostDec = Params.CostJumpDec; 1163*bdd1243dSDimitry Andric // Update the costs depending on the block metadata 1164*bdd1243dSDimitry Andric if (Jump.Source + 1 == Jump.Target) { 1165*bdd1243dSDimitry Andric // Adjusting the fall-through branch 1166*bdd1243dSDimitry Andric CostInc = Params.CostJumpFTInc; 1167*bdd1243dSDimitry Andric CostDec = Params.CostJumpFTDec; 1168*bdd1243dSDimitry Andric } 1169*bdd1243dSDimitry Andric if (Jump.HasUnknownWeight) { 1170*bdd1243dSDimitry Andric // The cost is different for fall-through and non-fall-through branches 1171*bdd1243dSDimitry Andric if (Jump.Source + 1 == Jump.Target) 1172*bdd1243dSDimitry Andric CostInc = Params.CostJumpUnknownFTInc; 1173*bdd1243dSDimitry Andric else 1174*bdd1243dSDimitry Andric CostInc = Params.CostJumpUnknownInc; 1175*bdd1243dSDimitry Andric CostDec = 0; 1176*bdd1243dSDimitry Andric } else { 1177*bdd1243dSDimitry Andric assert(Jump.Weight > 0 && "found zero-weight jump with a positive weight"); 1178*bdd1243dSDimitry Andric } 1179*bdd1243dSDimitry Andric return std::make_pair(CostInc, CostDec); 1180*bdd1243dSDimitry Andric } 1181*bdd1243dSDimitry Andric 1182*bdd1243dSDimitry Andric /// Extract resulting block and edge counts from the flow network. 1183*bdd1243dSDimitry Andric void extractWeights(const ProfiParams &Params, MinCostMaxFlow &Network, 1184*bdd1243dSDimitry Andric FlowFunction &Func) { 1185*bdd1243dSDimitry Andric uint64_t NumBlocks = Func.Blocks.size(); 1186*bdd1243dSDimitry Andric uint64_t NumJumps = Func.Jumps.size(); 1187*bdd1243dSDimitry Andric 11884824e7fdSDimitry Andric // Extract resulting jump counts 1189*bdd1243dSDimitry Andric for (uint64_t J = 0; J < NumJumps; J++) { 1190*bdd1243dSDimitry Andric auto &Jump = Func.Jumps[J]; 1191*bdd1243dSDimitry Andric uint64_t SrcOut = 2 * Jump.Source + 1; 1192*bdd1243dSDimitry Andric uint64_t DstIn = 2 * Jump.Target; 1193*bdd1243dSDimitry Andric 11944824e7fdSDimitry Andric int64_t Flow = 0; 1195*bdd1243dSDimitry Andric int64_t AuxFlow = Network.getFlow(SrcOut, DstIn); 1196*bdd1243dSDimitry Andric if (Jump.Source != Jump.Target) 1197*bdd1243dSDimitry Andric Flow = int64_t(Jump.Weight) + AuxFlow; 1198*bdd1243dSDimitry Andric else 1199*bdd1243dSDimitry Andric Flow = int64_t(Jump.Weight) + (AuxFlow > 0 ? AuxFlow : 0); 1200*bdd1243dSDimitry Andric 12014824e7fdSDimitry Andric Jump.Flow = Flow; 12024824e7fdSDimitry Andric assert(Flow >= 0 && "negative jump flow"); 12034824e7fdSDimitry Andric } 1204*bdd1243dSDimitry Andric 1205*bdd1243dSDimitry Andric // Extract resulting block counts 1206*bdd1243dSDimitry Andric auto InFlow = std::vector<uint64_t>(NumBlocks, 0); 1207*bdd1243dSDimitry Andric auto OutFlow = std::vector<uint64_t>(NumBlocks, 0); 1208*bdd1243dSDimitry Andric for (auto &Jump : Func.Jumps) { 1209*bdd1243dSDimitry Andric InFlow[Jump.Target] += Jump.Flow; 1210*bdd1243dSDimitry Andric OutFlow[Jump.Source] += Jump.Flow; 1211*bdd1243dSDimitry Andric } 1212*bdd1243dSDimitry Andric for (uint64_t B = 0; B < NumBlocks; B++) { 1213*bdd1243dSDimitry Andric auto &Block = Func.Blocks[B]; 1214*bdd1243dSDimitry Andric Block.Flow = std::max(OutFlow[B], InFlow[B]); 1215*bdd1243dSDimitry Andric } 12164824e7fdSDimitry Andric } 12174824e7fdSDimitry Andric 12184824e7fdSDimitry Andric #ifndef NDEBUG 1219*bdd1243dSDimitry Andric /// Verify that the provided block/jump weights are as expected. 1220*bdd1243dSDimitry Andric void verifyInput(const FlowFunction &Func) { 1221*bdd1243dSDimitry Andric // Verify the entry block 1222*bdd1243dSDimitry Andric assert(Func.Entry == 0 && Func.Blocks[0].isEntry()); 1223*bdd1243dSDimitry Andric for (size_t I = 1; I < Func.Blocks.size(); I++) { 1224*bdd1243dSDimitry Andric assert(!Func.Blocks[I].isEntry() && "multiple entry blocks"); 1225*bdd1243dSDimitry Andric } 1226*bdd1243dSDimitry Andric // Verify CFG jumps 1227*bdd1243dSDimitry Andric for (auto &Block : Func.Blocks) { 1228*bdd1243dSDimitry Andric assert((!Block.isEntry() || !Block.isExit()) && 1229*bdd1243dSDimitry Andric "a block cannot be an entry and an exit"); 1230*bdd1243dSDimitry Andric } 1231*bdd1243dSDimitry Andric // Verify input block weights 1232*bdd1243dSDimitry Andric for (auto &Block : Func.Blocks) { 1233*bdd1243dSDimitry Andric assert((!Block.HasUnknownWeight || Block.Weight == 0 || Block.isEntry()) && 1234*bdd1243dSDimitry Andric "non-zero weight of a block w/o weight except for an entry"); 1235*bdd1243dSDimitry Andric } 1236*bdd1243dSDimitry Andric // Verify input jump weights 1237*bdd1243dSDimitry Andric for (auto &Jump : Func.Jumps) { 1238*bdd1243dSDimitry Andric assert((!Jump.HasUnknownWeight || Jump.Weight == 0) && 1239*bdd1243dSDimitry Andric "non-zero weight of a jump w/o weight"); 1240*bdd1243dSDimitry Andric } 1241*bdd1243dSDimitry Andric } 1242*bdd1243dSDimitry Andric 1243*bdd1243dSDimitry Andric /// Verify that the computed flow values satisfy flow conservation rules. 1244*bdd1243dSDimitry Andric void verifyOutput(const FlowFunction &Func) { 12454824e7fdSDimitry Andric const uint64_t NumBlocks = Func.Blocks.size(); 12464824e7fdSDimitry Andric auto InFlow = std::vector<uint64_t>(NumBlocks, 0); 12474824e7fdSDimitry Andric auto OutFlow = std::vector<uint64_t>(NumBlocks, 0); 1248*bdd1243dSDimitry Andric for (const auto &Jump : Func.Jumps) { 12494824e7fdSDimitry Andric InFlow[Jump.Target] += Jump.Flow; 12504824e7fdSDimitry Andric OutFlow[Jump.Source] += Jump.Flow; 12514824e7fdSDimitry Andric } 12524824e7fdSDimitry Andric 12534824e7fdSDimitry Andric uint64_t TotalInFlow = 0; 12544824e7fdSDimitry Andric uint64_t TotalOutFlow = 0; 12554824e7fdSDimitry Andric for (uint64_t I = 0; I < NumBlocks; I++) { 12564824e7fdSDimitry Andric auto &Block = Func.Blocks[I]; 12574824e7fdSDimitry Andric if (Block.isEntry()) { 12584824e7fdSDimitry Andric TotalInFlow += Block.Flow; 12594824e7fdSDimitry Andric assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow"); 12604824e7fdSDimitry Andric } else if (Block.isExit()) { 12614824e7fdSDimitry Andric TotalOutFlow += Block.Flow; 12624824e7fdSDimitry Andric assert(Block.Flow == InFlow[I] && "incorrectly computed control flow"); 12634824e7fdSDimitry Andric } else { 12644824e7fdSDimitry Andric assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow"); 12654824e7fdSDimitry Andric assert(Block.Flow == InFlow[I] && "incorrectly computed control flow"); 12664824e7fdSDimitry Andric } 12674824e7fdSDimitry Andric } 12684824e7fdSDimitry Andric assert(TotalInFlow == TotalOutFlow && "incorrectly computed control flow"); 12690eae32dcSDimitry Andric 12700eae32dcSDimitry Andric // Verify that there are no isolated flow components 12710eae32dcSDimitry Andric // One could modify FlowFunction to hold edges indexed by the sources, which 12720eae32dcSDimitry Andric // will avoid a creation of the object 12730eae32dcSDimitry Andric auto PositiveFlowEdges = std::vector<std::vector<uint64_t>>(NumBlocks); 1274*bdd1243dSDimitry Andric for (const auto &Jump : Func.Jumps) { 12750eae32dcSDimitry Andric if (Jump.Flow > 0) { 12760eae32dcSDimitry Andric PositiveFlowEdges[Jump.Source].push_back(Jump.Target); 12770eae32dcSDimitry Andric } 12780eae32dcSDimitry Andric } 12790eae32dcSDimitry Andric 12800eae32dcSDimitry Andric // Run BFS from the source along edges with positive flow 12810eae32dcSDimitry Andric std::queue<uint64_t> Queue; 128204eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks, false); 12830eae32dcSDimitry Andric Queue.push(Func.Entry); 12840eae32dcSDimitry Andric Visited[Func.Entry] = true; 12850eae32dcSDimitry Andric while (!Queue.empty()) { 12860eae32dcSDimitry Andric uint64_t Src = Queue.front(); 12870eae32dcSDimitry Andric Queue.pop(); 12880eae32dcSDimitry Andric for (uint64_t Dst : PositiveFlowEdges[Src]) { 12890eae32dcSDimitry Andric if (!Visited[Dst]) { 12900eae32dcSDimitry Andric Queue.push(Dst); 12910eae32dcSDimitry Andric Visited[Dst] = true; 12920eae32dcSDimitry Andric } 12930eae32dcSDimitry Andric } 12940eae32dcSDimitry Andric } 12950eae32dcSDimitry Andric 12960eae32dcSDimitry Andric // Verify that every block that has a positive flow is reached from the source 12970eae32dcSDimitry Andric // along edges with a positive flow 12980eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks; I++) { 12990eae32dcSDimitry Andric auto &Block = Func.Blocks[I]; 13000eae32dcSDimitry Andric assert((Visited[I] || Block.Flow == 0) && "an isolated flow component"); 13010eae32dcSDimitry Andric } 13024824e7fdSDimitry Andric } 13034824e7fdSDimitry Andric #endif 13044824e7fdSDimitry Andric 13054824e7fdSDimitry Andric } // end of anonymous namespace 13064824e7fdSDimitry Andric 1307*bdd1243dSDimitry Andric /// Apply the profile inference algorithm for a given function 1308*bdd1243dSDimitry Andric void llvm::applyFlowInference(const ProfiParams &Params, FlowFunction &Func) { 1309*bdd1243dSDimitry Andric #ifndef NDEBUG 1310*bdd1243dSDimitry Andric // Verify the input data 1311*bdd1243dSDimitry Andric verifyInput(Func); 1312*bdd1243dSDimitry Andric #endif 1313*bdd1243dSDimitry Andric 13144824e7fdSDimitry Andric // Create and apply an inference network model 1315*bdd1243dSDimitry Andric auto InferenceNetwork = MinCostMaxFlow(Params); 1316*bdd1243dSDimitry Andric initializeNetwork(Params, InferenceNetwork, Func); 13174824e7fdSDimitry Andric InferenceNetwork.run(); 13184824e7fdSDimitry Andric 13194824e7fdSDimitry Andric // Extract flow values for every block and every edge 1320*bdd1243dSDimitry Andric extractWeights(Params, InferenceNetwork, Func); 13214824e7fdSDimitry Andric 13220eae32dcSDimitry Andric // Post-processing adjustments to the flow 1323*bdd1243dSDimitry Andric auto Adjuster = FlowAdjuster(Params, Func); 13240eae32dcSDimitry Andric Adjuster.run(); 13250eae32dcSDimitry Andric 13264824e7fdSDimitry Andric #ifndef NDEBUG 13274824e7fdSDimitry Andric // Verify the result 1328*bdd1243dSDimitry Andric verifyOutput(Func); 13294824e7fdSDimitry Andric #endif 13304824e7fdSDimitry Andric } 1331*bdd1243dSDimitry Andric 1332*bdd1243dSDimitry Andric /// Apply the profile inference algorithm for a given flow function 1333*bdd1243dSDimitry Andric void llvm::applyFlowInference(FlowFunction &Func) { 1334*bdd1243dSDimitry Andric ProfiParams Params; 1335*bdd1243dSDimitry Andric // Set the params from the command-line flags. 1336*bdd1243dSDimitry Andric Params.EvenFlowDistribution = SampleProfileEvenFlowDistribution; 1337*bdd1243dSDimitry Andric Params.RebalanceUnknown = SampleProfileRebalanceUnknown; 1338*bdd1243dSDimitry Andric Params.JoinIslands = SampleProfileJoinIslands; 1339*bdd1243dSDimitry Andric Params.CostBlockInc = SampleProfileProfiCostBlockInc; 1340*bdd1243dSDimitry Andric Params.CostBlockDec = SampleProfileProfiCostBlockDec; 1341*bdd1243dSDimitry Andric Params.CostBlockEntryInc = SampleProfileProfiCostBlockEntryInc; 1342*bdd1243dSDimitry Andric Params.CostBlockEntryDec = SampleProfileProfiCostBlockEntryDec; 1343*bdd1243dSDimitry Andric Params.CostBlockZeroInc = SampleProfileProfiCostBlockZeroInc; 1344*bdd1243dSDimitry Andric Params.CostBlockUnknownInc = SampleProfileProfiCostBlockUnknownInc; 1345*bdd1243dSDimitry Andric 1346*bdd1243dSDimitry Andric applyFlowInference(Params, Func); 1347*bdd1243dSDimitry Andric } 1348