2019-04-17 14:02:05 +08:00
|
|
|
//===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// \file
|
|
|
|
///
|
|
|
|
/// This file implements the bottleneck analysis view.
|
2019-06-01 01:18:34 +08:00
|
|
|
///
|
2019-04-17 14:02:05 +08:00
|
|
|
/// This view internally observes backend pressure increase events in order to
|
|
|
|
/// identify potential sources of bottlenecks.
|
2019-06-01 01:18:34 +08:00
|
|
|
///
|
2019-04-17 14:02:05 +08:00
|
|
|
/// Example of bottleneck analysis report:
|
|
|
|
///
|
|
|
|
/// Cycles with backend pressure increase [ 33.40% ]
|
|
|
|
/// Throughput Bottlenecks:
|
|
|
|
/// Resource Pressure [ 0.52% ]
|
|
|
|
/// - JLAGU [ 0.52% ]
|
|
|
|
/// Data Dependencies: [ 32.88% ]
|
|
|
|
/// - Register Dependencies [ 32.88% ]
|
|
|
|
/// - Memory Dependencies [ 0.00% ]
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
|
|
|
|
#define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
|
|
|
|
|
|
|
|
#include "Views/View.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2019-06-01 01:18:34 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
2019-04-17 14:02:05 +08:00
|
|
|
#include "llvm/MC/MCSchedule.h"
|
2019-06-01 01:18:34 +08:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2019-04-17 14:02:05 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace mca {
|
|
|
|
|
2019-06-01 01:18:34 +08:00
|
|
|
class PressureTracker {
|
|
|
|
const MCSchedModel &SM;
|
|
|
|
|
|
|
|
// Resource pressure distribution. There is an element for every processor
|
|
|
|
// resource declared by the scheduling model. Quantities are number of cycles.
|
|
|
|
SmallVector<unsigned, 4> ResourcePressureDistribution;
|
|
|
|
|
|
|
|
// Each processor resource is associated with a so-called processor resource
|
|
|
|
// mask. This vector allows to correlate processor resource IDs with processor
|
|
|
|
// resource masks. There is exactly one element per each processor resource
|
|
|
|
// declared by the scheduling model.
|
|
|
|
SmallVector<uint64_t, 4> ProcResID2Mask;
|
|
|
|
|
|
|
|
// Maps processor resource state indices (returned by calls to
|
|
|
|
// `getResourceStateIndex(Mask)` to processor resource identifiers.
|
|
|
|
SmallVector<unsigned, 4> ResIdx2ProcResID;
|
|
|
|
|
|
|
|
// Maps Processor Resource identifiers to ResourceUsers indices.
|
|
|
|
SmallVector<unsigned, 4> ProcResID2ResourceUsersIndex;
|
|
|
|
|
|
|
|
// Identifies the last user of a processor resource unit.
|
|
|
|
// This vector is updated on every instruction issued event.
|
|
|
|
// There is one entry for every processor resource unit declared by the
|
|
|
|
// processor model. An all_ones value is treated like an invalid instruction
|
|
|
|
// identifier.
|
2019-06-10 20:50:08 +08:00
|
|
|
using User = std::pair<unsigned, unsigned>;
|
|
|
|
SmallVector<User, 4> ResourceUsers;
|
2019-06-01 01:18:34 +08:00
|
|
|
|
|
|
|
struct InstructionPressureInfo {
|
|
|
|
unsigned RegisterPressureCycles;
|
|
|
|
unsigned MemoryPressureCycles;
|
|
|
|
unsigned ResourcePressureCycles;
|
|
|
|
};
|
|
|
|
DenseMap<unsigned, InstructionPressureInfo> IPI;
|
|
|
|
|
|
|
|
void updateResourcePressureDistribution(uint64_t CumulativeMask);
|
|
|
|
|
2019-06-10 20:50:08 +08:00
|
|
|
User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
|
2019-06-01 01:18:34 +08:00
|
|
|
unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
|
|
|
|
return ResourceUsers[Index + UnitID];
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
PressureTracker(const MCSchedModel &Model);
|
|
|
|
|
|
|
|
ArrayRef<unsigned> getResourcePressureDistribution() const {
|
|
|
|
return ResourcePressureDistribution;
|
|
|
|
}
|
|
|
|
|
2019-06-10 20:50:08 +08:00
|
|
|
void getResourceUsers(uint64_t ResourceMask,
|
|
|
|
SmallVectorImpl<User> &Users) const;
|
2019-06-01 01:18:34 +08:00
|
|
|
|
|
|
|
unsigned getRegisterPressureCycles(unsigned IID) const {
|
|
|
|
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
|
|
|
|
const InstructionPressureInfo &Info = IPI.find(IID)->second;
|
|
|
|
return Info.RegisterPressureCycles;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getMemoryPressureCycles(unsigned IID) const {
|
|
|
|
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
|
|
|
|
const InstructionPressureInfo &Info = IPI.find(IID)->second;
|
|
|
|
return Info.MemoryPressureCycles;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getResourcePressureCycles(unsigned IID) const {
|
|
|
|
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
|
|
|
|
const InstructionPressureInfo &Info = IPI.find(IID)->second;
|
|
|
|
return Info.ResourcePressureCycles;
|
|
|
|
}
|
|
|
|
|
2019-06-10 20:50:08 +08:00
|
|
|
void onInstructionDispatched(unsigned IID);
|
|
|
|
void onInstructionExecuted(unsigned IID);
|
|
|
|
|
2019-06-01 01:18:34 +08:00
|
|
|
void handlePressureEvent(const HWPressureEvent &Event);
|
2019-06-10 20:50:08 +08:00
|
|
|
void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
|
2019-06-01 01:18:34 +08:00
|
|
|
};
|
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
// An edge of a dependency graph.
|
|
|
|
// Vertices of the graph are instructions identified by their ID.
|
|
|
|
struct DependencyEdge {
|
|
|
|
enum DependencyType { DT_INVALID, DT_REGISTER, DT_MEMORY, DT_RESOURCE };
|
|
|
|
|
|
|
|
// Dependency edge descriptor.
|
|
|
|
//
|
|
|
|
// It describe the dependency reason, as well as the edge cost in cycles.
|
|
|
|
struct Dependency {
|
2019-06-10 20:50:08 +08:00
|
|
|
DependencyType Type;
|
2019-06-01 01:18:34 +08:00
|
|
|
uint64_t ResourceOrRegID;
|
2019-06-18 20:59:46 +08:00
|
|
|
uint64_t Cost;
|
2019-06-01 01:18:34 +08:00
|
|
|
};
|
2019-06-18 20:59:46 +08:00
|
|
|
Dependency Dep;
|
|
|
|
|
|
|
|
// Pair of vertices connected by this edge.
|
|
|
|
unsigned FromIID;
|
|
|
|
unsigned ToIID;
|
|
|
|
};
|
2019-06-01 01:18:34 +08:00
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
class DependencyGraph {
|
2019-06-01 01:18:34 +08:00
|
|
|
struct DGNode {
|
|
|
|
unsigned NumPredecessors;
|
2019-06-10 20:50:08 +08:00
|
|
|
SmallVector<DependencyEdge, 8> OutgoingEdges;
|
2019-06-01 01:18:34 +08:00
|
|
|
};
|
|
|
|
SmallVector<DGNode, 16> Nodes;
|
|
|
|
|
|
|
|
DependencyGraph(const DependencyGraph &) = delete;
|
|
|
|
DependencyGraph &operator=(const DependencyGraph &) = delete;
|
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
void addDependency(unsigned From, unsigned To,
|
|
|
|
DependencyEdge::Dependency &&DE);
|
2019-06-10 20:50:08 +08:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2019-06-18 20:59:46 +08:00
|
|
|
void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
|
|
|
|
MCInstPrinter &MCIP) const;
|
2019-06-10 20:50:08 +08:00
|
|
|
#endif
|
|
|
|
|
2019-06-01 01:18:34 +08:00
|
|
|
public:
|
2019-06-10 20:50:08 +08:00
|
|
|
DependencyGraph(unsigned Size) : Nodes(Size) {}
|
2019-06-01 01:18:34 +08:00
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
void addRegisterDep(unsigned From, unsigned To, unsigned RegID,
|
|
|
|
unsigned Cost) {
|
|
|
|
addDependency(From, To, {DependencyEdge::DT_REGISTER, RegID, Cost});
|
2019-06-01 01:18:34 +08:00
|
|
|
}
|
2019-06-10 20:50:08 +08:00
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
void addMemoryDep(unsigned From, unsigned To, unsigned Cost) {
|
|
|
|
addDependency(From, To, {DependencyEdge::DT_MEMORY, /* unused */ 0, Cost});
|
2019-06-01 01:18:34 +08:00
|
|
|
}
|
2019-06-10 20:50:08 +08:00
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
void addResourceDep(unsigned From, unsigned To, uint64_t Mask,
|
|
|
|
unsigned Cost) {
|
|
|
|
addDependency(From, To, {DependencyEdge::DT_RESOURCE, Mask, Cost});
|
2019-06-01 01:18:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2019-06-10 20:50:08 +08:00
|
|
|
void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
|
2019-06-01 01:18:34 +08:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2019-04-17 14:02:05 +08:00
|
|
|
/// A view that collects and prints a few performance numbers.
|
|
|
|
class BottleneckAnalysis : public View {
|
2019-06-01 01:18:34 +08:00
|
|
|
const MCSubtargetInfo &STI;
|
|
|
|
PressureTracker Tracker;
|
|
|
|
DependencyGraph DG;
|
|
|
|
|
|
|
|
ArrayRef<MCInst> Source;
|
2019-06-18 20:59:46 +08:00
|
|
|
unsigned Iterations;
|
2019-04-17 14:02:05 +08:00
|
|
|
unsigned TotalCycles;
|
|
|
|
|
2019-06-01 01:18:34 +08:00
|
|
|
bool PressureIncreasedBecauseOfResources;
|
|
|
|
bool PressureIncreasedBecauseOfRegisterDependencies;
|
|
|
|
bool PressureIncreasedBecauseOfMemoryDependencies;
|
|
|
|
// True if throughput was affected by dispatch stalls.
|
|
|
|
bool SeenStallCycles;
|
|
|
|
|
2019-04-17 14:02:05 +08:00
|
|
|
struct BackPressureInfo {
|
|
|
|
// Cycles where backpressure increased.
|
|
|
|
unsigned PressureIncreaseCycles;
|
|
|
|
// Cycles where backpressure increased because of pipeline pressure.
|
|
|
|
unsigned ResourcePressureCycles;
|
|
|
|
// Cycles where backpressure increased because of data dependencies.
|
|
|
|
unsigned DataDependencyCycles;
|
|
|
|
// Cycles where backpressure increased because of register dependencies.
|
|
|
|
unsigned RegisterDependencyCycles;
|
|
|
|
// Cycles where backpressure increased because of memory dependencies.
|
|
|
|
unsigned MemoryDependencyCycles;
|
|
|
|
};
|
|
|
|
BackPressureInfo BPI;
|
|
|
|
|
2019-06-10 20:50:08 +08:00
|
|
|
// Used to populate the dependency graph DG.
|
|
|
|
void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
|
|
|
|
void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
|
|
|
|
void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
|
|
|
|
|
2019-06-18 20:59:46 +08:00
|
|
|
// Prints a bottleneck message to OS.
|
|
|
|
void printBottleneckHints(raw_ostream &OS) const;
|
|
|
|
|
2019-04-17 14:02:05 +08:00
|
|
|
public:
|
2019-06-10 20:50:08 +08:00
|
|
|
BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
|
2019-06-18 20:59:46 +08:00
|
|
|
ArrayRef<MCInst> Sequence, unsigned Iterations);
|
2019-04-17 14:02:05 +08:00
|
|
|
|
2019-06-01 01:18:34 +08:00
|
|
|
void onCycleEnd() override;
|
2019-04-17 14:02:05 +08:00
|
|
|
void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
|
|
|
|
void onEvent(const HWPressureEvent &Event) override;
|
2019-06-01 01:18:34 +08:00
|
|
|
void onEvent(const HWInstructionEvent &Event) override;
|
2019-04-17 14:02:05 +08:00
|
|
|
|
2019-06-01 02:01:42 +08:00
|
|
|
void printView(raw_ostream &OS) const override;
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2019-06-10 21:33:54 +08:00
|
|
|
void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
|
2019-06-01 02:01:42 +08:00
|
|
|
#endif
|
2019-04-17 14:02:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mca
|
|
|
|
} // namespace llvm
|
|
|
|
|
|
|
|
#endif
|