1 //===-- BenchmarkResultTest.cpp ---------------------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "BenchmarkResult.h" 10 #include "X86InstrInfo.h" 11 #include "llvm/ADT/SmallString.h" 12 #include "llvm/MC/TargetRegistry.h" 13 #include "llvm/Support/Error.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/Path.h" 16 #include "llvm/Support/TargetSelect.h" 17 #include "llvm/Support/YAMLTraits.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include "gmock/gmock.h" 20 #include "gtest/gtest.h" 21 22 using ::testing::AllOf; 23 using ::testing::ElementsAre; 24 using ::testing::Eq; 25 using ::testing::Field; 26 using ::testing::get; 27 using ::testing::Pointwise; 28 using ::testing::Property; 29 30 namespace llvm { 31 namespace exegesis { 32 33 void InitializeX86ExegesisTarget(); 34 35 static std::string Dump(const MCInst &McInst) { 36 std::string Buffer; 37 raw_string_ostream OS(Buffer); 38 McInst.print(OS); 39 return Buffer; 40 } 41 42 MATCHER(EqMCInst, "") { 43 const std::string Lhs = Dump(get<0>(arg)); 44 const std::string Rhs = Dump(get<1>(arg)); 45 if (Lhs != Rhs) { 46 *result_listener << Lhs << " <=> " << Rhs; 47 return false; 48 } 49 return true; 50 } 51 52 namespace { 53 54 TEST(BenchmarkResultTest, WriteToAndReadFromDisk) { 55 LLVMInitializeX86TargetInfo(); 56 LLVMInitializeX86Target(); 57 LLVMInitializeX86TargetMC(); 58 InitializeX86ExegesisTarget(); 59 60 // Read benchmarks. 61 const LLVMState State = 62 cantFail(LLVMState::Create("x86_64-unknown-linux", "haswell")); 63 64 ExitOnError ExitOnErr; 65 66 InstructionBenchmark ToDisk; 67 68 ToDisk.Key.Instructions.push_back(MCInstBuilder(X86::XOR32rr) 69 .addReg(X86::AL) 70 .addReg(X86::AH) 71 .addImm(123) 72 .addDFPImm(bit_cast<uint64_t>(0.5))); 73 ToDisk.Key.Config = "config"; 74 ToDisk.Key.RegisterInitialValues = { 75 RegisterValue{X86::AL, APInt(8, "-1", 10)}, 76 RegisterValue{X86::AH, APInt(8, "123", 10)}}; 77 ToDisk.Mode = InstructionBenchmark::Latency; 78 ToDisk.CpuName = "cpu_name"; 79 ToDisk.LLVMTriple = "llvm_triple"; 80 ToDisk.NumRepetitions = 1; 81 ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, 1}); 82 ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2, 2}); 83 ToDisk.Error = "error"; 84 ToDisk.Info = "info"; 85 86 SmallString<64> Filename; 87 std::error_code EC; 88 EC = sys::fs::createUniqueDirectory("BenchmarkResultTestDir", Filename); 89 ASSERT_FALSE(EC); 90 sys::path::append(Filename, "data.yaml"); 91 errs() << Filename << "-------\n"; 92 { 93 int ResultFD = 0; 94 // Create output file or open existing file and truncate it, once. 95 ExitOnErr(errorCodeToError(openFileForWrite(Filename, ResultFD, 96 sys::fs::CD_CreateAlways, 97 sys::fs::OF_TextWithCRLF))); 98 raw_fd_ostream FileOstr(ResultFD, true /*shouldClose*/); 99 100 ExitOnErr(ToDisk.writeYamlTo(State, FileOstr)); 101 } 102 103 const std::unique_ptr<MemoryBuffer> Buffer = 104 std::move(*MemoryBuffer::getFile(Filename)); 105 106 { 107 // Read Triples/Cpu only. 108 const auto TriplesAndCpus = 109 ExitOnErr(InstructionBenchmark::readTriplesAndCpusFromYamls(*Buffer)); 110 111 ASSERT_THAT(TriplesAndCpus, 112 testing::ElementsAre( 113 AllOf(Field(&InstructionBenchmark::TripleAndCpu::LLVMTriple, 114 Eq("llvm_triple")), 115 Field(&InstructionBenchmark::TripleAndCpu::CpuName, 116 Eq("cpu_name"))))); 117 } 118 { 119 // One-element version. 120 const auto FromDisk = 121 ExitOnErr(InstructionBenchmark::readYaml(State, *Buffer)); 122 123 EXPECT_THAT(FromDisk.Key.Instructions, 124 Pointwise(EqMCInst(), ToDisk.Key.Instructions)); 125 EXPECT_EQ(FromDisk.Key.Config, ToDisk.Key.Config); 126 EXPECT_EQ(FromDisk.Mode, ToDisk.Mode); 127 EXPECT_EQ(FromDisk.CpuName, ToDisk.CpuName); 128 EXPECT_EQ(FromDisk.LLVMTriple, ToDisk.LLVMTriple); 129 EXPECT_EQ(FromDisk.NumRepetitions, ToDisk.NumRepetitions); 130 EXPECT_THAT(FromDisk.Measurements, ToDisk.Measurements); 131 EXPECT_THAT(FromDisk.Error, ToDisk.Error); 132 EXPECT_EQ(FromDisk.Info, ToDisk.Info); 133 } 134 { 135 // Vector version. 136 const auto FromDiskVector = 137 ExitOnErr(InstructionBenchmark::readYamls(State, *Buffer)); 138 ASSERT_EQ(FromDiskVector.size(), size_t{1}); 139 const auto &FromDisk = FromDiskVector[0]; 140 EXPECT_THAT(FromDisk.Key.Instructions, 141 Pointwise(EqMCInst(), ToDisk.Key.Instructions)); 142 EXPECT_EQ(FromDisk.Key.Config, ToDisk.Key.Config); 143 EXPECT_EQ(FromDisk.Mode, ToDisk.Mode); 144 EXPECT_EQ(FromDisk.CpuName, ToDisk.CpuName); 145 EXPECT_EQ(FromDisk.LLVMTriple, ToDisk.LLVMTriple); 146 EXPECT_EQ(FromDisk.NumRepetitions, ToDisk.NumRepetitions); 147 EXPECT_THAT(FromDisk.Measurements, ToDisk.Measurements); 148 EXPECT_THAT(FromDisk.Error, ToDisk.Error); 149 EXPECT_EQ(FromDisk.Info, ToDisk.Info); 150 } 151 } 152 153 TEST(BenchmarkResultTest, PerInstructionStats) { 154 PerInstructionStats Stats; 155 Stats.push(BenchmarkMeasure{"a", 0.5, 0.0}); 156 Stats.push(BenchmarkMeasure{"a", 1.5, 0.0}); 157 Stats.push(BenchmarkMeasure{"a", -1.0, 0.0}); 158 Stats.push(BenchmarkMeasure{"a", 0.0, 0.0}); 159 EXPECT_EQ(Stats.min(), -1.0); 160 EXPECT_EQ(Stats.max(), 1.5); 161 EXPECT_EQ(Stats.avg(), 0.25); // (0.5+1.5-1.0+0.0) / 4 162 } 163 } // namespace 164 } // namespace exegesis 165 } // namespace llvm 166