Index: llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-1.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-1.s @@ -0,0 +1,35 @@ + .text + .file "Hello_world.c" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl $0, -4(%rbp) + movabsq $.L.str, %rdi + movb $0, %al + callq printf + xorl %eax, %eax + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .type .L.str,@object # @.str + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "Hello world! \n" + .size .L.str, 15 + + .ident "clang version 14.0.0 (https://github.com/mmatic05/llvm-project.git 7ab6229b2185595432ee3503bdb8136bd5a32a85)" + .section ".note.GNU-stack","",@progbits Index: llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-2.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-2.s @@ -0,0 +1,28 @@ + .text + .file "Hello_world.c" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# %bb.0: # %entry + pushq %rax + .cfi_def_cfa_offset 16 + movl $.Lstr, %edi + callq puts@PLT + xorl %eax, %eax + popq %rcx + .cfi_def_cfa_offset 8 + retq +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .type .Lstr,@object # @str + .section .rodata.str1.1,"aMS",@progbits,1 +.Lstr: + .asciz "Hello world! " + .size .Lstr, 14 + + .ident "clang version 14.0.0 (https://github.com/mmatic05/llvm-project.git 7ab6229b2185595432ee3503bdb8136bd5a32a85)" + .section ".note.GNU-stack","",@progbits Index: llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-3.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-3.s @@ -0,0 +1,66 @@ + .text + .file "sum.c" + .globl sum # -- Begin function sum + .p2align 4, 0x90 + .type sum,@function +sum: # @sum + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -8(%rbp) + movl %esi, -4(%rbp) + movl -8(%rbp), %eax + addl -4(%rbp), %eax + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Lfunc_end0: + .size sum, .Lfunc_end0-sum + .cfi_endproc + # -- End function + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl $0, -16(%rbp) + movl $1, -8(%rbp) + movl $5, -4(%rbp) + movl -8(%rbp), %edi + movl -4(%rbp), %esi + callq sum + movl %eax, -12(%rbp) + movl -8(%rbp), %esi + movl -4(%rbp), %edx + movl -12(%rbp), %ecx + movabsq $.L.str, %rdi + movb $0, %al + callq printf + xorl %eax, %eax + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function + .type .L.str,@object # @.str + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "sum(%d,%d)=%d \n" + .size .L.str, 16 + + .ident "clang version 14.0.0 (https://github.com/mmatic05/llvm-project.git 00f463e835d4baa285bc488c9fcb859e0461e452)" + .section ".note.GNU-stack","",@progbits Index: llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-4.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/Inputs/diff-option-file-4.s @@ -0,0 +1,46 @@ + .text + .file "sum.c" + .globl sum # -- Begin function sum + .p2align 4, 0x90 + .type sum,@function +sum: # @sum + .cfi_startproc +# %bb.0: # %entry + # kill: def $esi killed $esi def $rsi + # kill: def $edi killed $edi def $rdi + leal (%rdi,%rsi), %eax + retq +.Lfunc_end0: + .size sum, .Lfunc_end0-sum + .cfi_endproc + # -- End function + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# %bb.0: # %entry + pushq %rax + .cfi_def_cfa_offset 16 + movl $.L.str, %edi + movl $1, %esi + movl $5, %edx + movl $6, %ecx + xorl %eax, %eax + callq printf + xorl %eax, %eax + popq %rcx + .cfi_def_cfa_offset 8 + retq +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function + .type .L.str,@object # @.str + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "sum(%d,%d)=%d \n" + .size .L.str, 16 + + .ident "clang version 14.0.0 (https://github.com/mmatic05/llvm-project.git 00f463e835d4baa285bc488c9fcb859e0461e452)" + .section ".note.GNU-stack","",@progbits Index: llvm/test/tools/llvm-mca/X86/diff-option-four-files.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/diff-option-four-files.s @@ -0,0 +1,30 @@ +# RUN: llvm-mca -diff %p/Inputs/diff-option-file-1.s %p/Inputs/diff-option-file-2.s %p/Inputs/diff-option-file-3.s %p/Inputs/diff-option-file-4.s 2>&1 | FileCheck %s + +# CHECK: Input files: +# CHECK-NEXT: [f1]: diff-option-file-1.s +# CHECK-NEXT: [f2]: diff-option-file-2.s +# CHECK-NEXT: [f3]: diff-option-file-3.s +# CHECK-NEXT: [f4]: diff-option-file-4.s + +# CHECK: Iterations: 100 + +# CHECK: [f1]: [f2]: [f3]: [f4]: +# CHECK-NEXT: Instructions: 1100 600 2800 1200 +# CHECK-NEXT: Total Cycles: 1097 897 2192 1096 +# CHECK-NEXT: Total uOps: 1900 1400 4500 2200 +# CHECK-NEXT: Dispatch Width: 6 6 6 6 +# CHECK-NEXT: uOps Per Cycle: 1.73 1.56 2.05 2.01 +# CHECK-NEXT: IPC: 1.00 0.67 1.28 1.09 +# CHECK-NEXT: Block RThroughput: 3.17 2.33 10.00 3.67 + +# CHECK: Resource pressure per iteration: +# CHECK-NEXT: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] +# CHECK-NEXT: [f1]: +# CHECK-NEXT: - - 2.72 2.76 1.66 1.68 3.00 2.76 2.76 1.66 +# CHECK-NEXT: [f2]: +# CHECK-NEXT: - - 1.11 1.95 1.33 1.34 2.00 1.95 1.99 1.33 +# CHECK-NEXT: [f3]: +# CHECK-NEXT: - - 4.71 4.72 7.00 7.00 10.00 4.73 4.84 7.00 +# CHECK-NEXT: [f4]: +# CHECK-NEXT: - - 3.00 3.00 1.75 1.76 2.00 3.01 3.99 1.49 + Index: llvm/test/tools/llvm-mca/X86/diff-option-two-files.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/X86/diff-option-two-files.s @@ -0,0 +1,24 @@ +# RUN: llvm-mca -diff %p/Inputs/diff-option-file-1.s %p/Inputs/diff-option-file-2.s 2>&1 | FileCheck %s + +# CHECK: Input files: +# CHECK-NEXT: [f1]: diff-option-file-1.s +# CHECK-NEXT: [f2]: diff-option-file-2.s + +# CHECK: Iterations: 100 + +# CHECK: [f1]: [f2]: +# CHECK-NEXT: Instructions: 1100 600 +# CHECK-NEXT: Total Cycles: 1097 897 +# CHECK-NEXT: Total uOps: 1900 1400 +# CHECK-NEXT: Dispatch Width: 6 6 +# CHECK-NEXT: uOps Per Cycle: 1.73 1.56 +# CHECK-NEXT: IPC: 1.00 0.67 +# CHECK-NEXT: Block RThroughput: 3.17 2.33 + +# CHECK: Resource pressure per iteration: +# CHECK-NEXT: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] +# CHECK-NEXT: [f1]: +# CHECK-NEXT: - - 2.72 2.76 1.66 1.68 3.00 2.76 2.76 1.66 +# CHECK-NEXT: [f2]: +# CHECK-NEXT: - - 1.11 1.95 1.33 1.34 2.00 1.95 1.99 1.33 + Index: llvm/tools/llvm-mca/CMakeLists.txt =================================================================== --- llvm/tools/llvm-mca/CMakeLists.txt +++ llvm/tools/llvm-mca/CMakeLists.txt @@ -17,6 +17,7 @@ CodeRegion.cpp CodeRegionGenerator.cpp PipelinePrinter.cpp + MachineCodePerformance.cpp Views/BottleneckAnalysis.cpp Views/DispatchStatistics.cpp Views/InstructionInfoView.cpp Index: llvm/tools/llvm-mca/MachineCodePerformance.h =================================================================== --- /dev/null +++ llvm/tools/llvm-mca/MachineCodePerformance.h @@ -0,0 +1,66 @@ +//===----------------------- MachineCodePerformance.h --------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements class MachineCodePerformance. +/// +/// MachineCodePerformance allows to collect machine code performance of an +/// input assembler file. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_MACHINECODEPERFORMANCE_H +#define LLVM_TOOLS_LLVM_MCA_MACHINECODEPERFORMANCE_H + +#include "Views/ResourcePressureView.h" +#include "Views/SummaryView.h" +#include "llvm/MCA/Pipeline.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace mca { + +class MachineCodePerformance { +public: + class FileParameters { + public: + SmallVector ResourcePressurePerIter; + unsigned Iterations; + unsigned Instructions; + unsigned TotalCycles; + unsigned TotalUOps; + unsigned DispatchWidth; + double UOpsPerCycle; + double IPC; + double BlockRThroughput; + FileParameters() : ResourcePressurePerIter() {} + }; + +private: + Pipeline &P; + std::unique_ptr summaryView; + std::unique_ptr resourcePressureView; + FileParameters FP; + +public: + MachineCodePerformance(Pipeline &Pipe); + void addSummaryView(std::unique_ptr V); + void addResourcePressureView(std::unique_ptr V); + void collectFileParameters(); + FileParameters getFileParameters() const; + void printColNamesOfResourcePressurePerIter(raw_ostream &OS, + const MCSchedModel &SM) const; + void + printResourcePressurePerIterWithoutColNames(raw_ostream &OS, + const MCSchedModel &SM) const; +}; +} // namespace mca +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_MCA_MACHINECODEPERFORMANCE_H Index: llvm/tools/llvm-mca/MachineCodePerformance.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-mca/MachineCodePerformance.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements the MachineCodePerformance interface. +/// +//===----------------------------------------------------------------------===// + +#include "MachineCodePerformance.h" +#include "Views/InstructionView.h" + +namespace llvm { +namespace mca { + +MachineCodePerformance::MachineCodePerformance(Pipeline &Pipe) : P(Pipe) {} + +void MachineCodePerformance::addSummaryView(std::unique_ptr V) { + P.addEventListener(V.get()); + summaryView = std::move(V); +} + +void MachineCodePerformance::addResourcePressureView( + std::unique_ptr V) { + P.addEventListener(V.get()); + resourcePressureView = std::move(V); +} + +void MachineCodePerformance::collectFileParameters() { + summaryView->getSummaryViewParameters( + FP.Instructions, FP.Iterations, FP.TotalCycles, FP.DispatchWidth, + FP.TotalUOps, FP.IPC, FP.UOpsPerCycle, FP.BlockRThroughput); + resourcePressureView->getResourcePressurePerIter(FP.ResourcePressurePerIter); +} + +MachineCodePerformance::FileParameters +MachineCodePerformance::getFileParameters() const { + return FP; +} + +void MachineCodePerformance::printColNamesOfResourcePressurePerIter( + raw_ostream &OS, const MCSchedModel &SM) const { + resourcePressureView->printColNamesOfResourcePressurePerIter(OS, SM); +} + +void MachineCodePerformance::printResourcePressurePerIterWithoutColNames( + raw_ostream &OS, const MCSchedModel &SM) const { + resourcePressureView->printResourcePressurePerIterWithoutColNames(OS, SM); +} +} // namespace mca +} // namespace llvm Index: llvm/tools/llvm-mca/Views/ResourcePressureView.h =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.h +++ llvm/tools/llvm-mca/Views/ResourcePressureView.h @@ -96,6 +96,13 @@ } StringRef getNameAsString() const override { return "ResourcePressureView"; } json::Value toJSON() const override; + void getResourcePressurePerIter( + SmallVector &ResourcePressurePerIter) const; + void printColNamesOfResourcePressurePerIter(raw_ostream &OS, + const MCSchedModel &SM) const; + void + printResourcePressurePerIterWithoutColNames(raw_ostream &OS, + const MCSchedModel &SM) const; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/ResourcePressureView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -196,5 +196,53 @@ json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}}); return JO; } + +void ResourcePressureView::getResourcePressurePerIter( + SmallVector &ResourcePressurePerIter) const { + ResourcePressurePerIter = SmallVector(); + ArrayRef Source = mca::InstructionView::getSource(); + const unsigned Executions = LastInstructionIdx / Source.size() + 1; + + for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) { + double Usage = ResourceUsage[I + Source.size() * E]; + if (!(Usage / Executions) || (Usage / Executions) < 0.005) { + ResourcePressurePerIter.push_back(" - "); + } else { + ResourcePressurePerIter.push_back( + std::to_string((((Usage / Executions) * 100) + 0.5) / 100)); + } + } +} + +void ResourcePressureView::printColNamesOfResourcePressurePerIter( + raw_ostream &OS, const MCSchedModel &SM) const { + std::string Buffer; + raw_string_ostream TempStream(Buffer); + formatted_raw_ostream FOS(TempStream); + + FOS << "\n\nResource pressure per iteration:\n"; + FOS.flush(); + printColumnNames(FOS, SM); + FOS << '\n'; + FOS.flush(); + OS << Buffer; +} + +void ResourcePressureView::printResourcePressurePerIterWithoutColNames( + raw_ostream &OS, const MCSchedModel &SM) const { + std::string Buffer; + raw_string_ostream TempStream(Buffer); + formatted_raw_ostream FOS(TempStream); + + ArrayRef Source = getSource(); + const unsigned Executions = LastInstructionIdx / Source.size() + 1; + for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) { + double Usage = ResourceUsage[I + Source.size() * E]; + printResourcePressure(FOS, Usage / Executions, (I + 1) * 7); + } + + FOS.flush(); + OS << Buffer; +} } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/SummaryView.h =================================================================== --- llvm/tools/llvm-mca/Views/SummaryView.h +++ llvm/tools/llvm-mca/Views/SummaryView.h @@ -83,6 +83,11 @@ void printView(llvm::raw_ostream &OS) const override; StringRef getNameAsString() const override { return "SummaryView"; } json::Value toJSON() const override; + void getSummaryViewParameters(unsigned &Instructions, unsigned &Iterations, + unsigned &TotalCycles, unsigned &DispatchWidth, + unsigned &TotalUOps, double &IPC, + double &UOpsPerCycle, + double &BlockRThroughput) const; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/SummaryView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/SummaryView.cpp +++ llvm/tools/llvm-mca/Views/SummaryView.cpp @@ -109,5 +109,21 @@ {"BlockRThroughput", DV.BlockRThroughput}}); return JO; } + +void SummaryView::getSummaryViewParameters( + unsigned &Instructions, unsigned &Iterations, unsigned &TotalCycles, + unsigned &DispatchWidth, unsigned &TotalUOps, double &IPC, + double &UOpsPerCycle, double &BlockRThroughput) const { + DisplayValues DV; + collectData(DV); + Instructions = DV.TotalInstructions; + Iterations = DV.Iterations; + TotalCycles = DV.TotalCycles; + TotalUOps = DV.TotalUOps; + DispatchWidth = DV.DispatchWidth; + UOpsPerCycle = DV.UOpsPerCycle; + IPC = DV.IPC; + BlockRThroughput = DV.BlockRThroughput; +} } // namespace mca. } // namespace llvm Index: llvm/tools/llvm-mca/llvm-mca.cpp =================================================================== --- llvm/tools/llvm-mca/llvm-mca.cpp +++ llvm/tools/llvm-mca/llvm-mca.cpp @@ -22,6 +22,7 @@ #include "CodeRegion.h" #include "CodeRegionGenerator.h" +#include "MachineCodePerformance.h" #include "PipelinePrinter.h" #include "Views/BottleneckAnalysis.h" #include "Views/DispatchStatistics.h" @@ -72,6 +73,10 @@ cl::desc(""), cl::cat(ToolOptions), cl::init("-")); +static cl::list InputFilenames(cl::Positional, cl::ZeroOrMore, + cl::desc(""), + cl::cat(ToolOptions)); + static cl::opt OutputFilename("o", cl::desc("Output filename"), cl::init("-"), cl::cat(ToolOptions), cl::value_desc("filename")); @@ -225,6 +230,12 @@ "Disable custom behaviour (use the default class which does nothing)."), cl::cat(ViewOptions), cl::init(false)); +static cl::opt + PrintDifference("diff", + cl::desc("Compare the statistics (results of the llvm-mca " + "tool) to the attached assembler files."), + cl::cat(ToolOptions), cl::init(false)); + namespace { const Target *getTarget(const char *ProgName) { @@ -301,23 +312,14 @@ return true; } -int main(int argc, char **argv) { - InitLLVM X(argc, argv); - - // Initialize targets and assembly parsers. - InitializeAllTargetInfos(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - InitializeAllTargetMCAs(); - - // Enable printing of available targets when flag --version is specified. - cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - - cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); +std::unique_ptr TOF; +SmallVector> + MachineCodePerformances; +std::unique_ptr MCSM; - // Parse flags and initialize target options. - cl::ParseCommandLineOptions(argc, argv, - "llvm machine code performance analyzer.\n"); +// Generating llvm-mca statistics for a single input file. +static int oneCycle(char **argv, std::string InputFilename) { + std::unique_ptr MCP; // Get the target from the triple. If a triple is not specified, then select // the default triple for the host. If the triple doesn't correspond to any @@ -438,13 +440,6 @@ return 1; } - // Now initialize the output file. - auto OF = getOutputStream(); - if (std::error_code EC = OF.getError()) { - WithColor::error() << EC.message() << '\n'; - return 1; - } - unsigned AssemblerDialect = CRG.getAssemblerDialect(); if (OutputAsmVariant >= 0) AssemblerDialect = static_cast(OutputAsmVariant); @@ -461,10 +456,12 @@ // Set the display preference for hex vs. decimal immediates. IP->setPrintImmHex(PrintImmHex); - std::unique_ptr TOF = std::move(*OF); - const MCSchedModel &SM = STI->getSchedModel(); + if (MCSM == nullptr) { + MCSM = std::make_unique(STI->getSchedModel()); + } + // Create an instruction builder. mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get()); @@ -561,12 +558,13 @@ if (!runPipeline(*P)) return 1; - if (PrintJson) { - Printer.printReport(JSONOutput); - } else { - Printer.printReport(TOF->os()); + if (!PrintDifference) { + if (PrintJson) { + Printer.printReport(JSONOutput); + } else { + Printer.printReport(TOF->os()); + } } - ++RegionIdx; continue; } @@ -591,6 +589,11 @@ mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO); + if (PrintDifference) { + MCP = std::make_unique( + mca::MachineCodePerformance(*P)); + } + // Targets can define their own custom Views that exist within their // /lib/Target/ directory so that the View can utilize their CustomBehaviour // or other backend symbols / functionality that are not already exposed @@ -617,6 +620,10 @@ Printer.addView( std::make_unique(SM, Insts, DispatchWidth)); + if (PrintDifference) + MCP->addSummaryView( + std::make_unique(SM, Insts, DispatchWidth)); + if (EnableBottleneckAnalysis) { if (!IsOutOfOrder) { WithColor::warning() @@ -657,6 +664,11 @@ Printer.addView( std::make_unique(*STI, *IP, Insts)); + if (PrintDifference) { + MCP->addResourcePressureView( + std::make_unique(*STI, *IP, Insts)); + } + if (PrintTimelineView) { unsigned TimelineIterations = TimelineMaxIterations ? TimelineMaxIterations : 10; @@ -678,17 +690,309 @@ if (!runPipeline(*P)) return 1; - if (PrintJson) { - Printer.printReport(JSONOutput); - } else { - Printer.printReport(TOF->os()); + if (!PrintDifference) { + if (PrintJson) { + Printer.printReport(JSONOutput); + } else { + Printer.printReport(TOF->os()); + } } - ++RegionIdx; } - if (PrintJson) - TOF->os() << formatv("{0:2}", json::Value(std::move(JSONOutput))) << "\n"; + if (!PrintDifference) { + if (PrintJson) + TOF->os() << formatv("{0:2}", json::Value(std::move(JSONOutput))) << "\n"; + } else { + MCP->collectFileParameters(); + MachineCodePerformances.push_back(std::move(MCP)); + } + + return 0; +} + +// Returns the name of the file to be analyzed from the path it is on. +static std::string getFilenameFromPath(std::string FilePath) { + size_t LastSlashPosition = FilePath.rfind("/"); + return FilePath.substr(LastSlashPosition + 1, + FilePath.length() - LastSlashPosition - 1); +} + +static int printCompareResults() { + constexpr unsigned ParameterTypesSize = 20; + constexpr unsigned SpacedFormattedOutputSize = 20; + constexpr unsigned FormatedValueLength = 28; + constexpr float FollowRoundingRules = 0.5; + constexpr unsigned TwoDecimalPlaceShift = 100; + constexpr unsigned TwoPlacesSavedFromDecimalPoint = 3; + + std::string ParameterTypes[8] = { + "Iterations", "Instructions", "Total Cycles", "Total uOps", + "Dispatch Width", "uOps Per Cycle", "IPC", "Block RThroughput"}; + + if (!PrintJson) { + std::string FormatedValue; + std::string SpacedFormattedOutput = " "; + SpacedFormattedOutput.resize(SpacedFormattedOutputSize, ' '); + + for (int i = 0; i < 8; i++) { + ParameterTypes[i] += ":"; + ParameterTypes[i].resize(ParameterTypesSize, ' '); + } + + TOF->os() << "\nInput files: \n"; + TOF->os() << "[f1]: " << getFilenameFromPath(InputFilename) << "\n"; + for (unsigned long i = 0; i < InputFilenames.size(); i++) + TOF->os() << "[f" << i + 2 + << "]: " << getFilenameFromPath(InputFilenames[i]) << "\n"; + + TOF->os() << "\nIterations: " + << MachineCodePerformances[0]->getFileParameters().Iterations + << "\n"; + + TOF->os() << " "; + FormatedValue = "[f1]:"; + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + for (unsigned long i = 1; i <= InputFilenames.size(); i++) { + FormatedValue = "[f" + std::to_string(i + 1) + "]:"; + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[1] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string(mcp->getFileParameters().Instructions); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[2] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string(mcp->getFileParameters().TotalCycles); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[3] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string(mcp->getFileParameters().TotalUOps); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[4] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string(mcp->getFileParameters().DispatchWidth); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[5] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string( + floor((mcp->getFileParameters().UOpsPerCycle * TwoDecimalPlaceShift) + + FollowRoundingRules) / + TwoDecimalPlaceShift); + FormatedValue.resize(FormatedValue.find('.') + + TwoPlacesSavedFromDecimalPoint); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[6] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = std::to_string( + floor((mcp->getFileParameters().IPC * TwoDecimalPlaceShift) + + FollowRoundingRules) / + TwoDecimalPlaceShift); + FormatedValue.resize(FormatedValue.find('.') + + TwoPlacesSavedFromDecimalPoint); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + TOF->os() << ParameterTypes[7] << SpacedFormattedOutput; + for (const auto &mcp : MachineCodePerformances) { + FormatedValue = + std::to_string(floor((mcp->getFileParameters().BlockRThroughput * + TwoDecimalPlaceShift) + + FollowRoundingRules) / + TwoDecimalPlaceShift); + FormatedValue.resize(FormatedValue.find('.') + + TwoPlacesSavedFromDecimalPoint); + FormatedValue.resize(FormatedValueLength, ' '); + TOF->os() << FormatedValue << " "; + } + TOF->os() << "\n"; + + MachineCodePerformances[0]->printColNamesOfResourcePressurePerIter( + TOF->os(), *MCSM); + for (unsigned long i = 0; i < MachineCodePerformances.size(); i++) { + TOF->os() << "[f" << i + 1 << "]: \n"; + MachineCodePerformances[i]->printResourcePressurePerIterWithoutColNames( + TOF->os(), *MCSM); + TOF->os() << "\n"; + } + + TOF->os() << "\n\n"; + + } else { + SmallVector JsonObjVector{}; + json::Object JsonObjCreatedByVector; + json::Object JsonObjVectorElem; + std::string ResourcePressurePerIteration = ""; + std::string OrdinalNumberOfFile; + + JsonObjVectorElem["Name"] = getFilenameFromPath(InputFilename); + JsonObjVectorElem[ParameterTypes[0]] = + MachineCodePerformances[0]->getFileParameters().Iterations; + JsonObjVectorElem[ParameterTypes[1]] = + MachineCodePerformances[0]->getFileParameters().Instructions; + JsonObjVectorElem[ParameterTypes[2]] = + MachineCodePerformances[0]->getFileParameters().TotalCycles; + JsonObjVectorElem[ParameterTypes[3]] = + MachineCodePerformances[0]->getFileParameters().TotalUOps; + JsonObjVectorElem[ParameterTypes[4]] = + MachineCodePerformances[0]->getFileParameters().DispatchWidth; + JsonObjVectorElem[ParameterTypes[5]] = + MachineCodePerformances[0]->getFileParameters().UOpsPerCycle; + JsonObjVectorElem[ParameterTypes[6]] = + MachineCodePerformances[0]->getFileParameters().IPC; + JsonObjVectorElem[ParameterTypes[7]] = + MachineCodePerformances[0]->getFileParameters().BlockRThroughput; + + ResourcePressurePerIteration = ""; + for (unsigned long j = 0; j < MachineCodePerformances[0] + ->getFileParameters() + .ResourcePressurePerIter.size(); + j++) { + ResourcePressurePerIteration += MachineCodePerformances[0] + ->getFileParameters() + .ResourcePressurePerIter[j]; + if (j != MachineCodePerformances[0] + ->getFileParameters() + .ResourcePressurePerIter.size() - + 1) + ResourcePressurePerIteration += ", "; + } + JsonObjVectorElem["Resource pressure per iteration"] = + ResourcePressurePerIteration; + JsonObjVector.push_back(std::move(JsonObjVectorElem)); + + for (unsigned long i = 0; i < InputFilenames.size(); i++) { + JsonObjVectorElem["Name"] = getFilenameFromPath(InputFilenames[i]); + JsonObjVectorElem[ParameterTypes[0]] = + MachineCodePerformances[i + 1]->getFileParameters().Iterations; + JsonObjVectorElem[ParameterTypes[1]] = + MachineCodePerformances[i + 1]->getFileParameters().Instructions; + JsonObjVectorElem[ParameterTypes[2]] = + MachineCodePerformances[i + 1]->getFileParameters().TotalCycles; + JsonObjVectorElem[ParameterTypes[3]] = + MachineCodePerformances[i + 1]->getFileParameters().TotalUOps; + JsonObjVectorElem[ParameterTypes[4]] = + MachineCodePerformances[i + 1]->getFileParameters().DispatchWidth; + JsonObjVectorElem[ParameterTypes[5]] = + MachineCodePerformances[i + 1]->getFileParameters().UOpsPerCycle; + JsonObjVectorElem[ParameterTypes[6]] = + MachineCodePerformances[i + 1]->getFileParameters().IPC; + JsonObjVectorElem[ParameterTypes[7]] = + MachineCodePerformances[i + 1]->getFileParameters().BlockRThroughput; + + ResourcePressurePerIteration = ""; + for (unsigned long j = 0; j < MachineCodePerformances[i + 1] + ->getFileParameters() + .ResourcePressurePerIter.size(); + j++) { + ResourcePressurePerIteration += MachineCodePerformances[i + 1] + ->getFileParameters() + .ResourcePressurePerIter[j]; + if (j != MachineCodePerformances[i + 1] + ->getFileParameters() + .ResourcePressurePerIter.size() - + 1) + ResourcePressurePerIteration += ", "; + } + + JsonObjVectorElem["Resource pressure per iteration"] = + ResourcePressurePerIteration; + JsonObjVector.push_back(std::move(JsonObjVectorElem)); + } + + OrdinalNumberOfFile = "File: " + std::to_string(1); + JsonObjCreatedByVector[OrdinalNumberOfFile] = std::move(JsonObjVector[0]); + for (unsigned long i = 0; i < InputFilenames.size(); i++) { + OrdinalNumberOfFile = "File: " + std::to_string(i + 2); + JsonObjCreatedByVector[OrdinalNumberOfFile] = + std::move(JsonObjVector[i + 1]); + } + + TOF->os() << formatv("{0:2}", + json::Value(std::move(JsonObjCreatedByVector))) + << "\n"; + } + + TOF->keep(); + return 0; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + // Initialize targets and assembly parsers. + InitializeAllTargetInfos(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllTargetMCAs(); + + // Enable printing of available targets when flag --version is specified. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); + + cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); + + // Parse flags and initialize target options. + cl::ParseCommandLineOptions(argc, argv, + "llvm machine code performance analyzer.\n"); + + // Now initialize the output file. + auto OF = getOutputStream(); + if (std::error_code EC = OF.getError()) { + WithColor::error() << EC.message() << '\n'; + return 1; + } + TOF = std::move(*OF); + + MachineCodePerformances = + SmallVector>(); + + if ((InputFilenames.size() + 1 < 2 && PrintDifference) || + (InputFilenames.size() + 1 > 1 && !PrintDifference)) { + errs() << " Wrong number of positional arguments specified!\n" + << " See: " << argv[0] << " --help\n"; + return 1; + } + + if (PrintDifference) { + unsigned CalledFunctionHasErrors; + + CalledFunctionHasErrors = oneCycle(argv, InputFilename); + if (CalledFunctionHasErrors != 0) + return 1; + + for (unsigned long i = 0; i < InputFilenames.size(); i++) { + CalledFunctionHasErrors = oneCycle(argv, InputFilenames[i]); + if (CalledFunctionHasErrors != 0) + return 1; + } + + CalledFunctionHasErrors = printCompareResults(); + if (CalledFunctionHasErrors != 0) + return 1; + + } else { + if (oneCycle(argv, InputFilename) != 0) + return 1; + } TOF->keep(); return 0;