[llvm] [MCA] Optimize memory consumption in resource pressure view (NFC) (PR #124904)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 29 03:10:29 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-tools-llvm-mca
Author: Anton Sidorenko (asi-sc)
<details>
<summary>Changes</summary>
ResourceUsage is a very sparse table. On large input asm sequences it consumes a lot of memory utilizing only a few percents of it (~4% on my benchmark). Reorganization of ResourceUsage to keep only used fields allows saving up to 18% of total memory use by mca or ~850% of input file size (~1.1GB in absolute values in my case).
NB: I use mca rather in unusual way by providing really big input asm sequences and I don't think there would be any noticeable change for small input files, but I still think it worth fixing.
---
Full diff: https://github.com/llvm/llvm-project/pull/124904.diff
2 Files Affected:
- (modified) llvm/tools/llvm-mca/Views/ResourcePressureView.cpp (+57-18)
- (modified) llvm/tools/llvm-mca/Views/ResourcePressureView.h (+7-2)
``````````diff
diff --git a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
index f39350f3b45852..26150849243764 100644
--- a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
+++ b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
@@ -37,8 +37,16 @@ ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
}
NumResourceUnits = R2VIndex;
- ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
- std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
+ ResourceUsage.resize(getSource().size());
+
+ ResourceReleaseAtCycles InitValue{0, 0};
+ auto Generator = [&InitValue]() {
+ auto Old = InitValue;
+ ++InitValue.ResourceIdx;
+ return Old;
+ };
+ std::generate_n(std::back_inserter(CommonResourceUsage), NumResourceUnits,
+ Generator);
}
void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
@@ -60,8 +68,19 @@ void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
assert(Resource2VecIndex.contains(RR.first));
unsigned R2VIndex = Resource2VecIndex[RR.first];
R2VIndex += llvm::countr_zero(RR.second);
- ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
- ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
+
+ InstResourceUsage &RU = ResourceUsage[SourceIdx];
+ ResourceReleaseAtCycles NewUsage{R2VIndex, Use.second};
+ auto ResCyclesIt =
+ lower_bound(RU, NewUsage, [](const auto &L, const auto &R) {
+ return L.ResourceIdx < R.ResourceIdx;
+ });
+ if (ResCyclesIt != RU.end() && ResCyclesIt->ResourceIdx == R2VIndex)
+ ResCyclesIt->Cycles += NewUsage.Cycles;
+ else
+ RU.insert(ResCyclesIt, std::move(NewUsage));
+
+ CommonResourceUsage[R2VIndex].Cycles += NewUsage.Cycles;
}
}
@@ -135,10 +154,17 @@ void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
ArrayRef<llvm::MCInst> Source = getSource();
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
+ auto UsageEntryEnd = CommonResourceUsage.end();
+ auto UsageEntryIt = CommonResourceUsage.begin();
for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
- double Usage = ResourceUsage[I + Source.size() * E];
- printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
+ double Pressure = 0.0;
+ if (UsageEntryIt != UsageEntryEnd && UsageEntryIt->ResourceIdx == I) {
+ Pressure = UsageEntryIt->Cycles / Executions;
+ ++UsageEntryIt;
+ }
+ printResourcePressure(FOS, Pressure, (I + 1) * 7);
}
+ assert(UsageEntryIt == UsageEntryEnd);
FOS.flush();
OS << Buffer;
@@ -157,11 +183,17 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
ArrayRef<llvm::MCInst> Source = getSource();
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
for (const MCInst &MCI : Source) {
- unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
+ auto UsageEntryEnd = ResourceUsage[InstrIndex].end();
+ auto UsageEntryIt = ResourceUsage[InstrIndex].begin();
for (unsigned J = 0; J < NumResourceUnits; ++J) {
- double Usage = ResourceUsage[J + BaseEltIdx];
- printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
+ double Pressure = 0.0;
+ if (UsageEntryIt != UsageEntryEnd && UsageEntryIt->ResourceIdx == J) {
+ Pressure = UsageEntryIt->Cycles / Executions;
+ ++UsageEntryIt;
+ }
+ printResourcePressure(FOS, Pressure, (J + 1) * 7);
}
+ assert(UsageEntryIt == UsageEntryEnd);
FOS << printInstructionString(MCI) << '\n';
FOS.flush();
@@ -180,17 +212,24 @@ json::Value ResourcePressureView::toJSON() const {
// non-zero values.
ArrayRef<llvm::MCInst> Source = getSource();
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
- for (const auto &R : enumerate(ResourceUsage)) {
- const ReleaseAtCycles &RU = R.value();
- if (RU.getNumerator() == 0)
- continue;
- unsigned InstructionIndex = R.index() / NumResourceUnits;
- unsigned ResourceIndex = R.index() % NumResourceUnits;
- double Usage = RU / Executions;
+
+ auto AddToJSON = [&ResourcePressureInfo, Executions](
+ const ResourceReleaseAtCycles &RU, unsigned InstIndex) {
+ assert(RU.Cycles.getNumerator() != 0);
+ double Usage = RU.Cycles / Executions;
ResourcePressureInfo.push_back(
- json::Object({{"InstructionIndex", InstructionIndex},
- {"ResourceIndex", ResourceIndex},
+ json::Object({{"InstructionIndex", InstIndex},
+ {"ResourceIndex", RU.ResourceIdx},
{"ResourceUsage", Usage}}));
+ };
+ for (const auto &R : enumerate(ResourceUsage)) {
+ unsigned InstructionIndex = R.index();
+ for (const auto &RU : R.value())
+ AddToJSON(RU, InstructionIndex);
+ }
+ for (const auto &RU : CommonResourceUsage) {
+ if (RU.Cycles.getNumerator() != 0)
+ AddToJSON(RU, Source.size());
}
json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});
diff --git a/llvm/tools/llvm-mca/Views/ResourcePressureView.h b/llvm/tools/llvm-mca/Views/ResourcePressureView.h
index be8ad04102fd05..3deb9e8a21d5ea 100644
--- a/llvm/tools/llvm-mca/Views/ResourcePressureView.h
+++ b/llvm/tools/llvm-mca/Views/ResourcePressureView.h
@@ -77,8 +77,13 @@ class ResourcePressureView : public InstructionView {
// resource ID.
llvm::DenseMap<unsigned, unsigned> Resource2VecIndex;
- // Table of resources used by instructions.
- std::vector<ReleaseAtCycles> ResourceUsage;
+ struct ResourceReleaseAtCycles {
+ unsigned ResourceIdx;
+ ReleaseAtCycles Cycles;
+ };
+ using InstResourceUsage = std::vector<ResourceReleaseAtCycles>;
+ std::vector<InstResourceUsage> ResourceUsage;
+ InstResourceUsage CommonResourceUsage;
unsigned NumResourceUnits;
void printResourcePressurePerIter(llvm::raw_ostream &OS) const;
``````````
</details>
https://github.com/llvm/llvm-project/pull/124904
More information about the llvm-commits
mailing list