1 //===--- IndexBenchmark.cpp - Clangd index benchmarks -----------*- 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 "../index/Serialization.h" 10 #include "../index/dex/Dex.h" 11 #include "benchmark/benchmark.h" 12 #include "llvm/ADT/SmallVector.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/Path.h" 15 #include "llvm/Support/Regex.h" 16 #include <fstream> 17 #include <streambuf> 18 #include <string> 19 20 const char *IndexFilename; 21 const char *RequestsFilename; 22 23 namespace clang { 24 namespace clangd { 25 namespace { 26 27 std::unique_ptr<SymbolIndex> buildMem() { 28 return loadIndex(IndexFilename, /*UseDex=*/false); 29 } 30 31 std::unique_ptr<SymbolIndex> buildDex() { 32 return loadIndex(IndexFilename, /*UseDex=*/true); 33 } 34 35 // Reads JSON array of serialized FuzzyFindRequest's from user-provided file. 36 std::vector<FuzzyFindRequest> extractQueriesFromLogs() { 37 std::ifstream InputStream(RequestsFilename); 38 std::string Log((std::istreambuf_iterator<char>(InputStream)), 39 std::istreambuf_iterator<char>()); 40 41 std::vector<FuzzyFindRequest> Requests; 42 auto JSONArray = llvm::json::parse(Log); 43 44 // Panic if the provided file couldn't be parsed. 45 if (!JSONArray) { 46 llvm::errs() << "Error when parsing JSON requests file: " 47 << llvm::toString(JSONArray.takeError()); 48 exit(1); 49 } 50 if (!JSONArray->getAsArray()) { 51 llvm::errs() << "Error: top-level value is not a JSON array: " << Log 52 << '\n'; 53 exit(1); 54 } 55 56 for (const auto &Item : *JSONArray->getAsArray()) { 57 FuzzyFindRequest Request; 58 // Panic if the provided file couldn't be parsed. 59 if (!fromJSON(Item, Request)) { 60 llvm::errs() << "Error when deserializing request: " << Item << '\n'; 61 exit(1); 62 } 63 Requests.push_back(Request); 64 } 65 return Requests; 66 } 67 68 static void MemQueries(benchmark::State &State) { 69 const auto Mem = buildMem(); 70 const auto Requests = extractQueriesFromLogs(); 71 for (auto _ : State) 72 for (const auto &Request : Requests) 73 Mem->fuzzyFind(Request, [](const Symbol &S) {}); 74 } 75 BENCHMARK(MemQueries); 76 77 static void DexQueries(benchmark::State &State) { 78 const auto Dex = buildDex(); 79 const auto Requests = extractQueriesFromLogs(); 80 for (auto _ : State) 81 for (const auto &Request : Requests) 82 Dex->fuzzyFind(Request, [](const Symbol &S) {}); 83 } 84 BENCHMARK(DexQueries); 85 86 } // namespace 87 } // namespace clangd 88 } // namespace clang 89 90 // FIXME(kbobyrev): Add index building time benchmarks. 91 // FIXME(kbobyrev): Add memory consumption "benchmarks" by manually measuring 92 // in-memory index size and reporting it as time. 93 // FIXME(kbobyrev): Create a logger wrapper to suppress debugging info printer. 94 int main(int argc, char *argv[]) { 95 if (argc < 3) { 96 llvm::errs() << "Usage: " << argv[0] 97 << " global-symbol-index.yaml requests.json " 98 "BENCHMARK_OPTIONS...\n"; 99 return -1; 100 } 101 IndexFilename = argv[1]; 102 RequestsFilename = argv[2]; 103 // Trim first two arguments of the benchmark invocation and pretend no 104 // arguments were passed in the first place. 105 argv[2] = argv[0]; 106 argv += 2; 107 argc -= 2; 108 ::benchmark::Initialize(&argc, argv); 109 ::benchmark::RunSpecifiedBenchmarks(); 110 } 111