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> 2306c3fb27SDimitry Andric #include <unordered_set> 244824e7fdSDimitry Andric 254824e7fdSDimitry Andric using namespace llvm; 264824e7fdSDimitry Andric #define DEBUG_TYPE "sample-profile-inference" 274824e7fdSDimitry Andric 284824e7fdSDimitry Andric namespace { 294824e7fdSDimitry Andric 30bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileEvenFlowDistribution( 31bdd1243dSDimitry Andric "sample-profile-even-flow-distribution", cl::init(true), cl::Hidden, 32bdd1243dSDimitry Andric cl::desc("Try to evenly distribute flow when there are multiple equally " 3381ad6265SDimitry Andric "likely options.")); 3481ad6265SDimitry Andric 35bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileRebalanceUnknown( 36bdd1243dSDimitry Andric "sample-profile-rebalance-unknown", cl::init(true), cl::Hidden, 37bdd1243dSDimitry Andric cl::desc("Evenly re-distribute flow among unknown subgraphs.")); 3881ad6265SDimitry Andric 39bdd1243dSDimitry Andric static cl::opt<bool> SampleProfileJoinIslands( 40bdd1243dSDimitry Andric "sample-profile-join-islands", cl::init(true), cl::Hidden, 41bdd1243dSDimitry Andric cl::desc("Join isolated components having positive flow.")); 4281ad6265SDimitry Andric 43bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockInc( 44bdd1243dSDimitry Andric "sample-profile-profi-cost-block-inc", cl::init(10), cl::Hidden, 45bdd1243dSDimitry Andric cl::desc("The cost of increasing a block's count by one.")); 4681ad6265SDimitry Andric 47bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockDec( 48bdd1243dSDimitry Andric "sample-profile-profi-cost-block-dec", cl::init(20), cl::Hidden, 49bdd1243dSDimitry Andric cl::desc("The cost of decreasing a block's count by one.")); 5081ad6265SDimitry Andric 51bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockEntryInc( 52bdd1243dSDimitry Andric "sample-profile-profi-cost-block-entry-inc", cl::init(40), cl::Hidden, 53bdd1243dSDimitry Andric cl::desc("The cost of increasing the entry block's count by one.")); 5481ad6265SDimitry Andric 55bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockEntryDec( 56bdd1243dSDimitry Andric "sample-profile-profi-cost-block-entry-dec", cl::init(10), cl::Hidden, 57bdd1243dSDimitry Andric cl::desc("The cost of decreasing the entry block's count by one.")); 58bdd1243dSDimitry Andric 59bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockZeroInc( 60bdd1243dSDimitry Andric "sample-profile-profi-cost-block-zero-inc", cl::init(11), cl::Hidden, 61bdd1243dSDimitry Andric cl::desc("The cost of increasing a count of zero-weight block by one.")); 62bdd1243dSDimitry Andric 63bdd1243dSDimitry Andric static cl::opt<unsigned> SampleProfileProfiCostBlockUnknownInc( 64bdd1243dSDimitry Andric "sample-profile-profi-cost-block-unknown-inc", cl::init(0), cl::Hidden, 65bdd1243dSDimitry Andric cl::desc("The cost of increasing an unknown block's count by one.")); 6681ad6265SDimitry Andric 674824e7fdSDimitry Andric /// A value indicating an infinite flow/capacity/weight of a block/edge. 684824e7fdSDimitry Andric /// Not using numeric_limits<int64_t>::max(), as the values can be summed up 694824e7fdSDimitry Andric /// during the execution. 704824e7fdSDimitry Andric static constexpr int64_t INF = ((int64_t)1) << 50; 714824e7fdSDimitry Andric 724824e7fdSDimitry Andric /// The minimum-cost maximum flow algorithm. 734824e7fdSDimitry Andric /// 744824e7fdSDimitry Andric /// The algorithm finds the maximum flow of minimum cost on a given (directed) 754824e7fdSDimitry Andric /// network using a modified version of the classical Moore-Bellman-Ford 764824e7fdSDimitry Andric /// approach. The algorithm applies a number of augmentation iterations in which 774824e7fdSDimitry Andric /// flow is sent along paths of positive capacity from the source to the sink. 784824e7fdSDimitry Andric /// The worst-case time complexity of the implementation is O(v(f)*m*n), where 794824e7fdSDimitry Andric /// where m is the number of edges, n is the number of vertices, and v(f) is the 804824e7fdSDimitry Andric /// value of the maximum flow. However, the observed running time on typical 814824e7fdSDimitry Andric /// instances is sub-quadratic, that is, o(n^2). 824824e7fdSDimitry Andric /// 834824e7fdSDimitry Andric /// The input is a set of edges with specified costs and capacities, and a pair 844824e7fdSDimitry Andric /// of nodes (source and sink). The output is the flow along each edge of the 854824e7fdSDimitry Andric /// minimum total cost respecting the given edge capacities. 864824e7fdSDimitry Andric class MinCostMaxFlow { 874824e7fdSDimitry Andric public: 88bdd1243dSDimitry Andric MinCostMaxFlow(const ProfiParams &Params) : Params(Params) {} 89bdd1243dSDimitry Andric 904824e7fdSDimitry Andric // Initialize algorithm's data structures for a network of a given size. 914824e7fdSDimitry Andric void initialize(uint64_t NodeCount, uint64_t SourceNode, uint64_t SinkNode) { 924824e7fdSDimitry Andric Source = SourceNode; 934824e7fdSDimitry Andric Target = SinkNode; 944824e7fdSDimitry Andric 954824e7fdSDimitry Andric Nodes = std::vector<Node>(NodeCount); 964824e7fdSDimitry Andric Edges = std::vector<std::vector<Edge>>(NodeCount, std::vector<Edge>()); 97bdd1243dSDimitry Andric if (Params.EvenFlowDistribution) 9881ad6265SDimitry Andric AugmentingEdges = 9981ad6265SDimitry Andric std::vector<std::vector<Edge *>>(NodeCount, std::vector<Edge *>()); 1004824e7fdSDimitry Andric } 1014824e7fdSDimitry Andric 1024824e7fdSDimitry Andric // Run the algorithm. 1034824e7fdSDimitry Andric int64_t run() { 104bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Starting profi for " << Nodes.size() << " nodes\n"); 105bdd1243dSDimitry Andric 10681ad6265SDimitry Andric // Iteratively find an augmentation path/dag in the network and send the 10781ad6265SDimitry Andric // flow along its edges 10881ad6265SDimitry Andric size_t AugmentationIters = applyFlowAugmentation(); 1094824e7fdSDimitry Andric 1104824e7fdSDimitry Andric // Compute the total flow and its cost 1114824e7fdSDimitry Andric int64_t TotalCost = 0; 1124824e7fdSDimitry Andric int64_t TotalFlow = 0; 1134824e7fdSDimitry Andric for (uint64_t Src = 0; Src < Nodes.size(); Src++) { 1144824e7fdSDimitry Andric for (auto &Edge : Edges[Src]) { 1154824e7fdSDimitry Andric if (Edge.Flow > 0) { 1164824e7fdSDimitry Andric TotalCost += Edge.Cost * Edge.Flow; 1174824e7fdSDimitry Andric if (Src == Source) 1184824e7fdSDimitry Andric TotalFlow += Edge.Flow; 1194824e7fdSDimitry Andric } 1204824e7fdSDimitry Andric } 1214824e7fdSDimitry Andric } 1224824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Completed profi after " << AugmentationIters 1234824e7fdSDimitry Andric << " iterations with " << TotalFlow << " total flow" 1244824e7fdSDimitry Andric << " of " << TotalCost << " cost\n"); 1254824e7fdSDimitry Andric (void)TotalFlow; 12681ad6265SDimitry Andric (void)AugmentationIters; 1274824e7fdSDimitry Andric return TotalCost; 1284824e7fdSDimitry Andric } 1294824e7fdSDimitry Andric 1304824e7fdSDimitry Andric /// Adding an edge to the network with a specified capacity and a cost. 1314824e7fdSDimitry Andric /// Multiple edges between a pair of nodes are allowed but self-edges 1324824e7fdSDimitry Andric /// are not supported. 1334824e7fdSDimitry Andric void addEdge(uint64_t Src, uint64_t Dst, int64_t Capacity, int64_t Cost) { 1344824e7fdSDimitry Andric assert(Capacity > 0 && "adding an edge of zero capacity"); 1354824e7fdSDimitry Andric assert(Src != Dst && "loop edge are not supported"); 1364824e7fdSDimitry Andric 1374824e7fdSDimitry Andric Edge SrcEdge; 1384824e7fdSDimitry Andric SrcEdge.Dst = Dst; 1394824e7fdSDimitry Andric SrcEdge.Cost = Cost; 1404824e7fdSDimitry Andric SrcEdge.Capacity = Capacity; 1414824e7fdSDimitry Andric SrcEdge.Flow = 0; 1424824e7fdSDimitry Andric SrcEdge.RevEdgeIndex = Edges[Dst].size(); 1434824e7fdSDimitry Andric 1444824e7fdSDimitry Andric Edge DstEdge; 1454824e7fdSDimitry Andric DstEdge.Dst = Src; 1464824e7fdSDimitry Andric DstEdge.Cost = -Cost; 1474824e7fdSDimitry Andric DstEdge.Capacity = 0; 1484824e7fdSDimitry Andric DstEdge.Flow = 0; 1494824e7fdSDimitry Andric DstEdge.RevEdgeIndex = Edges[Src].size(); 1504824e7fdSDimitry Andric 1514824e7fdSDimitry Andric Edges[Src].push_back(SrcEdge); 1524824e7fdSDimitry Andric Edges[Dst].push_back(DstEdge); 1534824e7fdSDimitry Andric } 1544824e7fdSDimitry Andric 1554824e7fdSDimitry Andric /// Adding an edge to the network of infinite capacity and a given cost. 1564824e7fdSDimitry Andric void addEdge(uint64_t Src, uint64_t Dst, int64_t Cost) { 1574824e7fdSDimitry Andric addEdge(Src, Dst, INF, Cost); 1584824e7fdSDimitry Andric } 1594824e7fdSDimitry Andric 1604824e7fdSDimitry Andric /// Get the total flow from a given source node. 1614824e7fdSDimitry Andric /// Returns a list of pairs (target node, amount of flow to the target). 1625f757f3fSDimitry Andric std::vector<std::pair<uint64_t, int64_t>> getFlow(uint64_t Src) const { 1634824e7fdSDimitry Andric std::vector<std::pair<uint64_t, int64_t>> Flow; 164bdd1243dSDimitry Andric for (const auto &Edge : Edges[Src]) { 1654824e7fdSDimitry Andric if (Edge.Flow > 0) 1664824e7fdSDimitry Andric Flow.push_back(std::make_pair(Edge.Dst, Edge.Flow)); 1674824e7fdSDimitry Andric } 1684824e7fdSDimitry Andric return Flow; 1694824e7fdSDimitry Andric } 1704824e7fdSDimitry Andric 1714824e7fdSDimitry Andric /// Get the total flow between a pair of nodes. 1724824e7fdSDimitry Andric int64_t getFlow(uint64_t Src, uint64_t Dst) const { 1734824e7fdSDimitry Andric int64_t Flow = 0; 174bdd1243dSDimitry Andric for (const auto &Edge : Edges[Src]) { 1754824e7fdSDimitry Andric if (Edge.Dst == Dst) { 1764824e7fdSDimitry Andric Flow += Edge.Flow; 1774824e7fdSDimitry Andric } 1784824e7fdSDimitry Andric } 1794824e7fdSDimitry Andric return Flow; 1804824e7fdSDimitry Andric } 1814824e7fdSDimitry Andric 1824824e7fdSDimitry Andric private: 18381ad6265SDimitry Andric /// Iteratively find an augmentation path/dag in the network and send the 18481ad6265SDimitry Andric /// flow along its edges. The method returns the number of applied iterations. 18581ad6265SDimitry Andric size_t applyFlowAugmentation() { 18681ad6265SDimitry Andric size_t AugmentationIters = 0; 18781ad6265SDimitry Andric while (findAugmentingPath()) { 18881ad6265SDimitry Andric uint64_t PathCapacity = computeAugmentingPathCapacity(); 18981ad6265SDimitry Andric while (PathCapacity > 0) { 19081ad6265SDimitry Andric bool Progress = false; 191bdd1243dSDimitry Andric if (Params.EvenFlowDistribution) { 19281ad6265SDimitry Andric // Identify node/edge candidates for augmentation 19381ad6265SDimitry Andric identifyShortestEdges(PathCapacity); 19481ad6265SDimitry Andric 19581ad6265SDimitry Andric // Find an augmenting DAG 19681ad6265SDimitry Andric auto AugmentingOrder = findAugmentingDAG(); 19781ad6265SDimitry Andric 19881ad6265SDimitry Andric // Apply the DAG augmentation 19981ad6265SDimitry Andric Progress = augmentFlowAlongDAG(AugmentingOrder); 20081ad6265SDimitry Andric PathCapacity = computeAugmentingPathCapacity(); 20181ad6265SDimitry Andric } 20281ad6265SDimitry Andric 20381ad6265SDimitry Andric if (!Progress) { 20481ad6265SDimitry Andric augmentFlowAlongPath(PathCapacity); 20581ad6265SDimitry Andric PathCapacity = 0; 20681ad6265SDimitry Andric } 20781ad6265SDimitry Andric 20881ad6265SDimitry Andric AugmentationIters++; 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric return AugmentationIters; 21281ad6265SDimitry Andric } 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric /// Compute the capacity of the cannonical augmenting path. If the path is 21581ad6265SDimitry Andric /// saturated (that is, no flow can be sent along the path), then return 0. 21681ad6265SDimitry Andric uint64_t computeAugmentingPathCapacity() { 21781ad6265SDimitry Andric uint64_t PathCapacity = INF; 21881ad6265SDimitry Andric uint64_t Now = Target; 21981ad6265SDimitry Andric while (Now != Source) { 22081ad6265SDimitry Andric uint64_t Pred = Nodes[Now].ParentNode; 22181ad6265SDimitry Andric auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex]; 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric assert(Edge.Capacity >= Edge.Flow && "incorrect edge flow"); 22481ad6265SDimitry Andric uint64_t EdgeCapacity = uint64_t(Edge.Capacity - Edge.Flow); 22581ad6265SDimitry Andric PathCapacity = std::min(PathCapacity, EdgeCapacity); 22681ad6265SDimitry Andric 22781ad6265SDimitry Andric Now = Pred; 22881ad6265SDimitry Andric } 22981ad6265SDimitry Andric return PathCapacity; 23081ad6265SDimitry Andric } 23181ad6265SDimitry Andric 2324824e7fdSDimitry Andric /// Check for existence of an augmenting path with a positive capacity. 2334824e7fdSDimitry Andric bool findAugmentingPath() { 2344824e7fdSDimitry Andric // Initialize data structures 2354824e7fdSDimitry Andric for (auto &Node : Nodes) { 2364824e7fdSDimitry Andric Node.Distance = INF; 2374824e7fdSDimitry Andric Node.ParentNode = uint64_t(-1); 2384824e7fdSDimitry Andric Node.ParentEdgeIndex = uint64_t(-1); 2394824e7fdSDimitry Andric Node.Taken = false; 2404824e7fdSDimitry Andric } 2414824e7fdSDimitry Andric 2424824e7fdSDimitry Andric std::queue<uint64_t> Queue; 2434824e7fdSDimitry Andric Queue.push(Source); 2444824e7fdSDimitry Andric Nodes[Source].Distance = 0; 2454824e7fdSDimitry Andric Nodes[Source].Taken = true; 2464824e7fdSDimitry Andric while (!Queue.empty()) { 2474824e7fdSDimitry Andric uint64_t Src = Queue.front(); 2484824e7fdSDimitry Andric Queue.pop(); 2494824e7fdSDimitry Andric Nodes[Src].Taken = false; 2504824e7fdSDimitry Andric // Although the residual network contains edges with negative costs 2514824e7fdSDimitry Andric // (in particular, backward edges), it can be shown that there are no 2524824e7fdSDimitry Andric // negative-weight cycles and the following two invariants are maintained: 2534824e7fdSDimitry Andric // (i) Dist[Source, V] >= 0 and (ii) Dist[V, Target] >= 0 for all nodes V, 2544824e7fdSDimitry Andric // where Dist is the length of the shortest path between two nodes. This 2554824e7fdSDimitry Andric // allows to prune the search-space of the path-finding algorithm using 2564824e7fdSDimitry Andric // the following early-stop criteria: 2574824e7fdSDimitry Andric // -- If we find a path with zero-distance from Source to Target, stop the 2584824e7fdSDimitry Andric // search, as the path is the shortest since Dist[Source, Target] >= 0; 2594824e7fdSDimitry Andric // -- If we have Dist[Source, V] > Dist[Source, Target], then do not 2604824e7fdSDimitry Andric // process node V, as it is guaranteed _not_ to be on a shortest path 2614824e7fdSDimitry Andric // from Source to Target; it follows from inequalities 2624824e7fdSDimitry Andric // Dist[Source, Target] >= Dist[Source, V] + Dist[V, Target] 2634824e7fdSDimitry Andric // >= Dist[Source, V] 264bdd1243dSDimitry Andric if (!Params.EvenFlowDistribution && Nodes[Target].Distance == 0) 2654824e7fdSDimitry Andric break; 2664824e7fdSDimitry Andric if (Nodes[Src].Distance > Nodes[Target].Distance) 2674824e7fdSDimitry Andric continue; 2684824e7fdSDimitry Andric 2694824e7fdSDimitry Andric // Process adjacent edges 2704824e7fdSDimitry Andric for (uint64_t EdgeIdx = 0; EdgeIdx < Edges[Src].size(); EdgeIdx++) { 2714824e7fdSDimitry Andric auto &Edge = Edges[Src][EdgeIdx]; 2724824e7fdSDimitry Andric if (Edge.Flow < Edge.Capacity) { 2734824e7fdSDimitry Andric uint64_t Dst = Edge.Dst; 2744824e7fdSDimitry Andric int64_t NewDistance = Nodes[Src].Distance + Edge.Cost; 2754824e7fdSDimitry Andric if (Nodes[Dst].Distance > NewDistance) { 2764824e7fdSDimitry Andric // Update the distance and the parent node/edge 2774824e7fdSDimitry Andric Nodes[Dst].Distance = NewDistance; 2784824e7fdSDimitry Andric Nodes[Dst].ParentNode = Src; 2794824e7fdSDimitry Andric Nodes[Dst].ParentEdgeIndex = EdgeIdx; 2804824e7fdSDimitry Andric // Add the node to the queue, if it is not there yet 2814824e7fdSDimitry Andric if (!Nodes[Dst].Taken) { 2824824e7fdSDimitry Andric Queue.push(Dst); 2834824e7fdSDimitry Andric Nodes[Dst].Taken = true; 2844824e7fdSDimitry Andric } 2854824e7fdSDimitry Andric } 2864824e7fdSDimitry Andric } 2874824e7fdSDimitry Andric } 2884824e7fdSDimitry Andric } 2894824e7fdSDimitry Andric 2904824e7fdSDimitry Andric return Nodes[Target].Distance != INF; 2914824e7fdSDimitry Andric } 2924824e7fdSDimitry Andric 2934824e7fdSDimitry Andric /// Update the current flow along the augmenting path. 29481ad6265SDimitry Andric void augmentFlowAlongPath(uint64_t PathCapacity) { 2950eae32dcSDimitry Andric assert(PathCapacity > 0 && "found an incorrect augmenting path"); 29681ad6265SDimitry Andric uint64_t Now = Target; 2974824e7fdSDimitry Andric while (Now != Source) { 2984824e7fdSDimitry Andric uint64_t Pred = Nodes[Now].ParentNode; 2994824e7fdSDimitry Andric auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex]; 3004824e7fdSDimitry Andric auto &RevEdge = Edges[Now][Edge.RevEdgeIndex]; 3014824e7fdSDimitry Andric 3024824e7fdSDimitry Andric Edge.Flow += PathCapacity; 3034824e7fdSDimitry Andric RevEdge.Flow -= PathCapacity; 3044824e7fdSDimitry Andric 3054824e7fdSDimitry Andric Now = Pred; 3064824e7fdSDimitry Andric } 3074824e7fdSDimitry Andric } 3084824e7fdSDimitry Andric 30981ad6265SDimitry Andric /// Find an Augmenting DAG order using a modified version of DFS in which we 31081ad6265SDimitry Andric /// can visit a node multiple times. In the DFS search, when scanning each 31181ad6265SDimitry Andric /// edge out of a node, continue search at Edge.Dst endpoint if it has not 31281ad6265SDimitry Andric /// been discovered yet and its NumCalls < MaxDfsCalls. The algorithm 31381ad6265SDimitry Andric /// runs in O(MaxDfsCalls * |Edges| + |Nodes|) time. 31481ad6265SDimitry Andric /// It returns an Augmenting Order (Taken nodes in decreasing Finish time) 31581ad6265SDimitry Andric /// that starts with Source and ends with Target. 31681ad6265SDimitry Andric std::vector<uint64_t> findAugmentingDAG() { 31781ad6265SDimitry Andric // We use a stack based implemenation of DFS to avoid recursion. 31881ad6265SDimitry Andric // Defining DFS data structures: 31981ad6265SDimitry Andric // A pair (NodeIdx, EdgeIdx) at the top of the Stack denotes that 32081ad6265SDimitry Andric // - we are currently visiting Nodes[NodeIdx] and 32181ad6265SDimitry Andric // - the next edge to scan is Edges[NodeIdx][EdgeIdx] 32281ad6265SDimitry Andric typedef std::pair<uint64_t, uint64_t> StackItemType; 32381ad6265SDimitry Andric std::stack<StackItemType> Stack; 32481ad6265SDimitry Andric std::vector<uint64_t> AugmentingOrder; 32581ad6265SDimitry Andric 32681ad6265SDimitry Andric // Phase 0: Initialize Node attributes and Time for DFS run 32781ad6265SDimitry Andric for (auto &Node : Nodes) { 32881ad6265SDimitry Andric Node.Discovery = 0; 32981ad6265SDimitry Andric Node.Finish = 0; 33081ad6265SDimitry Andric Node.NumCalls = 0; 33181ad6265SDimitry Andric Node.Taken = false; 33281ad6265SDimitry Andric } 33381ad6265SDimitry Andric uint64_t Time = 0; 33481ad6265SDimitry Andric // Mark Target as Taken 33581ad6265SDimitry Andric // Taken attribute will be propagated backwards from Target towards Source 33681ad6265SDimitry Andric Nodes[Target].Taken = true; 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric // Phase 1: Start DFS traversal from Source 33981ad6265SDimitry Andric Stack.emplace(Source, 0); 34081ad6265SDimitry Andric Nodes[Source].Discovery = ++Time; 34181ad6265SDimitry Andric while (!Stack.empty()) { 34281ad6265SDimitry Andric auto NodeIdx = Stack.top().first; 34381ad6265SDimitry Andric auto EdgeIdx = Stack.top().second; 34481ad6265SDimitry Andric 34581ad6265SDimitry Andric // If we haven't scanned all edges out of NodeIdx, continue scanning 34681ad6265SDimitry Andric if (EdgeIdx < Edges[NodeIdx].size()) { 34781ad6265SDimitry Andric auto &Edge = Edges[NodeIdx][EdgeIdx]; 34881ad6265SDimitry Andric auto &Dst = Nodes[Edge.Dst]; 34981ad6265SDimitry Andric Stack.top().second++; 35081ad6265SDimitry Andric 35181ad6265SDimitry Andric if (Edge.OnShortestPath) { 35281ad6265SDimitry Andric // If we haven't seen Edge.Dst so far, continue DFS search there 353bdd1243dSDimitry Andric if (Dst.Discovery == 0 && Dst.NumCalls < MaxDfsCalls) { 35481ad6265SDimitry Andric Dst.Discovery = ++Time; 35581ad6265SDimitry Andric Stack.emplace(Edge.Dst, 0); 35681ad6265SDimitry Andric Dst.NumCalls++; 35781ad6265SDimitry Andric } else if (Dst.Taken && Dst.Finish != 0) { 35881ad6265SDimitry Andric // Else, if Edge.Dst already have a path to Target, so that NodeIdx 35981ad6265SDimitry Andric Nodes[NodeIdx].Taken = true; 36081ad6265SDimitry Andric } 36181ad6265SDimitry Andric } 36281ad6265SDimitry Andric } else { 36381ad6265SDimitry Andric // If we are done scanning all edge out of NodeIdx 36481ad6265SDimitry Andric Stack.pop(); 36581ad6265SDimitry Andric // If we haven't found a path from NodeIdx to Target, forget about it 36681ad6265SDimitry Andric if (!Nodes[NodeIdx].Taken) { 36781ad6265SDimitry Andric Nodes[NodeIdx].Discovery = 0; 36881ad6265SDimitry Andric } else { 36981ad6265SDimitry Andric // If we have found a path from NodeIdx to Target, then finish NodeIdx 37081ad6265SDimitry Andric // and propagate Taken flag to DFS parent unless at the Source 37181ad6265SDimitry Andric Nodes[NodeIdx].Finish = ++Time; 37281ad6265SDimitry Andric // NodeIdx == Source if and only if the stack is empty 37381ad6265SDimitry Andric if (NodeIdx != Source) { 37481ad6265SDimitry Andric assert(!Stack.empty() && "empty stack while running dfs"); 37581ad6265SDimitry Andric Nodes[Stack.top().first].Taken = true; 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric AugmentingOrder.push_back(NodeIdx); 37881ad6265SDimitry Andric } 37981ad6265SDimitry Andric } 38081ad6265SDimitry Andric } 38181ad6265SDimitry Andric // Nodes are collected decreasing Finish time, so the order is reversed 38281ad6265SDimitry Andric std::reverse(AugmentingOrder.begin(), AugmentingOrder.end()); 38381ad6265SDimitry Andric 38481ad6265SDimitry Andric // Phase 2: Extract all forward (DAG) edges and fill in AugmentingEdges 38581ad6265SDimitry Andric for (size_t Src : AugmentingOrder) { 38681ad6265SDimitry Andric AugmentingEdges[Src].clear(); 38781ad6265SDimitry Andric for (auto &Edge : Edges[Src]) { 38881ad6265SDimitry Andric uint64_t Dst = Edge.Dst; 38981ad6265SDimitry Andric if (Edge.OnShortestPath && Nodes[Src].Taken && Nodes[Dst].Taken && 39081ad6265SDimitry Andric Nodes[Dst].Finish < Nodes[Src].Finish) { 39181ad6265SDimitry Andric AugmentingEdges[Src].push_back(&Edge); 39281ad6265SDimitry Andric } 39381ad6265SDimitry Andric } 39481ad6265SDimitry Andric assert((Src == Target || !AugmentingEdges[Src].empty()) && 39581ad6265SDimitry Andric "incorrectly constructed augmenting edges"); 39681ad6265SDimitry Andric } 39781ad6265SDimitry Andric 39881ad6265SDimitry Andric return AugmentingOrder; 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 40181ad6265SDimitry Andric /// Update the current flow along the given (acyclic) subgraph specified by 40281ad6265SDimitry Andric /// the vertex order, AugmentingOrder. The objective is to send as much flow 40381ad6265SDimitry Andric /// as possible while evenly distributing flow among successors of each node. 40481ad6265SDimitry Andric /// After the update at least one edge is saturated. 40581ad6265SDimitry Andric bool augmentFlowAlongDAG(const std::vector<uint64_t> &AugmentingOrder) { 40681ad6265SDimitry Andric // Phase 0: Initialization 40781ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 40881ad6265SDimitry Andric Nodes[Src].FracFlow = 0; 40981ad6265SDimitry Andric Nodes[Src].IntFlow = 0; 41081ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 41181ad6265SDimitry Andric Edge->AugmentedFlow = 0; 41281ad6265SDimitry Andric } 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric // Phase 1: Send a unit of fractional flow along the DAG 41681ad6265SDimitry Andric uint64_t MaxFlowAmount = INF; 41781ad6265SDimitry Andric Nodes[Source].FracFlow = 1.0; 41881ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 41981ad6265SDimitry Andric assert((Src == Target || Nodes[Src].FracFlow > 0.0) && 42081ad6265SDimitry Andric "incorrectly computed fractional flow"); 42181ad6265SDimitry Andric // Distribute flow evenly among successors of Src 42281ad6265SDimitry Andric uint64_t Degree = AugmentingEdges[Src].size(); 42381ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 42481ad6265SDimitry Andric double EdgeFlow = Nodes[Src].FracFlow / Degree; 42581ad6265SDimitry Andric Nodes[Edge->Dst].FracFlow += EdgeFlow; 42681ad6265SDimitry Andric if (Edge->Capacity == INF) 42781ad6265SDimitry Andric continue; 42881ad6265SDimitry Andric uint64_t MaxIntFlow = double(Edge->Capacity - Edge->Flow) / EdgeFlow; 42981ad6265SDimitry Andric MaxFlowAmount = std::min(MaxFlowAmount, MaxIntFlow); 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric } 43281ad6265SDimitry Andric // Stop early if we cannot send any (integral) flow from Source to Target 43381ad6265SDimitry Andric if (MaxFlowAmount == 0) 43481ad6265SDimitry Andric return false; 43581ad6265SDimitry Andric 43681ad6265SDimitry Andric // Phase 2: Send an integral flow of MaxFlowAmount 43781ad6265SDimitry Andric Nodes[Source].IntFlow = MaxFlowAmount; 43881ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 43981ad6265SDimitry Andric if (Src == Target) 44081ad6265SDimitry Andric break; 44181ad6265SDimitry Andric // Distribute flow evenly among successors of Src, rounding up to make 44281ad6265SDimitry Andric // sure all flow is sent 44381ad6265SDimitry Andric uint64_t Degree = AugmentingEdges[Src].size(); 44481ad6265SDimitry Andric // We are guaranteeed that Node[Src].IntFlow <= SuccFlow * Degree 44581ad6265SDimitry Andric uint64_t SuccFlow = (Nodes[Src].IntFlow + Degree - 1) / Degree; 44681ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 44781ad6265SDimitry Andric uint64_t Dst = Edge->Dst; 44881ad6265SDimitry Andric uint64_t EdgeFlow = std::min(Nodes[Src].IntFlow, SuccFlow); 44981ad6265SDimitry Andric EdgeFlow = std::min(EdgeFlow, uint64_t(Edge->Capacity - Edge->Flow)); 45081ad6265SDimitry Andric Nodes[Dst].IntFlow += EdgeFlow; 45181ad6265SDimitry Andric Nodes[Src].IntFlow -= EdgeFlow; 45281ad6265SDimitry Andric Edge->AugmentedFlow += EdgeFlow; 45381ad6265SDimitry Andric } 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric assert(Nodes[Target].IntFlow <= MaxFlowAmount); 45681ad6265SDimitry Andric Nodes[Target].IntFlow = 0; 45781ad6265SDimitry Andric 45881ad6265SDimitry Andric // Phase 3: Send excess flow back traversing the nodes backwards. 45981ad6265SDimitry Andric // Because of rounding, not all flow can be sent along the edges of Src. 46081ad6265SDimitry Andric // Hence, sending the remaining flow back to maintain flow conservation 46181ad6265SDimitry Andric for (size_t Idx = AugmentingOrder.size() - 1; Idx > 0; Idx--) { 46281ad6265SDimitry Andric uint64_t Src = AugmentingOrder[Idx - 1]; 46381ad6265SDimitry Andric // Try to send excess flow back along each edge. 46481ad6265SDimitry Andric // Make sure we only send back flow we just augmented (AugmentedFlow). 46581ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 46681ad6265SDimitry Andric uint64_t Dst = Edge->Dst; 46781ad6265SDimitry Andric if (Nodes[Dst].IntFlow == 0) 46881ad6265SDimitry Andric continue; 46981ad6265SDimitry Andric uint64_t EdgeFlow = std::min(Nodes[Dst].IntFlow, Edge->AugmentedFlow); 47081ad6265SDimitry Andric Nodes[Dst].IntFlow -= EdgeFlow; 47181ad6265SDimitry Andric Nodes[Src].IntFlow += EdgeFlow; 47281ad6265SDimitry Andric Edge->AugmentedFlow -= EdgeFlow; 47381ad6265SDimitry Andric } 47481ad6265SDimitry Andric } 47581ad6265SDimitry Andric 47681ad6265SDimitry Andric // Phase 4: Update flow values along all edges 47781ad6265SDimitry Andric bool HasSaturatedEdges = false; 47881ad6265SDimitry Andric for (uint64_t Src : AugmentingOrder) { 47981ad6265SDimitry Andric // Verify that we have sent all the excess flow from the node 48081ad6265SDimitry Andric assert(Src == Source || Nodes[Src].IntFlow == 0); 48181ad6265SDimitry Andric for (auto &Edge : AugmentingEdges[Src]) { 48281ad6265SDimitry Andric assert(uint64_t(Edge->Capacity - Edge->Flow) >= Edge->AugmentedFlow); 48381ad6265SDimitry Andric // Update flow values along the edge and its reverse copy 48481ad6265SDimitry Andric auto &RevEdge = Edges[Edge->Dst][Edge->RevEdgeIndex]; 48581ad6265SDimitry Andric Edge->Flow += Edge->AugmentedFlow; 48681ad6265SDimitry Andric RevEdge.Flow -= Edge->AugmentedFlow; 48781ad6265SDimitry Andric if (Edge->Capacity == Edge->Flow && Edge->AugmentedFlow > 0) 48881ad6265SDimitry Andric HasSaturatedEdges = true; 48981ad6265SDimitry Andric } 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric 49281ad6265SDimitry Andric // The augmentation is successful iff at least one edge becomes saturated 49381ad6265SDimitry Andric return HasSaturatedEdges; 49481ad6265SDimitry Andric } 49581ad6265SDimitry Andric 49681ad6265SDimitry Andric /// Identify candidate (shortest) edges for augmentation. 49781ad6265SDimitry Andric void identifyShortestEdges(uint64_t PathCapacity) { 49881ad6265SDimitry Andric assert(PathCapacity > 0 && "found an incorrect augmenting DAG"); 49981ad6265SDimitry Andric // To make sure the augmentation DAG contains only edges with large residual 50081ad6265SDimitry Andric // capacity, we prune all edges whose capacity is below a fraction of 50181ad6265SDimitry Andric // the capacity of the augmented path. 50281ad6265SDimitry Andric // (All edges of the path itself are always in the DAG) 50381ad6265SDimitry Andric uint64_t MinCapacity = std::max(PathCapacity / 2, uint64_t(1)); 50481ad6265SDimitry Andric 50581ad6265SDimitry Andric // Decide which edges are on a shortest path from Source to Target 50681ad6265SDimitry Andric for (size_t Src = 0; Src < Nodes.size(); Src++) { 50781ad6265SDimitry Andric // An edge cannot be augmenting if the endpoint has large distance 50881ad6265SDimitry Andric if (Nodes[Src].Distance > Nodes[Target].Distance) 50981ad6265SDimitry Andric continue; 51081ad6265SDimitry Andric 51181ad6265SDimitry Andric for (auto &Edge : Edges[Src]) { 51281ad6265SDimitry Andric uint64_t Dst = Edge.Dst; 51381ad6265SDimitry Andric Edge.OnShortestPath = 51481ad6265SDimitry Andric Src != Target && Dst != Source && 51581ad6265SDimitry Andric Nodes[Dst].Distance <= Nodes[Target].Distance && 51681ad6265SDimitry Andric Nodes[Dst].Distance == Nodes[Src].Distance + Edge.Cost && 51781ad6265SDimitry Andric Edge.Capacity > Edge.Flow && 51881ad6265SDimitry Andric uint64_t(Edge.Capacity - Edge.Flow) >= MinCapacity; 51981ad6265SDimitry Andric } 52081ad6265SDimitry Andric } 52181ad6265SDimitry Andric } 52281ad6265SDimitry Andric 523bdd1243dSDimitry Andric /// Maximum number of DFS iterations for DAG finding. 524bdd1243dSDimitry Andric static constexpr uint64_t MaxDfsCalls = 10; 525bdd1243dSDimitry Andric 52604eeddc0SDimitry Andric /// A node in a flow network. 5274824e7fdSDimitry Andric struct Node { 5284824e7fdSDimitry Andric /// The cost of the cheapest path from the source to the current node. 5294824e7fdSDimitry Andric int64_t Distance; 5304824e7fdSDimitry Andric /// The node preceding the current one in the path. 5314824e7fdSDimitry Andric uint64_t ParentNode; 5324824e7fdSDimitry Andric /// The index of the edge between ParentNode and the current node. 5334824e7fdSDimitry Andric uint64_t ParentEdgeIndex; 5344824e7fdSDimitry Andric /// An indicator of whether the current node is in a queue. 5354824e7fdSDimitry Andric bool Taken; 53681ad6265SDimitry Andric 53781ad6265SDimitry Andric /// Data fields utilized in DAG-augmentation: 53881ad6265SDimitry Andric /// Fractional flow. 53981ad6265SDimitry Andric double FracFlow; 54081ad6265SDimitry Andric /// Integral flow. 54181ad6265SDimitry Andric uint64_t IntFlow; 54281ad6265SDimitry Andric /// Discovery time. 54381ad6265SDimitry Andric uint64_t Discovery; 54481ad6265SDimitry Andric /// Finish time. 54581ad6265SDimitry Andric uint64_t Finish; 54681ad6265SDimitry Andric /// NumCalls. 54781ad6265SDimitry Andric uint64_t NumCalls; 5484824e7fdSDimitry Andric }; 54981ad6265SDimitry Andric 5504824e7fdSDimitry Andric /// An edge in a flow network. 5514824e7fdSDimitry Andric struct Edge { 5524824e7fdSDimitry Andric /// The cost of the edge. 5534824e7fdSDimitry Andric int64_t Cost; 5544824e7fdSDimitry Andric /// The capacity of the edge. 5554824e7fdSDimitry Andric int64_t Capacity; 5564824e7fdSDimitry Andric /// The current flow on the edge. 5574824e7fdSDimitry Andric int64_t Flow; 5584824e7fdSDimitry Andric /// The destination node of the edge. 5594824e7fdSDimitry Andric uint64_t Dst; 5604824e7fdSDimitry Andric /// The index of the reverse edge between Dst and the current node. 5614824e7fdSDimitry Andric uint64_t RevEdgeIndex; 56281ad6265SDimitry Andric 56381ad6265SDimitry Andric /// Data fields utilized in DAG-augmentation: 56481ad6265SDimitry Andric /// Whether the edge is currently on a shortest path from Source to Target. 56581ad6265SDimitry Andric bool OnShortestPath; 56681ad6265SDimitry Andric /// Extra flow along the edge. 56781ad6265SDimitry Andric uint64_t AugmentedFlow; 5684824e7fdSDimitry Andric }; 5694824e7fdSDimitry Andric 5704824e7fdSDimitry Andric /// The set of network nodes. 5714824e7fdSDimitry Andric std::vector<Node> Nodes; 5724824e7fdSDimitry Andric /// The set of network edges. 5734824e7fdSDimitry Andric std::vector<std::vector<Edge>> Edges; 5744824e7fdSDimitry Andric /// Source node of the flow. 5754824e7fdSDimitry Andric uint64_t Source; 5764824e7fdSDimitry Andric /// Target (sink) node of the flow. 5774824e7fdSDimitry Andric uint64_t Target; 57881ad6265SDimitry Andric /// Augmenting edges. 57981ad6265SDimitry Andric std::vector<std::vector<Edge *>> AugmentingEdges; 580bdd1243dSDimitry Andric /// Params for flow computation. 581bdd1243dSDimitry Andric const ProfiParams &Params; 5824824e7fdSDimitry Andric }; 5834824e7fdSDimitry Andric 584bdd1243dSDimitry Andric /// A post-processing adjustment of the control flow. It applies two steps by 5850eae32dcSDimitry Andric /// rerouting some flow and making it more realistic: 5860eae32dcSDimitry Andric /// 5870eae32dcSDimitry Andric /// - First, it removes all isolated components ("islands") with a positive flow 5880eae32dcSDimitry Andric /// that are unreachable from the entry block. For every such component, we 5890eae32dcSDimitry Andric /// find the shortest from the entry to an exit passing through the component, 5900eae32dcSDimitry Andric /// and increase the flow by one unit along the path. 5910eae32dcSDimitry Andric /// 5920eae32dcSDimitry Andric /// - Second, it identifies all "unknown subgraphs" consisting of basic blocks 5930eae32dcSDimitry Andric /// with no sampled counts. Then it rebalnces the flow that goes through such 5940eae32dcSDimitry Andric /// a subgraph so that each branch is taken with probability 50%. 5950eae32dcSDimitry Andric /// An unknown subgraph is such that for every two nodes u and v: 5960eae32dcSDimitry Andric /// - u dominates v and u is not unknown; 5970eae32dcSDimitry Andric /// - v post-dominates u; and 5980eae32dcSDimitry Andric /// - all inner-nodes of all (u,v)-paths are unknown. 5990eae32dcSDimitry Andric /// 6000eae32dcSDimitry Andric class FlowAdjuster { 6010eae32dcSDimitry Andric public: 602bdd1243dSDimitry Andric FlowAdjuster(const ProfiParams &Params, FlowFunction &Func) 603bdd1243dSDimitry Andric : Params(Params), Func(Func) {} 604bdd1243dSDimitry Andric 605bdd1243dSDimitry Andric /// Apply the post-processing. 606bdd1243dSDimitry Andric void run() { 607bdd1243dSDimitry Andric if (Params.JoinIslands) { 608bdd1243dSDimitry Andric // Adjust the flow to get rid of isolated components 609bdd1243dSDimitry Andric joinIsolatedComponents(); 6100eae32dcSDimitry Andric } 6110eae32dcSDimitry Andric 612bdd1243dSDimitry Andric if (Params.RebalanceUnknown) { 613bdd1243dSDimitry Andric // Rebalance the flow inside unknown subgraphs 6140eae32dcSDimitry Andric rebalanceUnknownSubgraphs(); 6150eae32dcSDimitry Andric } 616bdd1243dSDimitry Andric } 6170eae32dcSDimitry Andric 6180eae32dcSDimitry Andric private: 6190eae32dcSDimitry Andric void joinIsolatedComponents() { 6200eae32dcSDimitry Andric // Find blocks that are reachable from the source 62104eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks(), false); 6220eae32dcSDimitry Andric findReachable(Func.Entry, Visited); 6230eae32dcSDimitry Andric 6240eae32dcSDimitry Andric // Iterate over all non-reachable blocks and adjust their weights 6250eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks(); I++) { 6260eae32dcSDimitry Andric auto &Block = Func.Blocks[I]; 6270eae32dcSDimitry Andric if (Block.Flow > 0 && !Visited[I]) { 6280eae32dcSDimitry Andric // Find a path from the entry to an exit passing through the block I 6290eae32dcSDimitry Andric auto Path = findShortestPath(I); 6300eae32dcSDimitry Andric // Increase the flow along the path 6310eae32dcSDimitry Andric assert(Path.size() > 0 && Path[0]->Source == Func.Entry && 6320eae32dcSDimitry Andric "incorrectly computed path adjusting control flow"); 6330eae32dcSDimitry Andric Func.Blocks[Func.Entry].Flow += 1; 6340eae32dcSDimitry Andric for (auto &Jump : Path) { 6350eae32dcSDimitry Andric Jump->Flow += 1; 6360eae32dcSDimitry Andric Func.Blocks[Jump->Target].Flow += 1; 6370eae32dcSDimitry Andric // Update reachability 6380eae32dcSDimitry Andric findReachable(Jump->Target, Visited); 6390eae32dcSDimitry Andric } 6400eae32dcSDimitry Andric } 6410eae32dcSDimitry Andric } 6420eae32dcSDimitry Andric } 6430eae32dcSDimitry Andric 6440eae32dcSDimitry Andric /// Run BFS from a given block along the jumps with a positive flow and mark 6450eae32dcSDimitry Andric /// all reachable blocks. 64604eeddc0SDimitry Andric void findReachable(uint64_t Src, BitVector &Visited) { 6470eae32dcSDimitry Andric if (Visited[Src]) 6480eae32dcSDimitry Andric return; 6490eae32dcSDimitry Andric std::queue<uint64_t> Queue; 6500eae32dcSDimitry Andric Queue.push(Src); 6510eae32dcSDimitry Andric Visited[Src] = true; 6520eae32dcSDimitry Andric while (!Queue.empty()) { 6530eae32dcSDimitry Andric Src = Queue.front(); 6540eae32dcSDimitry Andric Queue.pop(); 655bdd1243dSDimitry Andric for (auto *Jump : Func.Blocks[Src].SuccJumps) { 6560eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 6570eae32dcSDimitry Andric if (Jump->Flow > 0 && !Visited[Dst]) { 6580eae32dcSDimitry Andric Queue.push(Dst); 6590eae32dcSDimitry Andric Visited[Dst] = true; 6600eae32dcSDimitry Andric } 6610eae32dcSDimitry Andric } 6620eae32dcSDimitry Andric } 6630eae32dcSDimitry Andric } 6640eae32dcSDimitry Andric 6650eae32dcSDimitry Andric /// Find the shortest path from the entry block to an exit block passing 6660eae32dcSDimitry Andric /// through a given block. 6670eae32dcSDimitry Andric std::vector<FlowJump *> findShortestPath(uint64_t BlockIdx) { 6680eae32dcSDimitry Andric // A path from the entry block to BlockIdx 6690eae32dcSDimitry Andric auto ForwardPath = findShortestPath(Func.Entry, BlockIdx); 6700eae32dcSDimitry Andric // A path from BlockIdx to an exit block 6710eae32dcSDimitry Andric auto BackwardPath = findShortestPath(BlockIdx, AnyExitBlock); 6720eae32dcSDimitry Andric 6730eae32dcSDimitry Andric // Concatenate the two paths 6740eae32dcSDimitry Andric std::vector<FlowJump *> Result; 6750eae32dcSDimitry Andric Result.insert(Result.end(), ForwardPath.begin(), ForwardPath.end()); 6760eae32dcSDimitry Andric Result.insert(Result.end(), BackwardPath.begin(), BackwardPath.end()); 6770eae32dcSDimitry Andric return Result; 6780eae32dcSDimitry Andric } 6790eae32dcSDimitry Andric 6800eae32dcSDimitry Andric /// Apply the Dijkstra algorithm to find the shortest path from a given 6810eae32dcSDimitry Andric /// Source to a given Target block. 6820eae32dcSDimitry Andric /// If Target == -1, then the path ends at an exit block. 6830eae32dcSDimitry Andric std::vector<FlowJump *> findShortestPath(uint64_t Source, uint64_t Target) { 6840eae32dcSDimitry Andric // Quit early, if possible 6850eae32dcSDimitry Andric if (Source == Target) 6860eae32dcSDimitry Andric return std::vector<FlowJump *>(); 6870eae32dcSDimitry Andric if (Func.Blocks[Source].isExit() && Target == AnyExitBlock) 6880eae32dcSDimitry Andric return std::vector<FlowJump *>(); 6890eae32dcSDimitry Andric 6900eae32dcSDimitry Andric // Initialize data structures 6910eae32dcSDimitry Andric auto Distance = std::vector<int64_t>(NumBlocks(), INF); 6920eae32dcSDimitry Andric auto Parent = std::vector<FlowJump *>(NumBlocks(), nullptr); 6930eae32dcSDimitry Andric Distance[Source] = 0; 6940eae32dcSDimitry Andric std::set<std::pair<uint64_t, uint64_t>> Queue; 6950eae32dcSDimitry Andric Queue.insert(std::make_pair(Distance[Source], Source)); 6960eae32dcSDimitry Andric 6970eae32dcSDimitry Andric // Run the Dijkstra algorithm 6980eae32dcSDimitry Andric while (!Queue.empty()) { 6990eae32dcSDimitry Andric uint64_t Src = Queue.begin()->second; 7000eae32dcSDimitry Andric Queue.erase(Queue.begin()); 7010eae32dcSDimitry Andric // If we found a solution, quit early 7020eae32dcSDimitry Andric if (Src == Target || 7030eae32dcSDimitry Andric (Func.Blocks[Src].isExit() && Target == AnyExitBlock)) 7040eae32dcSDimitry Andric break; 7050eae32dcSDimitry Andric 706bdd1243dSDimitry Andric for (auto *Jump : Func.Blocks[Src].SuccJumps) { 7070eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 7080eae32dcSDimitry Andric int64_t JumpDist = jumpDistance(Jump); 7090eae32dcSDimitry Andric if (Distance[Dst] > Distance[Src] + JumpDist) { 7100eae32dcSDimitry Andric Queue.erase(std::make_pair(Distance[Dst], Dst)); 7110eae32dcSDimitry Andric 7120eae32dcSDimitry Andric Distance[Dst] = Distance[Src] + JumpDist; 7130eae32dcSDimitry Andric Parent[Dst] = Jump; 7140eae32dcSDimitry Andric 7150eae32dcSDimitry Andric Queue.insert(std::make_pair(Distance[Dst], Dst)); 7160eae32dcSDimitry Andric } 7170eae32dcSDimitry Andric } 7180eae32dcSDimitry Andric } 7190eae32dcSDimitry Andric // If Target is not provided, find the closest exit block 7200eae32dcSDimitry Andric if (Target == AnyExitBlock) { 7210eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks(); I++) { 7220eae32dcSDimitry Andric if (Func.Blocks[I].isExit() && Parent[I] != nullptr) { 7230eae32dcSDimitry Andric if (Target == AnyExitBlock || Distance[Target] > Distance[I]) { 7240eae32dcSDimitry Andric Target = I; 7250eae32dcSDimitry Andric } 7260eae32dcSDimitry Andric } 7270eae32dcSDimitry Andric } 7280eae32dcSDimitry Andric } 7290eae32dcSDimitry Andric assert(Parent[Target] != nullptr && "a path does not exist"); 7300eae32dcSDimitry Andric 7310eae32dcSDimitry Andric // Extract the constructed path 7320eae32dcSDimitry Andric std::vector<FlowJump *> Result; 7330eae32dcSDimitry Andric uint64_t Now = Target; 7340eae32dcSDimitry Andric while (Now != Source) { 7350eae32dcSDimitry Andric assert(Now == Parent[Now]->Target && "incorrect parent jump"); 7360eae32dcSDimitry Andric Result.push_back(Parent[Now]); 7370eae32dcSDimitry Andric Now = Parent[Now]->Source; 7380eae32dcSDimitry Andric } 7390eae32dcSDimitry Andric // Reverse the path, since it is extracted from Target to Source 7400eae32dcSDimitry Andric std::reverse(Result.begin(), Result.end()); 7410eae32dcSDimitry Andric return Result; 7420eae32dcSDimitry Andric } 7430eae32dcSDimitry Andric 7440eae32dcSDimitry Andric /// A distance of a path for a given jump. 7450eae32dcSDimitry Andric /// In order to incite the path to use blocks/jumps with large positive flow, 7460eae32dcSDimitry Andric /// and avoid changing branch probability of outgoing edges drastically, 74781ad6265SDimitry Andric /// set the jump distance so as: 74881ad6265SDimitry Andric /// - to minimize the number of unlikely jumps used and subject to that, 74981ad6265SDimitry Andric /// - to minimize the number of Flow == 0 jumps used and subject to that, 75081ad6265SDimitry Andric /// - minimizes total multiplicative Flow increase for the remaining edges. 75181ad6265SDimitry Andric /// To capture this objective with integer distances, we round off fractional 75281ad6265SDimitry Andric /// parts to a multiple of 1 / BaseDistance. 7530eae32dcSDimitry Andric int64_t jumpDistance(FlowJump *Jump) const { 7540eae32dcSDimitry Andric if (Jump->IsUnlikely) 755bdd1243dSDimitry Andric return Params.CostUnlikely; 756bdd1243dSDimitry Andric uint64_t BaseDistance = 757bdd1243dSDimitry Andric std::max(FlowAdjuster::MinBaseDistance, 758bdd1243dSDimitry Andric std::min(Func.Blocks[Func.Entry].Flow, 759bdd1243dSDimitry Andric Params.CostUnlikely / (2 * (NumBlocks() + 1)))); 7600eae32dcSDimitry Andric if (Jump->Flow > 0) 76181ad6265SDimitry Andric return BaseDistance + BaseDistance / Jump->Flow; 762bdd1243dSDimitry Andric return 2 * BaseDistance * (NumBlocks() + 1); 7630eae32dcSDimitry Andric }; 7640eae32dcSDimitry Andric 7650eae32dcSDimitry Andric uint64_t NumBlocks() const { return Func.Blocks.size(); } 7660eae32dcSDimitry Andric 76704eeddc0SDimitry Andric /// Rebalance unknown subgraphs so that the flow is split evenly across the 76804eeddc0SDimitry Andric /// outgoing branches of every block of the subgraph. The method iterates over 76904eeddc0SDimitry Andric /// blocks with known weight and identifies unknown subgraphs rooted at the 77004eeddc0SDimitry Andric /// blocks. Then it verifies if flow rebalancing is feasible and applies it. 7710eae32dcSDimitry Andric void rebalanceUnknownSubgraphs() { 77204eeddc0SDimitry Andric // Try to find unknown subgraphs from each block 773bdd1243dSDimitry Andric for (const FlowBlock &SrcBlock : Func.Blocks) { 77404eeddc0SDimitry Andric // Verify if rebalancing rooted at SrcBlock is feasible 775bdd1243dSDimitry Andric if (!canRebalanceAtRoot(&SrcBlock)) 7760eae32dcSDimitry Andric continue; 7770eae32dcSDimitry Andric 77804eeddc0SDimitry Andric // Find an unknown subgraphs starting at SrcBlock. Along the way, 77904eeddc0SDimitry Andric // fill in known destinations and intermediate unknown blocks. 78004eeddc0SDimitry Andric std::vector<FlowBlock *> UnknownBlocks; 78104eeddc0SDimitry Andric std::vector<FlowBlock *> KnownDstBlocks; 782bdd1243dSDimitry Andric findUnknownSubgraph(&SrcBlock, KnownDstBlocks, UnknownBlocks); 78304eeddc0SDimitry Andric 78404eeddc0SDimitry Andric // Verify if rebalancing of the subgraph is feasible. If the search is 78504eeddc0SDimitry Andric // successful, find the unique destination block (which can be null) 7860eae32dcSDimitry Andric FlowBlock *DstBlock = nullptr; 787bdd1243dSDimitry Andric if (!canRebalanceSubgraph(&SrcBlock, KnownDstBlocks, UnknownBlocks, 78804eeddc0SDimitry Andric DstBlock)) 7890eae32dcSDimitry Andric continue; 79004eeddc0SDimitry Andric 79104eeddc0SDimitry Andric // We cannot rebalance subgraphs containing cycles among unknown blocks 792bdd1243dSDimitry Andric if (!isAcyclicSubgraph(&SrcBlock, DstBlock, UnknownBlocks)) 7930eae32dcSDimitry Andric continue; 7940eae32dcSDimitry Andric 7950eae32dcSDimitry Andric // Rebalance the flow 796bdd1243dSDimitry Andric rebalanceUnknownSubgraph(&SrcBlock, DstBlock, UnknownBlocks); 7970eae32dcSDimitry Andric } 7980eae32dcSDimitry Andric } 7990eae32dcSDimitry Andric 80004eeddc0SDimitry Andric /// Verify if rebalancing rooted at a given block is possible. 80104eeddc0SDimitry Andric bool canRebalanceAtRoot(const FlowBlock *SrcBlock) { 80204eeddc0SDimitry Andric // Do not attempt to find unknown subgraphs from an unknown or a 80304eeddc0SDimitry Andric // zero-flow block 804bdd1243dSDimitry Andric if (SrcBlock->HasUnknownWeight || SrcBlock->Flow == 0) 80504eeddc0SDimitry Andric return false; 80604eeddc0SDimitry Andric 80704eeddc0SDimitry Andric // Do not attempt to process subgraphs from a block w/o unknown sucessors 80804eeddc0SDimitry Andric bool HasUnknownSuccs = false; 809bdd1243dSDimitry Andric for (auto *Jump : SrcBlock->SuccJumps) { 810bdd1243dSDimitry Andric if (Func.Blocks[Jump->Target].HasUnknownWeight) { 81104eeddc0SDimitry Andric HasUnknownSuccs = true; 81204eeddc0SDimitry Andric break; 81304eeddc0SDimitry Andric } 81404eeddc0SDimitry Andric } 81504eeddc0SDimitry Andric if (!HasUnknownSuccs) 81604eeddc0SDimitry Andric return false; 81704eeddc0SDimitry Andric 81804eeddc0SDimitry Andric return true; 81904eeddc0SDimitry Andric } 82004eeddc0SDimitry Andric 82104eeddc0SDimitry Andric /// Find an unknown subgraph starting at block SrcBlock. The method sets 82204eeddc0SDimitry Andric /// identified destinations, KnownDstBlocks, and intermediate UnknownBlocks. 82304eeddc0SDimitry Andric void findUnknownSubgraph(const FlowBlock *SrcBlock, 82404eeddc0SDimitry Andric std::vector<FlowBlock *> &KnownDstBlocks, 82504eeddc0SDimitry Andric std::vector<FlowBlock *> &UnknownBlocks) { 8260eae32dcSDimitry Andric // Run BFS from SrcBlock and make sure all paths are going through unknown 82781ad6265SDimitry Andric // blocks and end at a known DstBlock 82804eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks(), false); 8290eae32dcSDimitry Andric std::queue<uint64_t> Queue; 8300eae32dcSDimitry Andric 8310eae32dcSDimitry Andric Queue.push(SrcBlock->Index); 8320eae32dcSDimitry Andric Visited[SrcBlock->Index] = true; 8330eae32dcSDimitry Andric while (!Queue.empty()) { 8340eae32dcSDimitry Andric auto &Block = Func.Blocks[Queue.front()]; 8350eae32dcSDimitry Andric Queue.pop(); 8360eae32dcSDimitry Andric // Process blocks reachable from Block 837bdd1243dSDimitry Andric for (auto *Jump : Block.SuccJumps) { 83804eeddc0SDimitry Andric // If Jump can be ignored, skip it 83904eeddc0SDimitry Andric if (ignoreJump(SrcBlock, nullptr, Jump)) 84004eeddc0SDimitry Andric continue; 84104eeddc0SDimitry Andric 8420eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 84304eeddc0SDimitry Andric // If Dst has been visited, skip Jump 8440eae32dcSDimitry Andric if (Visited[Dst]) 8450eae32dcSDimitry Andric continue; 84604eeddc0SDimitry Andric // Process block Dst 8470eae32dcSDimitry Andric Visited[Dst] = true; 848bdd1243dSDimitry Andric if (!Func.Blocks[Dst].HasUnknownWeight) { 84904eeddc0SDimitry Andric KnownDstBlocks.push_back(&Func.Blocks[Dst]); 8500eae32dcSDimitry Andric } else { 8510eae32dcSDimitry Andric Queue.push(Dst); 85204eeddc0SDimitry Andric UnknownBlocks.push_back(&Func.Blocks[Dst]); 85304eeddc0SDimitry Andric } 8540eae32dcSDimitry Andric } 8550eae32dcSDimitry Andric } 8560eae32dcSDimitry Andric } 8570eae32dcSDimitry Andric 85804eeddc0SDimitry Andric /// Verify if rebalancing of the subgraph is feasible. If the checks are 85904eeddc0SDimitry Andric /// successful, set the unique destination block, DstBlock (can be null). 86004eeddc0SDimitry Andric bool canRebalanceSubgraph(const FlowBlock *SrcBlock, 86104eeddc0SDimitry Andric const std::vector<FlowBlock *> &KnownDstBlocks, 86204eeddc0SDimitry Andric const std::vector<FlowBlock *> &UnknownBlocks, 86304eeddc0SDimitry Andric FlowBlock *&DstBlock) { 8640eae32dcSDimitry Andric // If the list of unknown blocks is empty, we don't need rebalancing 86504eeddc0SDimitry Andric if (UnknownBlocks.empty()) 8660eae32dcSDimitry Andric return false; 86704eeddc0SDimitry Andric 86804eeddc0SDimitry Andric // If there are multiple known sinks, we can't rebalance 86904eeddc0SDimitry Andric if (KnownDstBlocks.size() > 1) 8700eae32dcSDimitry Andric return false; 87104eeddc0SDimitry Andric DstBlock = KnownDstBlocks.empty() ? nullptr : KnownDstBlocks.front(); 87204eeddc0SDimitry Andric 87304eeddc0SDimitry Andric // Verify sinks of the subgraph 874bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 87504eeddc0SDimitry Andric if (Block->SuccJumps.empty()) { 87604eeddc0SDimitry Andric // If there are multiple (known and unknown) sinks, we can't rebalance 87704eeddc0SDimitry Andric if (DstBlock != nullptr) 87804eeddc0SDimitry Andric return false; 87904eeddc0SDimitry Andric continue; 88004eeddc0SDimitry Andric } 88104eeddc0SDimitry Andric size_t NumIgnoredJumps = 0; 882bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 88304eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 88404eeddc0SDimitry Andric NumIgnoredJumps++; 88504eeddc0SDimitry Andric } 88604eeddc0SDimitry Andric // If there is a non-sink block in UnknownBlocks with all jumps ignored, 88704eeddc0SDimitry Andric // then we can't rebalance 88804eeddc0SDimitry Andric if (NumIgnoredJumps == Block->SuccJumps.size()) 8890eae32dcSDimitry Andric return false; 8900eae32dcSDimitry Andric } 8910eae32dcSDimitry Andric 8920eae32dcSDimitry Andric return true; 8930eae32dcSDimitry Andric } 8940eae32dcSDimitry Andric 89504eeddc0SDimitry Andric /// Decide whether the Jump is ignored while processing an unknown subgraphs 89604eeddc0SDimitry Andric /// rooted at basic block SrcBlock with the destination block, DstBlock. 89704eeddc0SDimitry Andric bool ignoreJump(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 89804eeddc0SDimitry Andric const FlowJump *Jump) { 89904eeddc0SDimitry Andric // Ignore unlikely jumps with zero flow 90004eeddc0SDimitry Andric if (Jump->IsUnlikely && Jump->Flow == 0) 90104eeddc0SDimitry Andric return true; 90204eeddc0SDimitry Andric 90304eeddc0SDimitry Andric auto JumpSource = &Func.Blocks[Jump->Source]; 90404eeddc0SDimitry Andric auto JumpTarget = &Func.Blocks[Jump->Target]; 90504eeddc0SDimitry Andric 90604eeddc0SDimitry Andric // Do not ignore jumps coming into DstBlock 90704eeddc0SDimitry Andric if (DstBlock != nullptr && JumpTarget == DstBlock) 90804eeddc0SDimitry Andric return false; 90904eeddc0SDimitry Andric 91004eeddc0SDimitry Andric // Ignore jumps out of SrcBlock to known blocks 911bdd1243dSDimitry Andric if (!JumpTarget->HasUnknownWeight && JumpSource == SrcBlock) 91204eeddc0SDimitry Andric return true; 91304eeddc0SDimitry Andric 91404eeddc0SDimitry Andric // Ignore jumps to known blocks with zero flow 915bdd1243dSDimitry Andric if (!JumpTarget->HasUnknownWeight && JumpTarget->Flow == 0) 91604eeddc0SDimitry Andric return true; 91704eeddc0SDimitry Andric 91804eeddc0SDimitry Andric return false; 91904eeddc0SDimitry Andric } 92004eeddc0SDimitry Andric 9210eae32dcSDimitry Andric /// Verify if the given unknown subgraph is acyclic, and if yes, reorder 92204eeddc0SDimitry Andric /// UnknownBlocks in the topological order (so that all jumps are "forward"). 92304eeddc0SDimitry Andric bool isAcyclicSubgraph(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 92404eeddc0SDimitry Andric std::vector<FlowBlock *> &UnknownBlocks) { 9250eae32dcSDimitry Andric // Extract local in-degrees in the considered subgraph 9260eae32dcSDimitry Andric auto LocalInDegree = std::vector<uint64_t>(NumBlocks(), 0); 92704eeddc0SDimitry Andric auto fillInDegree = [&](const FlowBlock *Block) { 928bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 92904eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 93004eeddc0SDimitry Andric continue; 9310eae32dcSDimitry Andric LocalInDegree[Jump->Target]++; 9320eae32dcSDimitry Andric } 93304eeddc0SDimitry Andric }; 93404eeddc0SDimitry Andric fillInDegree(SrcBlock); 935bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 93604eeddc0SDimitry Andric fillInDegree(Block); 9370eae32dcSDimitry Andric } 9380eae32dcSDimitry Andric // A loop containing SrcBlock 9390eae32dcSDimitry Andric if (LocalInDegree[SrcBlock->Index] > 0) 9400eae32dcSDimitry Andric return false; 9410eae32dcSDimitry Andric 9420eae32dcSDimitry Andric std::vector<FlowBlock *> AcyclicOrder; 9430eae32dcSDimitry Andric std::queue<uint64_t> Queue; 9440eae32dcSDimitry Andric Queue.push(SrcBlock->Index); 9450eae32dcSDimitry Andric while (!Queue.empty()) { 94604eeddc0SDimitry Andric FlowBlock *Block = &Func.Blocks[Queue.front()]; 9470eae32dcSDimitry Andric Queue.pop(); 94804eeddc0SDimitry Andric // Stop propagation once we reach DstBlock, if any 94904eeddc0SDimitry Andric if (DstBlock != nullptr && Block == DstBlock) 9500eae32dcSDimitry Andric break; 9510eae32dcSDimitry Andric 95204eeddc0SDimitry Andric // Keep an acyclic order of unknown blocks 953bdd1243dSDimitry Andric if (Block->HasUnknownWeight && Block != SrcBlock) 95404eeddc0SDimitry Andric AcyclicOrder.push_back(Block); 95504eeddc0SDimitry Andric 9560eae32dcSDimitry Andric // Add to the queue all successors with zero local in-degree 957bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 95804eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 95904eeddc0SDimitry Andric continue; 9600eae32dcSDimitry Andric uint64_t Dst = Jump->Target; 9610eae32dcSDimitry Andric LocalInDegree[Dst]--; 9620eae32dcSDimitry Andric if (LocalInDegree[Dst] == 0) { 9630eae32dcSDimitry Andric Queue.push(Dst); 9640eae32dcSDimitry Andric } 9650eae32dcSDimitry Andric } 9660eae32dcSDimitry Andric } 9670eae32dcSDimitry Andric 9680eae32dcSDimitry Andric // If there is a cycle in the subgraph, AcyclicOrder contains only a subset 9690eae32dcSDimitry Andric // of all blocks 97004eeddc0SDimitry Andric if (UnknownBlocks.size() != AcyclicOrder.size()) 9710eae32dcSDimitry Andric return false; 97204eeddc0SDimitry Andric UnknownBlocks = AcyclicOrder; 9730eae32dcSDimitry Andric return true; 9740eae32dcSDimitry Andric } 9750eae32dcSDimitry Andric 97604eeddc0SDimitry Andric /// Rebalance a given subgraph rooted at SrcBlock, ending at DstBlock and 97704eeddc0SDimitry Andric /// having UnknownBlocks intermediate blocks. 97804eeddc0SDimitry Andric void rebalanceUnknownSubgraph(const FlowBlock *SrcBlock, 97904eeddc0SDimitry Andric const FlowBlock *DstBlock, 98004eeddc0SDimitry Andric const std::vector<FlowBlock *> &UnknownBlocks) { 9810eae32dcSDimitry Andric assert(SrcBlock->Flow > 0 && "zero-flow block in unknown subgraph"); 9820eae32dcSDimitry Andric 98304eeddc0SDimitry Andric // Ditribute flow from the source block 98404eeddc0SDimitry Andric uint64_t BlockFlow = 0; 98504eeddc0SDimitry Andric // SrcBlock's flow is the sum of outgoing flows along non-ignored jumps 986bdd1243dSDimitry Andric for (auto *Jump : SrcBlock->SuccJumps) { 98704eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 9880eae32dcSDimitry Andric continue; 98904eeddc0SDimitry Andric BlockFlow += Jump->Flow; 9900eae32dcSDimitry Andric } 99104eeddc0SDimitry Andric rebalanceBlock(SrcBlock, DstBlock, SrcBlock, BlockFlow); 99204eeddc0SDimitry Andric 99304eeddc0SDimitry Andric // Ditribute flow from the remaining blocks 994bdd1243dSDimitry Andric for (auto *Block : UnknownBlocks) { 995bdd1243dSDimitry Andric assert(Block->HasUnknownWeight && "incorrect unknown subgraph"); 99604eeddc0SDimitry Andric uint64_t BlockFlow = 0; 99704eeddc0SDimitry Andric // Block's flow is the sum of incoming flows 998bdd1243dSDimitry Andric for (auto *Jump : Block->PredJumps) { 99904eeddc0SDimitry Andric BlockFlow += Jump->Flow; 100004eeddc0SDimitry Andric } 100104eeddc0SDimitry Andric Block->Flow = BlockFlow; 100204eeddc0SDimitry Andric rebalanceBlock(SrcBlock, DstBlock, Block, BlockFlow); 100304eeddc0SDimitry Andric } 100404eeddc0SDimitry Andric } 100504eeddc0SDimitry Andric 100604eeddc0SDimitry Andric /// Redistribute flow for a block in a subgraph rooted at SrcBlock, 100704eeddc0SDimitry Andric /// and ending at DstBlock. 100804eeddc0SDimitry Andric void rebalanceBlock(const FlowBlock *SrcBlock, const FlowBlock *DstBlock, 100904eeddc0SDimitry Andric const FlowBlock *Block, uint64_t BlockFlow) { 101004eeddc0SDimitry Andric // Process all successor jumps and update corresponding flow values 101104eeddc0SDimitry Andric size_t BlockDegree = 0; 1012bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 101304eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 101404eeddc0SDimitry Andric continue; 101504eeddc0SDimitry Andric BlockDegree++; 101604eeddc0SDimitry Andric } 101704eeddc0SDimitry Andric // If all successor jumps of the block are ignored, skip it 101804eeddc0SDimitry Andric if (DstBlock == nullptr && BlockDegree == 0) 101904eeddc0SDimitry Andric return; 102004eeddc0SDimitry Andric assert(BlockDegree > 0 && "all outgoing jumps are ignored"); 102104eeddc0SDimitry Andric 102204eeddc0SDimitry Andric // Each of the Block's successors gets the following amount of flow. 102304eeddc0SDimitry Andric // Rounding the value up so that all flow is propagated 102404eeddc0SDimitry Andric uint64_t SuccFlow = (BlockFlow + BlockDegree - 1) / BlockDegree; 1025bdd1243dSDimitry Andric for (auto *Jump : Block->SuccJumps) { 102604eeddc0SDimitry Andric if (ignoreJump(SrcBlock, DstBlock, Jump)) 102704eeddc0SDimitry Andric continue; 102804eeddc0SDimitry Andric uint64_t Flow = std::min(SuccFlow, BlockFlow); 10290eae32dcSDimitry Andric Jump->Flow = Flow; 103004eeddc0SDimitry Andric BlockFlow -= Flow; 10310eae32dcSDimitry Andric } 103204eeddc0SDimitry Andric assert(BlockFlow == 0 && "not all flow is propagated"); 10330eae32dcSDimitry Andric } 10340eae32dcSDimitry Andric 10350eae32dcSDimitry Andric /// A constant indicating an arbitrary exit block of a function. 10360eae32dcSDimitry Andric static constexpr uint64_t AnyExitBlock = uint64_t(-1); 1037bdd1243dSDimitry Andric /// Minimum BaseDistance for the jump distance values in island joining. 1038bdd1243dSDimitry Andric static constexpr uint64_t MinBaseDistance = 10000; 10390eae32dcSDimitry Andric 1040bdd1243dSDimitry Andric /// Params for flow computation. 1041bdd1243dSDimitry Andric const ProfiParams &Params; 10420eae32dcSDimitry Andric /// The function. 10430eae32dcSDimitry Andric FlowFunction &Func; 10440eae32dcSDimitry Andric }; 10450eae32dcSDimitry Andric 1046bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params, 1047bdd1243dSDimitry Andric const FlowBlock &Block); 1048bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params, 1049bdd1243dSDimitry Andric const FlowJump &Jump); 1050bdd1243dSDimitry Andric 10514824e7fdSDimitry Andric /// Initializing flow network for a given function. 10524824e7fdSDimitry Andric /// 1053bdd1243dSDimitry Andric /// Every block is split into two nodes that are responsible for (i) an 1054bdd1243dSDimitry Andric /// incoming flow, (ii) an outgoing flow; they penalize an increase or a 10554824e7fdSDimitry Andric /// reduction of the block weight. 1056bdd1243dSDimitry Andric void initializeNetwork(const ProfiParams &Params, MinCostMaxFlow &Network, 1057bdd1243dSDimitry Andric FlowFunction &Func) { 10584824e7fdSDimitry Andric uint64_t NumBlocks = Func.Blocks.size(); 10594824e7fdSDimitry Andric assert(NumBlocks > 1 && "Too few blocks in a function"); 1060bdd1243dSDimitry Andric uint64_t NumJumps = Func.Jumps.size(); 1061bdd1243dSDimitry Andric assert(NumJumps > 0 && "Too few jumps in a function"); 10624824e7fdSDimitry Andric 10634824e7fdSDimitry Andric // Introducing dummy source/sink pairs to allow flow circulation. 1064*0fca6ea1SDimitry Andric // The nodes corresponding to blocks of the function have indices in 1065bdd1243dSDimitry Andric // the range [0 .. 2 * NumBlocks); the dummy sources/sinks are indexed by the 1066bdd1243dSDimitry Andric // next four values. 1067bdd1243dSDimitry Andric uint64_t S = 2 * NumBlocks; 10684824e7fdSDimitry Andric uint64_t T = S + 1; 10694824e7fdSDimitry Andric uint64_t S1 = S + 2; 10704824e7fdSDimitry Andric uint64_t T1 = S + 3; 10714824e7fdSDimitry Andric 1072bdd1243dSDimitry Andric Network.initialize(2 * NumBlocks + 4, S1, T1); 10734824e7fdSDimitry Andric 1074bdd1243dSDimitry Andric // Initialize nodes of the flow network 10754824e7fdSDimitry Andric for (uint64_t B = 0; B < NumBlocks; B++) { 10764824e7fdSDimitry Andric auto &Block = Func.Blocks[B]; 10774824e7fdSDimitry Andric 1078bdd1243dSDimitry Andric // Split every block into two auxiliary nodes to allow 1079bdd1243dSDimitry Andric // increase/reduction of the block count. 1080bdd1243dSDimitry Andric uint64_t Bin = 2 * B; 1081bdd1243dSDimitry Andric uint64_t Bout = 2 * B + 1; 10824824e7fdSDimitry Andric 10834824e7fdSDimitry Andric // Edges from S and to T 10844824e7fdSDimitry Andric if (Block.isEntry()) { 10854824e7fdSDimitry Andric Network.addEdge(S, Bin, 0); 10864824e7fdSDimitry Andric } else if (Block.isExit()) { 10874824e7fdSDimitry Andric Network.addEdge(Bout, T, 0); 10884824e7fdSDimitry Andric } 10894824e7fdSDimitry Andric 1090bdd1243dSDimitry Andric // Assign costs for increasing/decreasing the block counts 1091bdd1243dSDimitry Andric auto [AuxCostInc, AuxCostDec] = assignBlockCosts(Params, Block); 10924824e7fdSDimitry Andric 1093bdd1243dSDimitry Andric // Add the corresponding edges to the network 1094bdd1243dSDimitry Andric Network.addEdge(Bin, Bout, AuxCostInc); 10954824e7fdSDimitry Andric if (Block.Weight > 0) { 1096bdd1243dSDimitry Andric Network.addEdge(Bout, Bin, Block.Weight, AuxCostDec); 1097bdd1243dSDimitry Andric Network.addEdge(S1, Bout, Block.Weight, 0); 1098bdd1243dSDimitry Andric Network.addEdge(Bin, T1, Block.Weight, 0); 10994824e7fdSDimitry Andric } 11004824e7fdSDimitry Andric } 11014824e7fdSDimitry Andric 1102bdd1243dSDimitry Andric // Initialize edges of the flow network 1103bdd1243dSDimitry Andric for (uint64_t J = 0; J < NumJumps; J++) { 1104bdd1243dSDimitry Andric auto &Jump = Func.Jumps[J]; 1105bdd1243dSDimitry Andric 1106bdd1243dSDimitry Andric // Get the endpoints corresponding to the jump 1107bdd1243dSDimitry Andric uint64_t Jin = 2 * Jump.Source + 1; 1108bdd1243dSDimitry Andric uint64_t Jout = 2 * Jump.Target; 1109bdd1243dSDimitry Andric 1110bdd1243dSDimitry Andric // Assign costs for increasing/decreasing the jump counts 1111bdd1243dSDimitry Andric auto [AuxCostInc, AuxCostDec] = assignJumpCosts(Params, Jump); 1112bdd1243dSDimitry Andric 1113bdd1243dSDimitry Andric // Add the corresponding edges to the network 1114bdd1243dSDimitry Andric Network.addEdge(Jin, Jout, AuxCostInc); 1115bdd1243dSDimitry Andric if (Jump.Weight > 0) { 1116bdd1243dSDimitry Andric Network.addEdge(Jout, Jin, Jump.Weight, AuxCostDec); 1117bdd1243dSDimitry Andric Network.addEdge(S1, Jout, Jump.Weight, 0); 1118bdd1243dSDimitry Andric Network.addEdge(Jin, T1, Jump.Weight, 0); 11194824e7fdSDimitry Andric } 11204824e7fdSDimitry Andric } 11214824e7fdSDimitry Andric 11224824e7fdSDimitry Andric // Make sure we have a valid flow circulation 11234824e7fdSDimitry Andric Network.addEdge(T, S, 0); 11244824e7fdSDimitry Andric } 11254824e7fdSDimitry Andric 1126bdd1243dSDimitry Andric /// Assign costs for increasing/decreasing the block counts. 1127bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignBlockCosts(const ProfiParams &Params, 1128bdd1243dSDimitry Andric const FlowBlock &Block) { 1129bdd1243dSDimitry Andric // Modifying the weight of an unlikely block is expensive 1130bdd1243dSDimitry Andric if (Block.IsUnlikely) 1131bdd1243dSDimitry Andric return std::make_pair(Params.CostUnlikely, Params.CostUnlikely); 11324824e7fdSDimitry Andric 1133bdd1243dSDimitry Andric // Assign default values for the costs 1134bdd1243dSDimitry Andric int64_t CostInc = Params.CostBlockInc; 1135bdd1243dSDimitry Andric int64_t CostDec = Params.CostBlockDec; 1136bdd1243dSDimitry Andric // Update the costs depending on the block metadata 1137bdd1243dSDimitry Andric if (Block.HasUnknownWeight) { 1138bdd1243dSDimitry Andric CostInc = Params.CostBlockUnknownInc; 1139bdd1243dSDimitry Andric CostDec = 0; 1140bdd1243dSDimitry Andric } else { 1141bdd1243dSDimitry Andric // Increasing the count for "cold" blocks with zero initial count is more 1142bdd1243dSDimitry Andric // expensive than for "hot" ones 1143bdd1243dSDimitry Andric if (Block.Weight == 0) 1144bdd1243dSDimitry Andric CostInc = Params.CostBlockZeroInc; 1145bdd1243dSDimitry Andric // Modifying the count of the entry block is expensive 1146bdd1243dSDimitry Andric if (Block.isEntry()) { 1147bdd1243dSDimitry Andric CostInc = Params.CostBlockEntryInc; 1148bdd1243dSDimitry Andric CostDec = Params.CostBlockEntryDec; 11494824e7fdSDimitry Andric } 11504824e7fdSDimitry Andric } 1151bdd1243dSDimitry Andric return std::make_pair(CostInc, CostDec); 11524824e7fdSDimitry Andric } 11534824e7fdSDimitry Andric 1154bdd1243dSDimitry Andric /// Assign costs for increasing/decreasing the jump counts. 1155bdd1243dSDimitry Andric std::pair<int64_t, int64_t> assignJumpCosts(const ProfiParams &Params, 1156bdd1243dSDimitry Andric const FlowJump &Jump) { 1157bdd1243dSDimitry Andric // Modifying the weight of an unlikely jump is expensive 1158bdd1243dSDimitry Andric if (Jump.IsUnlikely) 1159bdd1243dSDimitry Andric return std::make_pair(Params.CostUnlikely, Params.CostUnlikely); 1160bdd1243dSDimitry Andric 1161bdd1243dSDimitry Andric // Assign default values for the costs 1162bdd1243dSDimitry Andric int64_t CostInc = Params.CostJumpInc; 1163bdd1243dSDimitry Andric int64_t CostDec = Params.CostJumpDec; 1164bdd1243dSDimitry Andric // Update the costs depending on the block metadata 1165bdd1243dSDimitry Andric if (Jump.Source + 1 == Jump.Target) { 1166bdd1243dSDimitry Andric // Adjusting the fall-through branch 1167bdd1243dSDimitry Andric CostInc = Params.CostJumpFTInc; 1168bdd1243dSDimitry Andric CostDec = Params.CostJumpFTDec; 1169bdd1243dSDimitry Andric } 1170bdd1243dSDimitry Andric if (Jump.HasUnknownWeight) { 1171bdd1243dSDimitry Andric // The cost is different for fall-through and non-fall-through branches 1172bdd1243dSDimitry Andric if (Jump.Source + 1 == Jump.Target) 1173bdd1243dSDimitry Andric CostInc = Params.CostJumpUnknownFTInc; 1174bdd1243dSDimitry Andric else 1175bdd1243dSDimitry Andric CostInc = Params.CostJumpUnknownInc; 1176bdd1243dSDimitry Andric CostDec = 0; 1177bdd1243dSDimitry Andric } else { 1178bdd1243dSDimitry Andric assert(Jump.Weight > 0 && "found zero-weight jump with a positive weight"); 1179bdd1243dSDimitry Andric } 1180bdd1243dSDimitry Andric return std::make_pair(CostInc, CostDec); 1181bdd1243dSDimitry Andric } 1182bdd1243dSDimitry Andric 1183bdd1243dSDimitry Andric /// Extract resulting block and edge counts from the flow network. 1184bdd1243dSDimitry Andric void extractWeights(const ProfiParams &Params, MinCostMaxFlow &Network, 1185bdd1243dSDimitry Andric FlowFunction &Func) { 1186bdd1243dSDimitry Andric uint64_t NumBlocks = Func.Blocks.size(); 1187bdd1243dSDimitry Andric uint64_t NumJumps = Func.Jumps.size(); 1188bdd1243dSDimitry Andric 11894824e7fdSDimitry Andric // Extract resulting jump counts 1190bdd1243dSDimitry Andric for (uint64_t J = 0; J < NumJumps; J++) { 1191bdd1243dSDimitry Andric auto &Jump = Func.Jumps[J]; 1192bdd1243dSDimitry Andric uint64_t SrcOut = 2 * Jump.Source + 1; 1193bdd1243dSDimitry Andric uint64_t DstIn = 2 * Jump.Target; 1194bdd1243dSDimitry Andric 11954824e7fdSDimitry Andric int64_t Flow = 0; 1196bdd1243dSDimitry Andric int64_t AuxFlow = Network.getFlow(SrcOut, DstIn); 1197bdd1243dSDimitry Andric if (Jump.Source != Jump.Target) 1198bdd1243dSDimitry Andric Flow = int64_t(Jump.Weight) + AuxFlow; 1199bdd1243dSDimitry Andric else 1200bdd1243dSDimitry Andric Flow = int64_t(Jump.Weight) + (AuxFlow > 0 ? AuxFlow : 0); 1201bdd1243dSDimitry Andric 12024824e7fdSDimitry Andric Jump.Flow = Flow; 12034824e7fdSDimitry Andric assert(Flow >= 0 && "negative jump flow"); 12044824e7fdSDimitry Andric } 1205bdd1243dSDimitry Andric 1206bdd1243dSDimitry Andric // Extract resulting block counts 1207bdd1243dSDimitry Andric auto InFlow = std::vector<uint64_t>(NumBlocks, 0); 1208bdd1243dSDimitry Andric auto OutFlow = std::vector<uint64_t>(NumBlocks, 0); 1209bdd1243dSDimitry Andric for (auto &Jump : Func.Jumps) { 1210bdd1243dSDimitry Andric InFlow[Jump.Target] += Jump.Flow; 1211bdd1243dSDimitry Andric OutFlow[Jump.Source] += Jump.Flow; 1212bdd1243dSDimitry Andric } 1213bdd1243dSDimitry Andric for (uint64_t B = 0; B < NumBlocks; B++) { 1214bdd1243dSDimitry Andric auto &Block = Func.Blocks[B]; 1215bdd1243dSDimitry Andric Block.Flow = std::max(OutFlow[B], InFlow[B]); 1216bdd1243dSDimitry Andric } 12174824e7fdSDimitry Andric } 12184824e7fdSDimitry Andric 12194824e7fdSDimitry Andric #ifndef NDEBUG 1220bdd1243dSDimitry Andric /// Verify that the provided block/jump weights are as expected. 1221bdd1243dSDimitry Andric void verifyInput(const FlowFunction &Func) { 122206c3fb27SDimitry Andric // Verify entry and exit blocks 1223bdd1243dSDimitry Andric assert(Func.Entry == 0 && Func.Blocks[0].isEntry()); 122406c3fb27SDimitry Andric size_t NumExitBlocks = 0; 1225bdd1243dSDimitry Andric for (size_t I = 1; I < Func.Blocks.size(); I++) { 1226bdd1243dSDimitry Andric assert(!Func.Blocks[I].isEntry() && "multiple entry blocks"); 122706c3fb27SDimitry Andric if (Func.Blocks[I].isExit()) 122806c3fb27SDimitry Andric NumExitBlocks++; 122906c3fb27SDimitry Andric } 123006c3fb27SDimitry Andric assert(NumExitBlocks > 0 && "cannot find exit blocks"); 123106c3fb27SDimitry Andric 123206c3fb27SDimitry Andric // Verify that there are no parallel edges 123306c3fb27SDimitry Andric for (auto &Block : Func.Blocks) { 123406c3fb27SDimitry Andric std::unordered_set<uint64_t> UniqueSuccs; 123506c3fb27SDimitry Andric for (auto &Jump : Block.SuccJumps) { 123606c3fb27SDimitry Andric auto It = UniqueSuccs.insert(Jump->Target); 123706c3fb27SDimitry Andric assert(It.second && "input CFG contains parallel edges"); 123806c3fb27SDimitry Andric } 1239bdd1243dSDimitry Andric } 1240bdd1243dSDimitry Andric // Verify CFG jumps 1241bdd1243dSDimitry Andric for (auto &Block : Func.Blocks) { 1242bdd1243dSDimitry Andric assert((!Block.isEntry() || !Block.isExit()) && 1243bdd1243dSDimitry Andric "a block cannot be an entry and an exit"); 1244bdd1243dSDimitry Andric } 1245bdd1243dSDimitry Andric // Verify input block weights 1246bdd1243dSDimitry Andric for (auto &Block : Func.Blocks) { 1247bdd1243dSDimitry Andric assert((!Block.HasUnknownWeight || Block.Weight == 0 || Block.isEntry()) && 1248bdd1243dSDimitry Andric "non-zero weight of a block w/o weight except for an entry"); 1249bdd1243dSDimitry Andric } 1250bdd1243dSDimitry Andric // Verify input jump weights 1251bdd1243dSDimitry Andric for (auto &Jump : Func.Jumps) { 1252bdd1243dSDimitry Andric assert((!Jump.HasUnknownWeight || Jump.Weight == 0) && 1253bdd1243dSDimitry Andric "non-zero weight of a jump w/o weight"); 1254bdd1243dSDimitry Andric } 1255bdd1243dSDimitry Andric } 1256bdd1243dSDimitry Andric 1257bdd1243dSDimitry Andric /// Verify that the computed flow values satisfy flow conservation rules. 1258bdd1243dSDimitry Andric void verifyOutput(const FlowFunction &Func) { 12594824e7fdSDimitry Andric const uint64_t NumBlocks = Func.Blocks.size(); 12604824e7fdSDimitry Andric auto InFlow = std::vector<uint64_t>(NumBlocks, 0); 12614824e7fdSDimitry Andric auto OutFlow = std::vector<uint64_t>(NumBlocks, 0); 1262bdd1243dSDimitry Andric for (const auto &Jump : Func.Jumps) { 12634824e7fdSDimitry Andric InFlow[Jump.Target] += Jump.Flow; 12644824e7fdSDimitry Andric OutFlow[Jump.Source] += Jump.Flow; 12654824e7fdSDimitry Andric } 12664824e7fdSDimitry Andric 12674824e7fdSDimitry Andric uint64_t TotalInFlow = 0; 12684824e7fdSDimitry Andric uint64_t TotalOutFlow = 0; 12694824e7fdSDimitry Andric for (uint64_t I = 0; I < NumBlocks; I++) { 12704824e7fdSDimitry Andric auto &Block = Func.Blocks[I]; 12714824e7fdSDimitry Andric if (Block.isEntry()) { 12724824e7fdSDimitry Andric TotalInFlow += Block.Flow; 12734824e7fdSDimitry Andric assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow"); 12744824e7fdSDimitry Andric } else if (Block.isExit()) { 12754824e7fdSDimitry Andric TotalOutFlow += Block.Flow; 12764824e7fdSDimitry Andric assert(Block.Flow == InFlow[I] && "incorrectly computed control flow"); 12774824e7fdSDimitry Andric } else { 12784824e7fdSDimitry Andric assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow"); 12794824e7fdSDimitry Andric assert(Block.Flow == InFlow[I] && "incorrectly computed control flow"); 12804824e7fdSDimitry Andric } 12814824e7fdSDimitry Andric } 12824824e7fdSDimitry Andric assert(TotalInFlow == TotalOutFlow && "incorrectly computed control flow"); 12830eae32dcSDimitry Andric 12840eae32dcSDimitry Andric // Verify that there are no isolated flow components 12850eae32dcSDimitry Andric // One could modify FlowFunction to hold edges indexed by the sources, which 12860eae32dcSDimitry Andric // will avoid a creation of the object 12870eae32dcSDimitry Andric auto PositiveFlowEdges = std::vector<std::vector<uint64_t>>(NumBlocks); 1288bdd1243dSDimitry Andric for (const auto &Jump : Func.Jumps) { 12890eae32dcSDimitry Andric if (Jump.Flow > 0) { 12900eae32dcSDimitry Andric PositiveFlowEdges[Jump.Source].push_back(Jump.Target); 12910eae32dcSDimitry Andric } 12920eae32dcSDimitry Andric } 12930eae32dcSDimitry Andric 12940eae32dcSDimitry Andric // Run BFS from the source along edges with positive flow 12950eae32dcSDimitry Andric std::queue<uint64_t> Queue; 129604eeddc0SDimitry Andric auto Visited = BitVector(NumBlocks, false); 12970eae32dcSDimitry Andric Queue.push(Func.Entry); 12980eae32dcSDimitry Andric Visited[Func.Entry] = true; 12990eae32dcSDimitry Andric while (!Queue.empty()) { 13000eae32dcSDimitry Andric uint64_t Src = Queue.front(); 13010eae32dcSDimitry Andric Queue.pop(); 13020eae32dcSDimitry Andric for (uint64_t Dst : PositiveFlowEdges[Src]) { 13030eae32dcSDimitry Andric if (!Visited[Dst]) { 13040eae32dcSDimitry Andric Queue.push(Dst); 13050eae32dcSDimitry Andric Visited[Dst] = true; 13060eae32dcSDimitry Andric } 13070eae32dcSDimitry Andric } 13080eae32dcSDimitry Andric } 13090eae32dcSDimitry Andric 13100eae32dcSDimitry Andric // Verify that every block that has a positive flow is reached from the source 13110eae32dcSDimitry Andric // along edges with a positive flow 13120eae32dcSDimitry Andric for (uint64_t I = 0; I < NumBlocks; I++) { 13130eae32dcSDimitry Andric auto &Block = Func.Blocks[I]; 13140eae32dcSDimitry Andric assert((Visited[I] || Block.Flow == 0) && "an isolated flow component"); 13150eae32dcSDimitry Andric } 13164824e7fdSDimitry Andric } 13174824e7fdSDimitry Andric #endif 13184824e7fdSDimitry Andric 13194824e7fdSDimitry Andric } // end of anonymous namespace 13204824e7fdSDimitry Andric 132106c3fb27SDimitry Andric /// Apply the profile inference algorithm for a given function and provided 132206c3fb27SDimitry Andric /// profi options 1323bdd1243dSDimitry Andric void llvm::applyFlowInference(const ProfiParams &Params, FlowFunction &Func) { 132406c3fb27SDimitry Andric // Check if the function has samples and assign initial flow values 132506c3fb27SDimitry Andric bool HasSamples = false; 132606c3fb27SDimitry Andric for (FlowBlock &Block : Func.Blocks) { 132706c3fb27SDimitry Andric if (Block.Weight > 0) 132806c3fb27SDimitry Andric HasSamples = true; 132906c3fb27SDimitry Andric Block.Flow = Block.Weight; 133006c3fb27SDimitry Andric } 133106c3fb27SDimitry Andric for (FlowJump &Jump : Func.Jumps) { 133206c3fb27SDimitry Andric if (Jump.Weight > 0) 133306c3fb27SDimitry Andric HasSamples = true; 133406c3fb27SDimitry Andric Jump.Flow = Jump.Weight; 133506c3fb27SDimitry Andric } 133606c3fb27SDimitry Andric 133706c3fb27SDimitry Andric // Quit early for functions with a single block or ones w/o samples 133806c3fb27SDimitry Andric if (Func.Blocks.size() <= 1 || !HasSamples) 133906c3fb27SDimitry Andric return; 134006c3fb27SDimitry Andric 1341bdd1243dSDimitry Andric #ifndef NDEBUG 1342bdd1243dSDimitry Andric // Verify the input data 1343bdd1243dSDimitry Andric verifyInput(Func); 1344bdd1243dSDimitry Andric #endif 1345bdd1243dSDimitry Andric 13464824e7fdSDimitry Andric // Create and apply an inference network model 1347bdd1243dSDimitry Andric auto InferenceNetwork = MinCostMaxFlow(Params); 1348bdd1243dSDimitry Andric initializeNetwork(Params, InferenceNetwork, Func); 13494824e7fdSDimitry Andric InferenceNetwork.run(); 13504824e7fdSDimitry Andric 13514824e7fdSDimitry Andric // Extract flow values for every block and every edge 1352bdd1243dSDimitry Andric extractWeights(Params, InferenceNetwork, Func); 13534824e7fdSDimitry Andric 13540eae32dcSDimitry Andric // Post-processing adjustments to the flow 1355bdd1243dSDimitry Andric auto Adjuster = FlowAdjuster(Params, Func); 13560eae32dcSDimitry Andric Adjuster.run(); 13570eae32dcSDimitry Andric 13584824e7fdSDimitry Andric #ifndef NDEBUG 13594824e7fdSDimitry Andric // Verify the result 1360bdd1243dSDimitry Andric verifyOutput(Func); 13614824e7fdSDimitry Andric #endif 13624824e7fdSDimitry Andric } 1363bdd1243dSDimitry Andric 1364bdd1243dSDimitry Andric /// Apply the profile inference algorithm for a given flow function 1365bdd1243dSDimitry Andric void llvm::applyFlowInference(FlowFunction &Func) { 1366bdd1243dSDimitry Andric ProfiParams Params; 1367bdd1243dSDimitry Andric // Set the params from the command-line flags. 1368bdd1243dSDimitry Andric Params.EvenFlowDistribution = SampleProfileEvenFlowDistribution; 1369bdd1243dSDimitry Andric Params.RebalanceUnknown = SampleProfileRebalanceUnknown; 1370bdd1243dSDimitry Andric Params.JoinIslands = SampleProfileJoinIslands; 1371bdd1243dSDimitry Andric Params.CostBlockInc = SampleProfileProfiCostBlockInc; 1372bdd1243dSDimitry Andric Params.CostBlockDec = SampleProfileProfiCostBlockDec; 1373bdd1243dSDimitry Andric Params.CostBlockEntryInc = SampleProfileProfiCostBlockEntryInc; 1374bdd1243dSDimitry Andric Params.CostBlockEntryDec = SampleProfileProfiCostBlockEntryDec; 1375bdd1243dSDimitry Andric Params.CostBlockZeroInc = SampleProfileProfiCostBlockZeroInc; 1376bdd1243dSDimitry Andric Params.CostBlockUnknownInc = SampleProfileProfiCostBlockUnknownInc; 1377bdd1243dSDimitry Andric 1378bdd1243dSDimitry Andric applyFlowInference(Params, Func); 1379bdd1243dSDimitry Andric } 1380