//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "llvm/IR/RuntimeLibcalls.h" #include "benchmark/benchmark.h" #include "llvm/IR/DataLayout.h" #include "llvm/Support/Error.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/TargetParser/Triple.h" #include #include using namespace llvm; static constexpr unsigned MaxFuncNameSize = 53; static std::vector getLibcallNameStringRefs() { std::vector Names(RTLIB::NumLibcallImpls); // Keep the strlens on the StringRef construction out of the benchmark loop. for (RTLIB::LibcallImpl LC : RTLIB::libcall_impls()) Names[LC] = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(LC); return Names; } static std::vector getRandomFuncNames() { std::mt19937_64 Rng; std::uniform_int_distribution<> StringLengthDistribution(1, MaxFuncNameSize); std::uniform_int_distribution<> CharDistribution(1, 255); int NumTestFuncs = 1 << 10; std::vector TestFuncNames(NumTestFuncs); for (std::string &TestFuncName : TestFuncNames) { for (int I = 0, E = StringLengthDistribution(Rng); I != E; ++I) TestFuncName += static_cast(CharDistribution(Rng)); } return TestFuncNames; } #ifdef SYMBOL_TEST_DATA_FILE static std::vector readSymbolsFromFile(StringRef InputFile) { auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile, /*IsText=*/true); if (!BufOrError) { reportFatalUsageError("failed to open \'" + Twine(InputFile) + "\': " + BufOrError.getError().message()); } // Hackily figure out if there's a prefix on the symbol names - llvm-nm // appears to not have a flag to skip this. llvm::Triple HostTriple(LLVM_HOST_TRIPLE); std::string DummyDatalayout = "e"; DummyDatalayout += DataLayout::getManglingComponent(HostTriple); DataLayout DL(DummyDatalayout); char GlobalPrefix = DL.getGlobalPrefix(); std::vector Lines; for (line_iterator LineIt(**BufOrError, /*SkipBlanks=*/true); !LineIt.is_at_eof(); ++LineIt) { StringRef SymbolName = *LineIt; SymbolName.consume_front(StringRef(&GlobalPrefix, 1)); Lines.push_back(SymbolName.str()); } return Lines; } #endif static void BM_LookupRuntimeLibcallByNameKnownCalls(benchmark::State &State) { std::vector Names = getLibcallNameStringRefs(); for (auto _ : State) { for (StringRef Name : Names) { benchmark::DoNotOptimize( RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(Name).empty()); } } } static void BM_LookupRuntimeLibcallByNameRandomCalls(benchmark::State &State) { std::vector TestFuncNames = getRandomFuncNames(); for (auto _ : State) { for (const std::string &Name : TestFuncNames) { benchmark::DoNotOptimize( RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(StringRef(Name)) .empty()); } } } #ifdef SYMBOL_TEST_DATA_FILE // This isn't fully representative, it doesn't include any anonymous functions. // nm -n --no-demangle --format=just-symbols sample-binary > sample.txt static void BM_LookupRuntimeLibcallByNameSampleData(benchmark::State &State) { std::vector TestFuncNames = readSymbolsFromFile(SYMBOL_TEST_DATA_FILE); for (auto _ : State) { for (const std::string &Name : TestFuncNames) { benchmark::DoNotOptimize( RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(StringRef(Name)) .empty()); } } } #endif BENCHMARK(BM_LookupRuntimeLibcallByNameKnownCalls); BENCHMARK(BM_LookupRuntimeLibcallByNameRandomCalls); #ifdef SYMBOL_TEST_DATA_FILE BENCHMARK(BM_LookupRuntimeLibcallByNameSampleData); #endif BENCHMARK_MAIN();