244 lines · cpp
1//===- SandboxIRBench.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// These tests measure the performance of some core SandboxIR functions and10// compare them against LLVM IR.11//12//===----------------------------------------------------------------------===//13 14#include "benchmark/benchmark.h"15#include "llvm/AsmParser/Parser.h"16#include "llvm/IR/BasicBlock.h"17#include "llvm/IR/DataLayout.h"18#include "llvm/IR/Function.h"19#include "llvm/IR/Instruction.h"20#include "llvm/IR/Module.h"21#include "llvm/SandboxIR/Function.h"22#include "llvm/SandboxIR/Instruction.h"23#include "llvm/SandboxIR/Module.h"24#include "llvm/Support/SourceMgr.h"25#include <memory>26#include <sstream>27 28using namespace llvm;29 30static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {31 SMDiagnostic Err;32 std::unique_ptr<Module> M = parseAssemblyString(IR, Err, C);33 if (!M)34 Err.print("SandboxIRBench", errs());35 return M;36}37 38enum class IR {39 LLVM, ///> LLVM IR40 SBoxNoTracking, ///> Sandbox IR with tracking disabled41 SBoxTracking, ///> Sandbox IR with tracking enabled42};43// Traits to get llvm::BasicBlock/sandboxir::BasicBlock from IR::LLVM/IR::SBox.44template <IR IRTy> struct TypeSelect {};45template <> struct TypeSelect<IR::LLVM> {46 using BasicBlock = llvm::BasicBlock;47};48template <> struct TypeSelect<IR::SBoxNoTracking> {49 using BasicBlock = sandboxir::BasicBlock;50};51template <> struct TypeSelect<IR::SBoxTracking> {52 using BasicBlock = sandboxir::BasicBlock;53};54 55template <IR IRTy>56static typename TypeSelect<IRTy>::BasicBlock *57genIR(std::unique_ptr<llvm::Module> &LLVMM, LLVMContext &LLVMCtx,58 sandboxir::Context &Ctx,59 std::function<std::string(unsigned)> GenerateIRStr,60 unsigned NumInstrs = 0u) {61 std::string IRStr = GenerateIRStr(NumInstrs);62 LLVMM = parseIR(LLVMCtx, IRStr.c_str());63 llvm::Function *LLVMF = &*LLVMM->getFunction("foo");64 llvm::BasicBlock *LLVMBB = &*LLVMF->begin();65 66 sandboxir::Function *F = Ctx.createFunction(LLVMF);67 sandboxir::BasicBlock *BB = &*F->begin();68 // Start tracking if we are testing with tracking enabled.69 if constexpr (IRTy == IR::SBoxTracking)70 Ctx.save();71 72 if constexpr (IRTy == IR::LLVM)73 return LLVMBB;74 else75 return BB;76}77 78template <IR IRTy> static void finalize(sandboxir::Context &Ctx) {79 // Accept changes if we are tracking.80 if constexpr (IRTy == IR::SBoxTracking)81 Ctx.accept();82}83 84static std::string generateBBWalkIR(unsigned Size) {85 std::stringstream SS;86 SS << "define void @foo(i32 %v1, i32 %v2) {\n";87 for (auto Cnt : seq<unsigned>(0, Size))88 SS << " %add" << Cnt << " = add i32 %v1, %v2\n";89 SS << "ret void";90 SS << "}";91 return SS.str();92}93 94template <IR IRTy> static void SBoxIRCreation(benchmark::State &State) {95 static_assert(IRTy != IR::LLVM, "Expected SBoxTracking or SBoxNoTracking");96 LLVMContext LLVMCtx;97 unsigned NumInstrs = State.range(0);98 std::unique_ptr<llvm::Module> LLVMM;99 std::string IRStr = generateBBWalkIR(NumInstrs);100 LLVMM = parseIR(LLVMCtx, IRStr.c_str());101 llvm::Function *LLVMF = &*LLVMM->getFunction("foo");102 103 for (auto _ : State) {104 State.PauseTiming();105 sandboxir::Context Ctx(LLVMCtx);106 if constexpr (IRTy == IR::SBoxTracking)107 Ctx.save();108 State.ResumeTiming();109 110 sandboxir::Function *F = Ctx.createFunction(LLVMF);111 benchmark::DoNotOptimize(F);112 State.PauseTiming();113 if constexpr (IRTy == IR::SBoxTracking)114 Ctx.accept();115 State.ResumeTiming();116 }117}118 119template <IR IRTy> static void BBWalk(benchmark::State &State) {120 LLVMContext LLVMCtx;121 sandboxir::Context Ctx(LLVMCtx);122 unsigned NumInstrs = State.range(0);123 std::unique_ptr<llvm::Module> LLVMM;124 auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateBBWalkIR, NumInstrs);125 for (auto _ : State) {126 // Walk LLVM Instructions.127 for (auto &I : *BB)128 benchmark::DoNotOptimize(I);129 }130}131 132static std::string generateGetTypeIR(unsigned Size) {133 return R"IR(134define void @foo(i32 %v1, i32 %v2) {135 %add = add i32 %v1, %v2136 ret void137}138)IR";139}140 141template <IR IRTy> static void GetType(benchmark::State &State) {142 LLVMContext LLVMCtx;143 sandboxir::Context Ctx(LLVMCtx);144 std::unique_ptr<llvm::Module> LLVMM;145 auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateGetTypeIR);146 auto *I = &*BB->begin();147 for (auto _ : State)148 benchmark::DoNotOptimize(I->getType());149}150 151static std::string generateRAUWIR(unsigned Size) {152 std::stringstream SS;153 SS << "define void @foo(i32 %v1, i32 %v2) {\n";154 SS << " %def1 = add i32 %v1, %v2\n";155 SS << " %def2 = add i32 %v1, %v2\n";156 for (auto Cnt : seq<unsigned>(0, Size))157 SS << " %add" << Cnt << " = add i32 %def1, %def1\n";158 SS << "ret void";159 SS << "}";160 return SS.str();161}162 163template <IR IRTy> static void RAUW(benchmark::State &State) {164 LLVMContext LLVMCtx;165 sandboxir::Context Ctx(LLVMCtx);166 std::unique_ptr<llvm::Module> LLVMM;167 unsigned NumInstrs = State.range(0);168 auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateRAUWIR, NumInstrs);169 auto It = BB->begin();170 auto *Def1 = &*It++;171 auto *Def2 = &*It++;172 for (auto _ : State) {173 Def1->replaceAllUsesWith(Def2);174 Def2->replaceAllUsesWith(Def1);175 }176 finalize<IRTy>(Ctx);177}178 179static std::string generateRUOWIR(unsigned NumOperands) {180 std::stringstream SS;181 auto GenOps = [&SS, NumOperands]() {182 for (auto Cnt : seq<unsigned>(0, NumOperands)) {183 SS << "i8 %arg" << Cnt;184 bool IsLast = Cnt + 1 == NumOperands;185 if (!IsLast)186 SS << ", ";187 }188 };189 190 SS << "define void @foo(";191 GenOps();192 SS << ") {\n";193 194 SS << " call void @foo(";195 GenOps();196 SS << ")\n";197 SS << "ret void";198 SS << "}";199 return SS.str();200}201 202template <IR IRTy> static void RUOW(benchmark::State &State) {203 LLVMContext LLVMCtx;204 sandboxir::Context Ctx(LLVMCtx);205 std::unique_ptr<llvm::Module> LLVMM;206 unsigned NumOperands = State.range(0);207 auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateRUOWIR, NumOperands);208 209 auto It = BB->begin();210 auto *F = BB->getParent();211 auto *Arg0 = F->getArg(0);212 auto *Arg1 = F->getArg(1);213 auto *Call = &*It++;214 for (auto _ : State)215 Call->replaceUsesOfWith(Arg0, Arg1);216 finalize<IRTy>(Ctx);217}218 219// Measure the time it takes to create Sandbox IR without/with tracking.220BENCHMARK(SBoxIRCreation<IR::SBoxNoTracking>)221 ->Args({10})222 ->Args({100})223 ->Args({1000});224BENCHMARK(SBoxIRCreation<IR::SBoxTracking>)225 ->Args({10})226 ->Args({100})227 ->Args({1000});228 229BENCHMARK(GetType<IR::LLVM>);230BENCHMARK(GetType<IR::SBoxNoTracking>);231 232BENCHMARK(BBWalk<IR::LLVM>)->Args({1024});233BENCHMARK(BBWalk<IR::SBoxTracking>)->Args({1024});234 235BENCHMARK(RAUW<IR::LLVM>)->Args({512});236BENCHMARK(RAUW<IR::SBoxNoTracking>)->Args({512});237BENCHMARK(RAUW<IR::SBoxTracking>)->Args({512});238 239BENCHMARK(RUOW<IR::LLVM>)->Args({4096});240BENCHMARK(RUOW<IR::SBoxNoTracking>)->Args({4096});241BENCHMARK(RUOW<IR::SBoxTracking>)->Args({4096});242 243BENCHMARK_MAIN();244