1 //===--------------------- BottleneckAnalysis.cpp ---------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// 10 /// This file implements the functionalities used by the BottleneckAnalysis 11 /// to report bottleneck info. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "Views/BottleneckAnalysis.h" 16 #include "llvm/MC/MCInst.h" 17 #include "llvm/MCA/Support.h" 18 #include "llvm/Support/Format.h" 19 #include "llvm/Support/FormattedStream.h" 20 21 namespace llvm { 22 namespace mca { 23 24 #define DEBUG_TYPE "llvm-mca" 25 26 PressureTracker::PressureTracker(const MCSchedModel &Model) 27 : SM(Model), 28 ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0), 29 ProcResID2Mask(Model.getNumProcResourceKinds(), 0), 30 ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0), 31 ProcResID2ResourceUsersIndex(Model.getNumProcResourceKinds(), 0) { 32 computeProcResourceMasks(SM, ProcResID2Mask); 33 34 // Ignore the invalid resource at index zero. 35 unsigned NextResourceUsersIdx = 0; 36 for (unsigned I = 1, E = Model.getNumProcResourceKinds(); I < E; ++I) { 37 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 38 ProcResID2ResourceUsersIndex[I] = NextResourceUsersIdx; 39 NextResourceUsersIdx += ProcResource.NumUnits; 40 uint64_t ResourceMask = ProcResID2Mask[I]; 41 ResIdx2ProcResID[getResourceStateIndex(ResourceMask)] = I; 42 } 43 44 ResourceUsers.resize(NextResourceUsersIdx); 45 std::fill(ResourceUsers.begin(), ResourceUsers.end(), 46 std::make_pair<unsigned, unsigned>(~0U, 0U)); 47 } 48 49 void PressureTracker::getResourceUsers(uint64_t ResourceMask, 50 SmallVectorImpl<User> &Users) const { 51 unsigned Index = getResourceStateIndex(ResourceMask); 52 unsigned ProcResID = ResIdx2ProcResID[Index]; 53 const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID); 54 for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) { 55 const User U = getResourceUser(ProcResID, I); 56 if (U.second && IPI.find(U.first) != IPI.end()) 57 Users.emplace_back(U); 58 } 59 } 60 61 void PressureTracker::onInstructionDispatched(unsigned IID) { 62 IPI.insert(std::make_pair(IID, InstructionPressureInfo())); 63 } 64 65 void PressureTracker::onInstructionExecuted(unsigned IID) { IPI.erase(IID); } 66 67 void PressureTracker::handleInstructionIssuedEvent( 68 const HWInstructionIssuedEvent &Event) { 69 unsigned IID = Event.IR.getSourceIndex(); 70 using ResourceRef = HWInstructionIssuedEvent::ResourceRef; 71 using ResourceUse = std::pair<ResourceRef, ResourceCycles>; 72 for (const ResourceUse &Use : Event.UsedResources) { 73 const ResourceRef &RR = Use.first; 74 unsigned Index = ProcResID2ResourceUsersIndex[RR.first]; 75 Index += countTrailingZeros(RR.second); 76 ResourceUsers[Index] = std::make_pair(IID, Use.second.getNumerator()); 77 } 78 } 79 80 void PressureTracker::updateResourcePressureDistribution( 81 uint64_t CumulativeMask) { 82 while (CumulativeMask) { 83 uint64_t Current = CumulativeMask & (-CumulativeMask); 84 unsigned ResIdx = getResourceStateIndex(Current); 85 unsigned ProcResID = ResIdx2ProcResID[ResIdx]; 86 uint64_t Mask = ProcResID2Mask[ProcResID]; 87 88 if (Mask == Current) { 89 ResourcePressureDistribution[ProcResID]++; 90 CumulativeMask ^= Current; 91 continue; 92 } 93 94 Mask ^= Current; 95 while (Mask) { 96 uint64_t SubUnit = Mask & (-Mask); 97 ResIdx = getResourceStateIndex(SubUnit); 98 ProcResID = ResIdx2ProcResID[ResIdx]; 99 ResourcePressureDistribution[ProcResID]++; 100 Mask ^= SubUnit; 101 } 102 103 CumulativeMask ^= Current; 104 } 105 } 106 107 void PressureTracker::handlePressureEvent(const HWPressureEvent &Event) { 108 assert(Event.Reason != HWPressureEvent::INVALID && 109 "Unexpected invalid event!"); 110 111 switch (Event.Reason) { 112 default: 113 break; 114 115 case HWPressureEvent::RESOURCES: { 116 const uint64_t ResourceMask = Event.ResourceMask; 117 updateResourcePressureDistribution(Event.ResourceMask); 118 119 for (const InstRef &IR : Event.AffectedInstructions) { 120 const Instruction &IS = *IR.getInstruction(); 121 unsigned BusyResources = IS.getCriticalResourceMask() & ResourceMask; 122 if (!BusyResources) 123 continue; 124 125 unsigned IID = IR.getSourceIndex(); 126 IPI[IID].ResourcePressureCycles++; 127 } 128 break; 129 } 130 131 case HWPressureEvent::REGISTER_DEPS: 132 for (const InstRef &IR : Event.AffectedInstructions) { 133 unsigned IID = IR.getSourceIndex(); 134 IPI[IID].RegisterPressureCycles++; 135 } 136 break; 137 138 case HWPressureEvent::MEMORY_DEPS: 139 for (const InstRef &IR : Event.AffectedInstructions) { 140 unsigned IID = IR.getSourceIndex(); 141 IPI[IID].MemoryPressureCycles++; 142 } 143 } 144 } 145 146 #ifndef NDEBUG 147 void DependencyGraph::dumpDependencyEdge(raw_ostream &OS, 148 const DependencyEdge &DepEdge, 149 MCInstPrinter &MCIP) const { 150 unsigned FromIID = DepEdge.FromIID; 151 unsigned ToIID = DepEdge.ToIID; 152 assert(FromIID < ToIID && "Graph should be acyclic!"); 153 154 const DependencyEdge::Dependency &DE = DepEdge.Dep; 155 assert(DE.Type != DependencyEdge::DT_INVALID && "Unexpected invalid edge!"); 156 157 OS << " FROM: " << FromIID << " TO: " << ToIID << " "; 158 if (DE.Type == DependencyEdge::DT_REGISTER) { 159 OS << " - REGISTER: "; 160 MCIP.printRegName(OS, DE.ResourceOrRegID); 161 } else if (DE.Type == DependencyEdge::DT_MEMORY) { 162 OS << " - MEMORY"; 163 } else { 164 assert(DE.Type == DependencyEdge::DT_RESOURCE && 165 "Unsupported dependency type!"); 166 OS << " - RESOURCE MASK: " << DE.ResourceOrRegID; 167 } 168 OS << " - CYCLES: " << DE.Cost << '\n'; 169 } 170 #endif // NDEBUG 171 172 void DependencyGraph::initializeRootSet( 173 SmallVectorImpl<unsigned> &RootSet) const { 174 for (unsigned I = 0, E = Nodes.size(); I < E; ++I) { 175 const DGNode &N = Nodes[I]; 176 if (N.NumPredecessors == 0 && !N.OutgoingEdges.empty()) 177 RootSet.emplace_back(I); 178 } 179 } 180 181 void DependencyGraph::propagateThroughEdges( 182 SmallVectorImpl<unsigned> &RootSet) { 183 SmallVector<unsigned, 8> ToVisit; 184 185 // A critical sequence is computed as the longest path from a node of the 186 // RootSet to a leaf node (i.e. a node with no successors). The RootSet is 187 // composed of nodes with at least one successor, and no predecessors. 188 // 189 // Each node of the graph starts with an initial default cost of zero. The 190 // cost of a node is a measure of criticality: the higher the cost, the bigger 191 // is the performance impact. 192 // 193 // This algorithm is very similar to a (reverse) Dijkstra. Every iteration of 194 // the inner loop selects (i.e. visits) a node N from a set of `unvisited 195 // nodes`, and then propagates the cost of N to all its neighbors. 196 // 197 // The `unvisited nodes` set initially contains all the nodes from the 198 // RootSet. A node N is added to the `unvisited nodes` if all its 199 // predecessors have been visited already. 200 // 201 // For simplicity, every node tracks the number of unvisited incoming edges in 202 // field `NumVisitedPredecessors`. When the value of that field drops to 203 // zero, then the corresponding node is added to a `ToVisit` set. 204 // 205 // At the end of every iteration of the outer loop, set `ToVisit` becomes our 206 // new `unvisited nodes` set. 207 // 208 // The algorithm terminates when the set of unvisited nodes (i.e. our RootSet) 209 // is empty. This algorithm works under the assumption that the graph is 210 // acyclic. 211 do { 212 for (unsigned IID : RootSet) { 213 const DGNode &N = Nodes[IID]; 214 for (const DependencyEdge &DepEdge : N.OutgoingEdges) { 215 unsigned ToIID = DepEdge.ToIID; 216 DGNode &To = Nodes[ToIID]; 217 uint64_t Cost = N.Cost + DepEdge.Dep.Cost; 218 // Check if this is the most expensive incoming edge seen so far. In 219 // case, update the total cost of the destination node (ToIID), as well 220 // its field `CriticalPredecessor`. 221 if (Cost > To.Cost) { 222 To.CriticalPredecessor = DepEdge; 223 To.Cost = Cost; 224 To.Depth = N.Depth + 1; 225 } 226 To.NumVisitedPredecessors++; 227 if (To.NumVisitedPredecessors == To.NumPredecessors) 228 ToVisit.emplace_back(ToIID); 229 } 230 } 231 232 std::swap(RootSet, ToVisit); 233 ToVisit.clear(); 234 } while (!RootSet.empty()); 235 } 236 237 void DependencyGraph::getCriticalSequence( 238 SmallVectorImpl<const DependencyEdge *> &Seq) const { 239 // At this stage, nodes of the graph have been already visited, and costs have 240 // been propagated through the edges (see method `propagateThroughEdges()`). 241 242 // Identify the node N with the highest cost in the graph. By construction, 243 // that node is the last instruction of our critical sequence. 244 // Field N.Depth would tell us the total length of the sequence. 245 // 246 // To obtain the sequence of critical edges, we simply follow the chain of critical 247 // predecessors starting from node N (field DGNode::CriticalPredecessor). 248 const auto It = std::max_element( 249 Nodes.begin(), Nodes.end(), 250 [](const DGNode &Lhs, const DGNode &Rhs) { return Lhs.Cost < Rhs.Cost; }); 251 unsigned IID = std::distance(Nodes.begin(), It); 252 Seq.resize(Nodes[IID].Depth); 253 for (unsigned I = Seq.size(), E = 0; I > E; --I) { 254 const DGNode &N = Nodes[IID]; 255 Seq[I - 1] = &N.CriticalPredecessor; 256 IID = N.CriticalPredecessor.FromIID; 257 } 258 } 259 260 static void printInstruction(formatted_raw_ostream &FOS, 261 const MCSubtargetInfo &STI, MCInstPrinter &MCIP, 262 const MCInst &MCI, 263 bool UseDifferentColor = false) { 264 std::string Instruction; 265 raw_string_ostream InstrStream(Instruction); 266 267 FOS.PadToColumn(14); 268 269 MCIP.printInst(&MCI, InstrStream, "", STI); 270 InstrStream.flush(); 271 272 if (UseDifferentColor) 273 FOS.changeColor(raw_ostream::CYAN, true, false); 274 FOS << StringRef(Instruction).ltrim(); 275 if (UseDifferentColor) 276 FOS.resetColor(); 277 } 278 279 void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const { 280 SmallVector<const DependencyEdge *, 16> Seq; 281 DG.getCriticalSequence(Seq); 282 if (Seq.empty()) 283 return; 284 285 OS << "\nCritical sequence based on the simulation:\n\n"; 286 287 const DependencyEdge &FirstEdge = *Seq[0]; 288 unsigned FromIID = FirstEdge.FromIID % Source.size(); 289 unsigned ToIID = FirstEdge.ToIID % Source.size(); 290 bool IsLoopCarried = FromIID >= ToIID; 291 292 formatted_raw_ostream FOS(OS); 293 FOS.PadToColumn(14); 294 FOS << "Instruction"; 295 FOS.PadToColumn(58); 296 FOS << "Dependency Information"; 297 298 bool HasColors = FOS.has_colors(); 299 300 unsigned CurrentIID = 0; 301 if (IsLoopCarried) { 302 FOS << "\n +----< " << FromIID << "."; 303 printInstruction(FOS, STI, MCIP, Source[FromIID], HasColors); 304 FOS << "\n |\n | < loop carried > \n |"; 305 } else { 306 while (CurrentIID < FromIID) { 307 FOS << "\n " << CurrentIID << "."; 308 printInstruction(FOS, STI, MCIP, Source[CurrentIID]); 309 CurrentIID++; 310 } 311 312 FOS << "\n +----< " << CurrentIID << "."; 313 printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors); 314 CurrentIID++; 315 } 316 317 for (const DependencyEdge *&DE : Seq) { 318 ToIID = DE->ToIID % Source.size(); 319 unsigned LastIID = CurrentIID > ToIID ? Source.size() : ToIID; 320 321 while (CurrentIID < LastIID) { 322 FOS << "\n | " << CurrentIID << "."; 323 printInstruction(FOS, STI, MCIP, Source[CurrentIID]); 324 CurrentIID++; 325 } 326 327 if (CurrentIID == ToIID) { 328 FOS << "\n +----> " << ToIID << "."; 329 printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors); 330 } else { 331 FOS << "\n |\n | < loop carried > \n |" 332 << "\n +----> " << ToIID << "."; 333 printInstruction(FOS, STI, MCIP, Source[ToIID], HasColors); 334 } 335 FOS.PadToColumn(58); 336 337 const DependencyEdge::Dependency &Dep = DE->Dep; 338 if (HasColors) 339 FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false); 340 341 if (Dep.Type == DependencyEdge::DT_REGISTER) { 342 FOS << "## REGISTER dependency: "; 343 if (HasColors) 344 FOS.changeColor(raw_ostream::MAGENTA, true, false); 345 MCIP.printRegName(FOS, Dep.ResourceOrRegID); 346 } else if (Dep.Type == DependencyEdge::DT_MEMORY) { 347 FOS << "## MEMORY dependency."; 348 } else { 349 assert(Dep.Type == DependencyEdge::DT_RESOURCE && 350 "Unsupported dependency type!"); 351 FOS << "## RESOURCE interference: "; 352 if (HasColors) 353 FOS.changeColor(raw_ostream::MAGENTA, true, false); 354 FOS << Tracker.resolveResourceName(Dep.ResourceOrRegID); 355 if (HasColors) { 356 FOS.resetColor(); 357 FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false); 358 } 359 FOS << " [ probability: " << ((DE->Frequency * 100) / Iterations) 360 << "% ]"; 361 } 362 if (HasColors) 363 FOS.resetColor(); 364 ++CurrentIID; 365 } 366 367 while (CurrentIID < Source.size()) { 368 FOS << "\n " << CurrentIID << "."; 369 printInstruction(FOS, STI, MCIP, Source[CurrentIID]); 370 CurrentIID++; 371 } 372 373 FOS << '\n'; 374 FOS.flush(); 375 } 376 377 #ifndef NDEBUG 378 void DependencyGraph::dump(raw_ostream &OS, MCInstPrinter &MCIP) const { 379 OS << "\nREG DEPS\n"; 380 for (const DGNode &Node : Nodes) 381 for (const DependencyEdge &DE : Node.OutgoingEdges) 382 if (DE.Dep.Type == DependencyEdge::DT_REGISTER) 383 dumpDependencyEdge(OS, DE, MCIP); 384 385 OS << "\nMEM DEPS\n"; 386 for (const DGNode &Node : Nodes) 387 for (const DependencyEdge &DE : Node.OutgoingEdges) 388 if (DE.Dep.Type == DependencyEdge::DT_MEMORY) 389 dumpDependencyEdge(OS, DE, MCIP); 390 391 OS << "\nRESOURCE DEPS\n"; 392 for (const DGNode &Node : Nodes) 393 for (const DependencyEdge &DE : Node.OutgoingEdges) 394 if (DE.Dep.Type == DependencyEdge::DT_RESOURCE) 395 dumpDependencyEdge(OS, DE, MCIP); 396 } 397 #endif // NDEBUG 398 399 void DependencyGraph::addDependency(unsigned From, unsigned To, 400 DependencyEdge::Dependency &&Dep) { 401 DGNode &NodeFrom = Nodes[From]; 402 DGNode &NodeTo = Nodes[To]; 403 SmallVectorImpl<DependencyEdge> &Vec = NodeFrom.OutgoingEdges; 404 405 auto It = find_if(Vec, [To, Dep](DependencyEdge &DE) { 406 return DE.ToIID == To && DE.Dep.ResourceOrRegID == Dep.ResourceOrRegID; 407 }); 408 409 if (It != Vec.end()) { 410 It->Dep.Cost += Dep.Cost; 411 It->Frequency++; 412 return; 413 } 414 415 DependencyEdge DE = {Dep, From, To, 1}; 416 Vec.emplace_back(DE); 417 NodeTo.NumPredecessors++; 418 } 419 420 BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti, 421 MCInstPrinter &Printer, 422 ArrayRef<MCInst> S, unsigned NumIter) 423 : STI(sti), MCIP(Printer), Tracker(STI.getSchedModel()), DG(S.size() * 3), 424 Source(S), Iterations(NumIter), TotalCycles(0), 425 PressureIncreasedBecauseOfResources(false), 426 PressureIncreasedBecauseOfRegisterDependencies(false), 427 PressureIncreasedBecauseOfMemoryDependencies(false), 428 SeenStallCycles(false), BPI() {} 429 430 void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To, 431 unsigned RegID, unsigned Cost) { 432 bool IsLoopCarried = From >= To; 433 unsigned SourceSize = Source.size(); 434 if (IsLoopCarried) { 435 Cost *= Iterations / 2; 436 DG.addRegisterDep(From, To + SourceSize, RegID, Cost); 437 DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost); 438 return; 439 } 440 DG.addRegisterDep(From + SourceSize, To + SourceSize, RegID, Cost); 441 } 442 443 void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To, 444 unsigned Cost) { 445 bool IsLoopCarried = From >= To; 446 unsigned SourceSize = Source.size(); 447 if (IsLoopCarried) { 448 Cost *= Iterations / 2; 449 DG.addMemoryDep(From, To + SourceSize, Cost); 450 DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost); 451 return; 452 } 453 DG.addMemoryDep(From + SourceSize, To + SourceSize, Cost); 454 } 455 456 void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To, 457 uint64_t Mask, unsigned Cost) { 458 bool IsLoopCarried = From >= To; 459 unsigned SourceSize = Source.size(); 460 if (IsLoopCarried) { 461 Cost *= Iterations / 2; 462 DG.addResourceDep(From, To + SourceSize, Mask, Cost); 463 DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost); 464 return; 465 } 466 DG.addResourceDep(From + SourceSize, To + SourceSize, Mask, Cost); 467 } 468 469 void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) { 470 const unsigned IID = Event.IR.getSourceIndex(); 471 if (Event.Type == HWInstructionEvent::Dispatched) { 472 Tracker.onInstructionDispatched(IID); 473 return; 474 } 475 if (Event.Type == HWInstructionEvent::Executed) { 476 Tracker.onInstructionExecuted(IID); 477 return; 478 } 479 480 if (Event.Type != HWInstructionEvent::Issued) 481 return; 482 483 const Instruction &IS = *Event.IR.getInstruction(); 484 unsigned To = IID % Source.size(); 485 486 unsigned Cycles = 2 * Tracker.getResourcePressureCycles(IID); 487 uint64_t ResourceMask = IS.getCriticalResourceMask(); 488 SmallVector<std::pair<unsigned, unsigned>, 4> Users; 489 while (ResourceMask) { 490 uint64_t Current = ResourceMask & (-ResourceMask); 491 Tracker.getResourceUsers(Current, Users); 492 for (const std::pair<unsigned, unsigned> &U : Users) 493 addResourceDep(U.first % Source.size(), To, Current, U.second + Cycles); 494 Users.clear(); 495 ResourceMask ^= Current; 496 } 497 498 const CriticalDependency &RegDep = IS.getCriticalRegDep(); 499 if (RegDep.Cycles) { 500 Cycles = RegDep.Cycles + 2 * Tracker.getRegisterPressureCycles(IID); 501 unsigned From = RegDep.IID % Source.size(); 502 addRegisterDep(From, To, RegDep.RegID, Cycles); 503 } 504 505 const CriticalDependency &MemDep = IS.getCriticalMemDep(); 506 if (MemDep.Cycles) { 507 Cycles = MemDep.Cycles + 2 * Tracker.getMemoryPressureCycles(IID); 508 unsigned From = MemDep.IID % Source.size(); 509 addMemoryDep(From, To, Cycles); 510 } 511 512 Tracker.handleInstructionIssuedEvent( 513 static_cast<const HWInstructionIssuedEvent &>(Event)); 514 515 // Check if this is the last simulated instruction. 516 if (IID == ((Iterations * Source.size()) - 1)) 517 DG.finalizeGraph(); 518 } 519 520 void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) { 521 assert(Event.Reason != HWPressureEvent::INVALID && 522 "Unexpected invalid event!"); 523 524 Tracker.handlePressureEvent(Event); 525 526 switch (Event.Reason) { 527 default: 528 break; 529 530 case HWPressureEvent::RESOURCES: 531 PressureIncreasedBecauseOfResources = true; 532 break; 533 case HWPressureEvent::REGISTER_DEPS: 534 PressureIncreasedBecauseOfRegisterDependencies = true; 535 break; 536 case HWPressureEvent::MEMORY_DEPS: 537 PressureIncreasedBecauseOfMemoryDependencies = true; 538 break; 539 } 540 } 541 542 void BottleneckAnalysis::onCycleEnd() { 543 ++TotalCycles; 544 545 bool PressureIncreasedBecauseOfDataDependencies = 546 PressureIncreasedBecauseOfRegisterDependencies || 547 PressureIncreasedBecauseOfMemoryDependencies; 548 if (!PressureIncreasedBecauseOfResources && 549 !PressureIncreasedBecauseOfDataDependencies) 550 return; 551 552 ++BPI.PressureIncreaseCycles; 553 if (PressureIncreasedBecauseOfRegisterDependencies) 554 ++BPI.RegisterDependencyCycles; 555 if (PressureIncreasedBecauseOfMemoryDependencies) 556 ++BPI.MemoryDependencyCycles; 557 if (PressureIncreasedBecauseOfDataDependencies) 558 ++BPI.DataDependencyCycles; 559 if (PressureIncreasedBecauseOfResources) 560 ++BPI.ResourcePressureCycles; 561 PressureIncreasedBecauseOfResources = false; 562 PressureIncreasedBecauseOfRegisterDependencies = false; 563 PressureIncreasedBecauseOfMemoryDependencies = false; 564 } 565 566 void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const { 567 if (!SeenStallCycles || !BPI.PressureIncreaseCycles) { 568 OS << "\n\nNo resource or data dependency bottlenecks discovered.\n"; 569 return; 570 } 571 572 double PressurePerCycle = 573 (double)BPI.PressureIncreaseCycles * 100 / TotalCycles; 574 double ResourcePressurePerCycle = 575 (double)BPI.ResourcePressureCycles * 100 / TotalCycles; 576 double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles; 577 double RegDepPressurePerCycle = 578 (double)BPI.RegisterDependencyCycles * 100 / TotalCycles; 579 double MemDepPressurePerCycle = 580 (double)BPI.MemoryDependencyCycles * 100 / TotalCycles; 581 582 OS << "\n\nCycles with backend pressure increase [ " 583 << format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]"; 584 585 OS << "\nThroughput Bottlenecks: " 586 << "\n Resource Pressure [ " 587 << format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100) 588 << "% ]"; 589 590 if (BPI.PressureIncreaseCycles) { 591 ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution(); 592 const MCSchedModel &SM = STI.getSchedModel(); 593 for (unsigned I = 0, E = Distribution.size(); I < E; ++I) { 594 unsigned ResourceCycles = Distribution[I]; 595 if (ResourceCycles) { 596 double Frequency = (double)ResourceCycles * 100 / TotalCycles; 597 const MCProcResourceDesc &PRDesc = *SM.getProcResource(I); 598 OS << "\n - " << PRDesc.Name << " [ " 599 << format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]"; 600 } 601 } 602 } 603 604 OS << "\n Data Dependencies: [ " 605 << format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]"; 606 OS << "\n - Register Dependencies [ " 607 << format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100) 608 << "% ]"; 609 OS << "\n - Memory Dependencies [ " 610 << format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100) 611 << "% ]\n"; 612 } 613 614 void BottleneckAnalysis::printView(raw_ostream &OS) const { 615 std::string Buffer; 616 raw_string_ostream TempStream(Buffer); 617 printBottleneckHints(TempStream); 618 TempStream.flush(); 619 OS << Buffer; 620 printCriticalSequence(OS); 621 } 622 623 } // namespace mca. 624 } // namespace llvm 625