From 733dc3e50b2d34ebccaba24ca72ce72b5a3545f6 Mon Sep 17 00:00:00 2001 From: Rahman Lavaee Date: Thu, 5 May 2022 11:37:15 -0700 Subject: [PATCH] [BOLT] Report per-section hotness in bolt-heatmap. This patch adds a new feature to bolt heatmap to print the hotness of each section in terms of the percentage of samples within that section. Sample output generated for the clang binary: Section Name, Begin Address, End Address, Percentage Hotness .text, 0x1a7b9b0, 0x20a2cc0, 1.4709 .init, 0x20a2cc0, 0x20a2ce1, 0.0001 .fini, 0x20a2ce4, 0x20a2cf2, 0.0000 .text.unlikely, 0x20a2d00, 0x431990c, 0.3061 .text.hot, 0x4319910, 0x4bc6927, 97.2197 .text.startup, 0x4bc6930, 0x4c10c89, 0.0058 .plt, 0x4c10c90, 0x4c12010, 0.9974 Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D124412 --- bolt/include/bolt/Profile/Heatmap.h | 22 +++++++++-- bolt/lib/Profile/DataAggregator.cpp | 22 ++++++++++- bolt/lib/Profile/Heatmap.cpp | 60 +++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/bolt/include/bolt/Profile/Heatmap.h b/bolt/include/bolt/Profile/Heatmap.h index 7ad72c512405..74d7eedc3078 100644 --- a/bolt/include/bolt/Profile/Heatmap.h +++ b/bolt/include/bolt/Profile/Heatmap.h @@ -12,12 +12,20 @@ #include "llvm/ADT/StringRef.h" #include #include +#include namespace llvm { class raw_ostream; namespace bolt { +/// Struct representing a section name and its address range in the binary. +struct SectionNameAndRange { + StringRef Name; + uint64_t BeginAddress; + uint64_t EndAddress; +}; + class Heatmap { /// Number of bytes per entry in the heat map. size_t BucketSize; @@ -34,11 +42,15 @@ class Heatmap { /// Map buckets to the number of samples. std::map Map; + /// Map section names to their address range. + const std::vector TextSections; + public: explicit Heatmap(uint64_t BucketSize = 4096, uint64_t MinAddress = 0, - uint64_t MaxAddress = std::numeric_limits::max()) - : BucketSize(BucketSize), MinAddress(MinAddress), - MaxAddress(MaxAddress){}; + uint64_t MaxAddress = std::numeric_limits::max(), + std::vector TextSections = {}) + : BucketSize(BucketSize), MinAddress(MinAddress), MaxAddress(MaxAddress), + TextSections(TextSections) {} inline bool ignoreAddress(uint64_t Address) const { return (Address > MaxAddress) || (Address < MinAddress); @@ -65,6 +77,10 @@ public: void printCDF(raw_ostream &OS) const; + void printSectionHotness(StringRef Filename) const; + + void printSectionHotness(raw_ostream &OS) const; + size_t size() const { return Map.size(); } }; diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 7992daaa9360..314ab8969d43 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -116,6 +116,22 @@ namespace { const char TimerGroupName[] = "aggregator"; const char TimerGroupDesc[] = "Aggregator"; +std::vector getTextSections(const BinaryContext *BC) { + std::vector sections; + for (BinarySection &Section : BC->sections()) { + if (!Section.isText()) + continue; + if (Section.getSize() == 0) + continue; + sections.push_back( + {Section.getName(), Section.getAddress(), Section.getEndAddress()}); + } + std::sort(sections.begin(), sections.end(), + [](const SectionNameAndRange &A, const SectionNameAndRange &B) { + return A.BeginAddress < B.BeginAddress; + }); + return sections; +} } constexpr uint64_t DataAggregator::KernelBaseAddr; @@ -1292,7 +1308,7 @@ std::error_code DataAggregator::printLBRHeatMap() { opts::HeatmapMinAddress = KernelBaseAddr; } Heatmap HM(opts::HeatmapBlock, opts::HeatmapMinAddress, - opts::HeatmapMaxAddress); + opts::HeatmapMaxAddress, getTextSections(BC)); uint64_t NumTotalSamples = 0; if (opts::BasicAggregation) { @@ -1374,6 +1390,10 @@ std::error_code DataAggregator::printLBRHeatMap() { HM.printCDF(opts::OutputFilename); else HM.printCDF(opts::OutputFilename + ".csv"); + if (opts::OutputFilename == "-") + HM.printSectionHotness(opts::OutputFilename); + else + HM.printSectionHotness(opts::OutputFilename + "-section-hotness.csv"); return std::error_code(); } diff --git a/bolt/lib/Profile/Heatmap.cpp b/bolt/lib/Profile/Heatmap.cpp index 9910aed777a1..9761829683cd 100644 --- a/bolt/lib/Profile/Heatmap.cpp +++ b/bolt/lib/Profile/Heatmap.cpp @@ -8,6 +8,7 @@ #include "bolt/Profile/Heatmap.h" #include "bolt/Utils/CommandLineOpts.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -251,5 +252,64 @@ void Heatmap::printCDF(raw_ostream &OS) const { Counts.clear(); } +void Heatmap::printSectionHotness(StringRef FileName) const { + std::error_code EC; + raw_fd_ostream OS(FileName, EC, sys::fs::OpenFlags::OF_None); + if (EC) { + errs() << "error opening output file: " << EC.message() << '\n'; + exit(1); + } + printSectionHotness(OS); +} + +void Heatmap::printSectionHotness(raw_ostream &OS) const { + uint64_t NumTotalCounts = 0; + StringMap SectionHotness; + unsigned TextSectionIndex = 0; + + if (TextSections.empty()) + return; + + uint64_t UnmappedHotness = 0; + auto RecordUnmappedBucket = [&](uint64_t Address, uint64_t Frequency) { + errs() << "Couldn't map the address bucket [0x" << Twine::utohexstr(Address) + << ", 0x" << Twine::utohexstr(Address + BucketSize) + << "] containing " << Frequency + << " samples to a text section in the binary."; + UnmappedHotness += Frequency; + }; + + for (const std::pair &KV : Map) { + NumTotalCounts += KV.second; + // We map an address bucket to the first section (lowest address) + // overlapping with that bucket. + auto Address = KV.first * BucketSize; + while (TextSectionIndex < TextSections.size() && + Address >= TextSections[TextSectionIndex].EndAddress) + TextSectionIndex++; + if (TextSectionIndex >= TextSections.size() || + Address + BucketSize < TextSections[TextSectionIndex].BeginAddress) { + RecordUnmappedBucket(Address, KV.second); + continue; + } + SectionHotness[TextSections[TextSectionIndex].Name] += KV.second; + } + + assert(NumTotalCounts > 0 && + "total number of heatmap buckets should be greater than 0"); + + OS << "Section Name, Begin Address, End Address, Percentage Hotness\n"; + for (auto &TextSection : TextSections) { + OS << TextSection.Name << ", 0x" + << Twine::utohexstr(TextSection.BeginAddress) << ", 0x" + << Twine::utohexstr(TextSection.EndAddress) << ", " + << format("%.4f", + 100.0 * SectionHotness[TextSection.Name] / NumTotalCounts) + << "\n"; + } + if (UnmappedHotness > 0) + OS << "[unmapped], 0x0, 0x0, " + << format("%.4f", 100.0 * UnmappedHotness / NumTotalCounts) << "\n"; +} } // namespace bolt } // namespace llvm