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