#include "bolt/Profile/DataAggregator.h"
#include "bolt/Core/BinaryContext.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Passes/BinaryPasses.h"
#include "bolt/Profile/BoltAddressTranslation.h"
#include "bolt/Profile/Heatmap.h"
#include "bolt/Profile/YAMLProfileWriter.h"
#include "bolt/Utils/CommandLineOpts.h"
#include "bolt/Utils/Utils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <optional>
#include <unordered_map>
#include <utility>
#define DEBUG_TYPE …
usingnamespacellvm;
usingnamespacebolt;
namespace opts {
static cl::opt<bool>
BasicAggregation("nl",
cl::desc("aggregate basic samples (without LBR info)"),
cl::cat(AggregatorCategory));
static cl::opt<std::string>
ITraceAggregation("itrace",
cl::desc("Generate LBR info with perf itrace argument"),
cl::cat(AggregatorCategory));
static cl::opt<bool>
FilterMemProfile("filter-mem-profile",
cl::desc("if processing a memory profile, filter out stack or heap accesses "
"that won't be useful for BOLT to reduce profile file size"),
cl::init(true),
cl::cat(AggregatorCategory));
static cl::opt<unsigned long long>
FilterPID("pid",
cl::desc("only use samples from process with specified PID"),
cl::init(0),
cl::Optional,
cl::cat(AggregatorCategory));
static cl::opt<bool>
IgnoreBuildID("ignore-build-id",
cl::desc("continue even if build-ids in input binary and perf.data mismatch"),
cl::init(false),
cl::cat(AggregatorCategory));
static cl::opt<bool> IgnoreInterruptLBR(
"ignore-interrupt-lbr",
cl::desc("ignore kernel interrupt LBR that happens asynchronously"),
cl::init(true), cl::cat(AggregatorCategory));
static cl::opt<unsigned long long>
MaxSamples("max-samples",
cl::init(-1ULL),
cl::desc("maximum number of samples to read from LBR profile"),
cl::Optional,
cl::Hidden,
cl::cat(AggregatorCategory));
extern cl::opt<opts::ProfileFormatKind> ProfileFormat;
extern cl::opt<bool> ProfileWritePseudoProbes;
extern cl::opt<std::string> SaveProfile;
cl::opt<bool> ReadPreAggregated(
"pa", cl::desc("skip perf and read data from a pre-aggregated file format"),
cl::cat(AggregatorCategory));
static cl::opt<bool>
TimeAggregator("time-aggr",
cl::desc("time BOLT aggregator"),
cl::init(false),
cl::ZeroOrMore,
cl::cat(AggregatorCategory));
static cl::opt<bool>
UseEventPC("use-event-pc",
cl::desc("use event PC in combination with LBR sampling"),
cl::cat(AggregatorCategory));
static cl::opt<bool> WriteAutoFDOData(
"autofdo", cl::desc("generate autofdo textual data instead of bolt data"),
cl::cat(AggregatorCategory));
}
namespace {
const char TimerGroupName[] = …;
const char TimerGroupDesc[] = …;
std::vector<SectionNameAndRange> getTextSections(const BinaryContext *BC) { … }
}
constexpr uint64_t DataAggregator::KernelBaseAddr;
DataAggregator::~DataAggregator() { … }
namespace {
void deleteTempFile(const std::string &FileName) { … }
}
void DataAggregator::deleteTempFiles() { … }
void DataAggregator::findPerfExecutable() { … }
void DataAggregator::start() { … }
void DataAggregator::abort() { … }
void DataAggregator::launchPerfProcess(StringRef Name, PerfProcessInfo &PPI,
const char *ArgsString, bool Wait) { … }
void DataAggregator::processFileBuildID(StringRef FileBuildID) { … }
bool DataAggregator::checkPerfDataMagic(StringRef FileName) { … }
void DataAggregator::parsePreAggregated() { … }
std::error_code DataAggregator::writeAutoFDOData(StringRef OutputFilename) { … }
void DataAggregator::filterBinaryMMapInfo() { … }
int DataAggregator::prepareToParse(StringRef Name, PerfProcessInfo &Process,
PerfProcessErrorCallbackTy Callback) { … }
Error DataAggregator::preprocessProfile(BinaryContext &BC) { … }
Error DataAggregator::readProfile(BinaryContext &BC) { … }
bool DataAggregator::mayHaveProfileData(const BinaryFunction &Function) { … }
void DataAggregator::processProfile(BinaryContext &BC) { … }
BinaryFunction *
DataAggregator::getBinaryFunctionContainingAddress(uint64_t Address) const { … }
BinaryFunction *
DataAggregator::getBATParentFunction(const BinaryFunction &Func) const { … }
StringRef DataAggregator::getLocationName(const BinaryFunction &Func,
bool BAT) { … }
bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address,
uint64_t Count) { … }
bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From,
uint64_t To, uint64_t Count,
uint64_t Mispreds) { … }
bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
BinaryFunction *ToFunc, uint64_t From,
uint64_t To, uint64_t Count,
uint64_t Mispreds) { … }
bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
uint64_t Mispreds) { … }
bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
uint64_t Count) { … }
std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>>
DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
const LBREntry &FirstLBR,
const LBREntry &SecondLBR,
uint64_t Count) const { … }
bool DataAggregator::recordEntry(BinaryFunction &BF, uint64_t To, bool Mispred,
uint64_t Count) const { … }
bool DataAggregator::recordExit(BinaryFunction &BF, uint64_t From, bool Mispred,
uint64_t Count) const { … }
ErrorOr<LBREntry> DataAggregator::parseLBREntry() { … }
bool DataAggregator::checkAndConsumeFS() { … }
void DataAggregator::consumeRestOfLine() { … }
bool DataAggregator::checkNewLine() { … }
ErrorOr<DataAggregator::PerfBranchSample> DataAggregator::parseBranchSample() { … }
ErrorOr<DataAggregator::PerfBasicSample> DataAggregator::parseBasicSample() { … }
ErrorOr<DataAggregator::PerfMemSample> DataAggregator::parseMemSample() { … }
ErrorOr<Location> DataAggregator::parseLocationOrOffset() { … }
ErrorOr<DataAggregator::AggregatedLBREntry>
DataAggregator::parseAggregatedLBREntry() { … }
bool DataAggregator::ignoreKernelInterrupt(LBREntry &LBR) const { … }
std::error_code DataAggregator::printLBRHeatMap() { … }
uint64_t DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
bool NeedsSkylakeFix) { … }
std::error_code DataAggregator::parseBranchEvents() { … }
void DataAggregator::processBranchEvents() { … }
std::error_code DataAggregator::parseBasicEvents() { … }
void DataAggregator::processBasicEvents() { … }
std::error_code DataAggregator::parseMemEvents() { … }
void DataAggregator::processMemEvents() { … }
std::error_code DataAggregator::parsePreAggregatedLBRSamples() { … }
void DataAggregator::processPreAggregated() { … }
std::optional<int32_t> DataAggregator::parseCommExecEvent() { … }
namespace {
std::optional<uint64_t> parsePerfTime(const StringRef TimeStr) { … }
}
std::optional<DataAggregator::ForkInfo> DataAggregator::parseForkEvent() { … }
ErrorOr<std::pair<StringRef, DataAggregator::MMapInfo>>
DataAggregator::parseMMapEvent() { … }
std::error_code DataAggregator::parseMMapEvents() { … }
std::error_code DataAggregator::parseTaskEvents() { … }
std::optional<std::pair<StringRef, StringRef>>
DataAggregator::parseNameBuildIDPair() { … }
bool DataAggregator::hasAllBuildIDs() { … }
std::optional<StringRef>
DataAggregator::getFileNameForBuildID(StringRef FileBuildID) { … }
std::error_code
DataAggregator::writeAggregatedFile(StringRef OutputFilename) const { … }
std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
StringRef OutputFilename) const { … }
void DataAggregator::dump() const { … }
void DataAggregator::dump(const LBREntry &LBR) const { … }
void DataAggregator::dump(const PerfBranchSample &Sample) const { … }
void DataAggregator::dump(const PerfMemSample &Sample) const { … }