144 lines · cpp
1//===- RemarkInstructionMix.cpp -------------------------------------------===//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// Generic tool to extract instruction mix from asm-printer remarks.10//11//===----------------------------------------------------------------------===//12 13#include "RemarkUtilHelpers.h"14#include "RemarkUtilRegistry.h"15 16#include "llvm/Support/Format.h"17#include "llvm/Support/FormattedStream.h"18#include "llvm/Support/Regex.h"19 20#include <cmath>21#include <numeric>22 23using namespace llvm;24using namespace remarks;25using namespace llvm::remarkutil;26 27namespace instructionmix {28 29static cl::SubCommand30 InstructionMix("instruction-mix",31 "Instruction Mix (requires asm-printer remarks)");32 33static cl::opt<std::string>34 FunctionFilter("filter", cl::sub(InstructionMix), cl::ValueOptional,35 cl::desc("Optional function name to filter collection by"));36 37static cl::opt<std::string>38 FunctionFilterRE("rfilter", cl::sub(InstructionMix), cl::ValueOptional,39 cl::desc("Optional function name to filter collection by "40 "(accepts regular expressions)"));41 42enum ReportStyleOptions { human_output, csv_output };43static cl::opt<ReportStyleOptions> ReportStyle(44 "report_style", cl::sub(InstructionMix),45 cl::init(ReportStyleOptions::human_output),46 cl::desc("Choose the report output format:"),47 cl::values(clEnumValN(human_output, "human", "Human-readable format"),48 clEnumValN(csv_output, "csv", "CSV format")));49 50INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionMix)51INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionMix)52 53static Error tryInstructionMix() {54 auto MaybeOF =55 getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);56 if (!MaybeOF)57 return MaybeOF.takeError();58 59 auto OF = std::move(*MaybeOF);60 auto MaybeBuf = getInputMemoryBuffer(InputFileName);61 if (!MaybeBuf)62 return MaybeBuf.takeError();63 auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());64 if (!MaybeParser)65 return MaybeParser.takeError();66 67 Expected<std::optional<FilterMatcher>> Filter =68 FilterMatcher::createExactOrRE(FunctionFilter, FunctionFilterRE);69 if (!Filter)70 return Filter.takeError();71 72 // Collect the histogram of instruction counts.73 llvm::DenseMap<StringRef, unsigned> Histogram;74 auto &Parser = **MaybeParser;75 auto MaybeRemark = Parser.next();76 for (; MaybeRemark; MaybeRemark = Parser.next()) {77 Remark &Remark = **MaybeRemark;78 if (Remark.RemarkName != "InstructionMix")79 continue;80 if (*Filter && !(*Filter)->match(Remark.FunctionName))81 continue;82 for (auto &Arg : Remark.Args) {83 StringRef Key = Arg.Key;84 if (!Key.consume_front("INST_"))85 continue;86 unsigned Val = 0;87 bool ParseError = Arg.Val.getAsInteger(10, Val);88 assert(!ParseError);89 (void)ParseError;90 Histogram[Key] += Val;91 }92 }93 94 // Sort it.95 using MixEntry = std::pair<StringRef, unsigned>;96 llvm::SmallVector<MixEntry> Mix(Histogram.begin(), Histogram.end());97 std::sort(Mix.begin(), Mix.end(), [](const auto &LHS, const auto &RHS) {98 return LHS.second > RHS.second;99 });100 101 // Print the results.102 switch (ReportStyle) {103 case human_output: {104 formatted_raw_ostream FOS(OF->os());105 size_t MaxMnemonic =106 std::accumulate(Mix.begin(), Mix.end(), StringRef("Instruction").size(),107 [](size_t MaxMnemonic, const MixEntry &Elt) {108 return std::max(MaxMnemonic, Elt.first.size());109 });110 unsigned MaxValue = std::accumulate(111 Mix.begin(), Mix.end(), 1, [](unsigned MaxValue, const MixEntry &Elt) {112 return std::max(MaxValue, Elt.second);113 });114 unsigned ValueWidth = std::log10(MaxValue) + 1;115 FOS << "Instruction";116 FOS.PadToColumn(MaxMnemonic + 1) << "Count\n";117 FOS << "-----------";118 FOS.PadToColumn(MaxMnemonic + 1) << "-----\n";119 for (const auto &[Inst, Count] : Mix) {120 FOS << Inst;121 FOS.PadToColumn(MaxMnemonic + 1)122 << " " << format_decimal(Count, ValueWidth) << "\n";123 }124 } break;125 case csv_output: {126 OF->os() << "Instruction,Count\n";127 for (const auto &[Inst, Count] : Mix)128 OF->os() << Inst << "," << Count << "\n";129 } break;130 }131 132 auto E = MaybeRemark.takeError();133 if (!E.isA<EndOfFileError>())134 return E;135 consumeError(std::move(E));136 OF->keep();137 return Error::success();138}139 140static CommandRegistration InstructionMixReg(&InstructionMix,141 tryInstructionMix);142 143} // namespace instructionmix144