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