135 lines · cpp
1//===- bolt/tools/heatmap/heatmap.cpp - Profile heatmap visualization tool ===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "bolt/Rewrite/RewriteInstance.h"10#include "bolt/Utils/CommandLineOpts.h"11#include "llvm/MC/TargetRegistry.h"12#include "llvm/Object/Binary.h"13#include "llvm/Support/CommandLine.h"14#include "llvm/Support/Errc.h"15#include "llvm/Support/Error.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Program.h"18#include "llvm/Support/TargetSelect.h"19 20using namespace llvm;21using namespace bolt;22 23namespace opts {24 25static cl::OptionCategory *HeatmapCategories[] = {&HeatmapCategory,26 &BoltOutputCategory};27 28static cl::opt<std::string> InputFilename(cl::Positional,29 cl::desc("<executable>"),30 cl::Required,31 cl::cat(HeatmapCategory));32 33} // namespace opts34 35static StringRef ToolName;36 37static void report_error(StringRef Message, std::error_code EC) {38 assert(EC);39 errs() << ToolName << ": '" << Message << "': " << EC.message() << ".\n";40 exit(1);41}42 43static void report_error(StringRef Message, Error E) {44 assert(E);45 errs() << ToolName << ": '" << Message << "': " << toString(std::move(E))46 << ".\n";47 exit(1);48}49 50static std::string GetExecutablePath(const char *Argv0) {51 SmallString<256> ExecutablePath(Argv0);52 // Do a PATH lookup if Argv0 isn't a valid path.53 if (!llvm::sys::fs::exists(ExecutablePath))54 if (llvm::ErrorOr<std::string> P =55 llvm::sys::findProgramByName(ExecutablePath))56 ExecutablePath = *P;57 return std::string(ExecutablePath);58}59 60int main(int argc, char **argv) {61 cl::HideUnrelatedOptions(ArrayRef(opts::HeatmapCategories));62 cl::ParseCommandLineOptions(63 argc, argv,64 " BOLT Code Heatmap tool\n\n"65 " Produces code heatmaps using sampled profile\n\n"66 67 " Inputs:\n"68 " - Binary (supports BOLT-optimized binaries),\n"69 " - Sampled profile collected from the binary:\n"70 " - perf data or pre-aggregated profile data (instrumentation profile "71 "not supported)\n"72 " - perf data can have basic (IP) or branch-stack (brstack) "73 "samples\n\n"74 75 " Outputs:\n"76 " - Heatmaps: colored ASCII (requires a color-capable terminal or a"77 " conversion tool like `aha`)\n"78 " Multiple heatmaps are produced by default with different "79 "granularities (set by `block-size` option)\n"80 " - Section hotness: per-section samples% and utilization%\n"81 " - Cumulative distribution: working set size corresponding to a "82 "given percentile of samples\n");83 84 if (opts::PerfData.empty()) {85 errs() << ToolName << ": expected -perfdata=<filename> option.\n";86 exit(1);87 }88 89 opts::HeatmapMode = opts::HM_Exclusive;90 opts::AggregateOnly = true;91 if (!sys::fs::exists(opts::InputFilename))92 report_error(opts::InputFilename, errc::no_such_file_or_directory);93 94 // Output to stdout by default95 if (opts::OutputFilename.empty())96 opts::OutputFilename = "-";97 opts::HeatmapOutput.assign(opts::OutputFilename);98 99 // Initialize targets and assembly printers/parsers.100#define BOLT_TARGET(target) \101 LLVMInitialize##target##TargetInfo(); \102 LLVMInitialize##target##TargetMC(); \103 LLVMInitialize##target##AsmParser(); \104 LLVMInitialize##target##Disassembler(); \105 LLVMInitialize##target##Target(); \106 LLVMInitialize##target##AsmPrinter();107 108#include "bolt/Core/TargetConfig.def"109 110 ToolName = argv[0];111 std::string ToolPath = GetExecutablePath(argv[0]);112 Expected<OwningBinary<Binary>> BinaryOrErr =113 createBinary(opts::InputFilename);114 if (Error E = BinaryOrErr.takeError())115 report_error(opts::InputFilename, std::move(E));116 Binary &Binary = *BinaryOrErr.get().getBinary();117 118 if (auto *e = dyn_cast<ELFObjectFileBase>(&Binary)) {119 auto RIOrErr = RewriteInstance::create(e, argc, argv, ToolPath);120 if (Error E = RIOrErr.takeError())121 report_error("RewriteInstance", std::move(E));122 123 RewriteInstance &RI = *RIOrErr.get();124 if (Error E = RI.setProfile(opts::PerfData))125 report_error(opts::PerfData, std::move(E));126 127 if (Error E = RI.run())128 report_error(opts::InputFilename, std::move(E));129 } else {130 report_error(opts::InputFilename, object_error::invalid_file_type);131 }132 133 return EXIT_SUCCESS;134}135