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