Index: clang-tools-extra/clangd/CMakeLists.txt =================================================================== --- clang-tools-extra/clangd/CMakeLists.txt +++ clang-tools-extra/clangd/CMakeLists.txt @@ -71,3 +71,7 @@ endif() add_subdirectory(tool) add_subdirectory(global-symbol-builder) + +if (LLVM_INCLUDE_BENCHMARKS) + add_subdirectory(benchmarks) +endif() Index: clang-tools-extra/clangd/benchmarks/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tools-extra/clangd/benchmarks/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../) + +add_benchmark(IndexBenchmark IndexBenchmark.cpp) + +target_link_libraries(IndexBenchmark + PRIVATE + clangDaemon + LLVMSupport + ) Index: clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp @@ -0,0 +1,148 @@ +//===--- DexBenchmark.cpp - DexIndex benchmarks -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../index/SymbolYAML.h" +#include "../index/dex/DexIndex.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include "benchmark/benchmark.h" +#include +#include +#include + +// FIXME(kbobyrev): Get rid of global variables and put them into +// benchmark::State? +std::unique_ptr Dex; +std::unique_ptr Mem; + +std::vector Requests; + +std::vector RealRequests; + +std::string IndexFilename; +std::string LogFilename; + +void readLogFile() { + llvm::Regex RequestMatcher("fuzzyFind\\(\"([a-zA-Z]*)\", scopes=\\[(.*)\\]"); + llvm::SmallVector Matches; + std::ifstream InputStream(LogFilename); + std::string Log((std::istreambuf_iterator(InputStream)), + std::istreambuf_iterator()); + llvm::StringRef S = Log; + llvm::SmallVector Strings; + S.split(Strings, '\n'); + + clang::clangd::FuzzyFindRequest R; + R.MaxCandidateCount = 100; + + llvm::SmallVector CSS; + + for (auto Line : Strings) { + if (RequestMatcher.match(Line, &Matches)) { + R.Query = Matches[1]; + CSS.clear(); + Line.split(CSS, ','); + R.Scopes.clear(); + for (auto C : CSS) { + R.Scopes.push_back(C); + } + RealRequests.push_back(R); + } + } + llvm::outs() << "Generated " << RealRequests.size() << " requests.\n"; +} + +void initializeEnvironment(char *argv[]) { + IndexFilename = argv[1]; + LogFilename = argv[2]; + + readLogFile(); + + Dex = clang::clangd::buildStaticIndex(IndexFilename, true); + Mem = clang::clangd::buildStaticIndex(IndexFilename, false); + + // FXIME(kbobyrev): Add more requests. + clang::clangd::FuzzyFindRequest R; + R.MaxCandidateCount = 100; + Requests.push_back(R); + R.Scopes = {"::"}; + Requests.push_back(R); + R.Scopes = {"::", "llvm::", "clang::", "clangd::"}; + Requests.push_back(R); + R.Scopes = {"::", "clang::", "llvm::", "std::"}; + R.Query = "TUDec"; + Requests.push_back(R); + R.Query = "non-existent symbol"; + Requests.push_back(R); +} + +namespace clang { +namespace clangd { +namespace dex { + +static void BuildMem(benchmark::State &State) { + for (auto _ : State) + Mem = clang::clangd::buildStaticIndex(IndexFilename, false); +} +BENCHMARK(BuildMem); + +static void MemAdHocQueries(benchmark::State &State) { + for (auto _ : State) + for (const auto Req : Requests) + Mem->fuzzyFind(Req, [](const Symbol &S) {}); +} +BENCHMARK(MemAdHocQueries); + +static void MemRealQ(benchmark::State &State) { + for (auto _ : State) + for (const auto Req : RealRequests) + Mem->fuzzyFind(Req, [](const Symbol &S) {}); +} +BENCHMARK(MemRealQ); + +static void BuildDex(benchmark::State &State) { + for (auto _ : State) + Dex = clang::clangd::buildStaticIndex(IndexFilename, true); +} +BENCHMARK(BuildDex); + +static void DexAdHocQueries(benchmark::State &State) { + for (auto _ : State) + for (const auto Req : Requests) + Dex->fuzzyFind(Req, [](const Symbol &S) {}); +} +BENCHMARK(DexAdHocQueries); + +static void DexRealQ(benchmark::State &State) { + for (auto _ : State) + for (const auto Req : RealRequests) + Dex->fuzzyFind(Req, [](const Symbol &S) {}); +} +BENCHMARK(DexRealQ); + +} // namespace dex +} // namespace clangd +} // namespace clang + +// FIXME(kbobyrev): Extract fuzzyFind requests from the user logs (-log=verbose) +// and add a separate benchmark target for a bunch of user-provided fuzzy find +// requests. +int main(int argc, char *argv[]) { + if (argc < 3) { + llvm::errs() << "Usage: " << argv[0] + << " global-symbol-index.yaml fuzzy-find-requests.log BENCHMARK_OPTIONS...\n"; + return -1; + } + initializeEnvironment(argv); + // Trim first two arguments of the benchmark invocation. + argv += 2; + argc -= 2; + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); +} Index: clang-tools-extra/clangd/index/SymbolYAML.h =================================================================== --- clang-tools-extra/clangd/index/SymbolYAML.h +++ clang-tools-extra/clangd/index/SymbolYAML.h @@ -42,6 +42,12 @@ // The YAML result is safe to concatenate if you have multiple symbol slabs. void SymbolsToYAML(const SymbolSlab &Symbols, llvm::raw_ostream &OS); +// Build an in-memory static index for global symbols from a YAML-format file. +// The size of global symbols should be relatively small, so that all symbols +// can be managed in memory. +std::unique_ptr buildStaticIndex(llvm::StringRef YamlSymbolFile, + bool UseDex); + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/index/SymbolYAML.cpp =================================================================== --- clang-tools-extra/clangd/index/SymbolYAML.cpp +++ clang-tools-extra/clangd/index/SymbolYAML.cpp @@ -9,6 +9,7 @@ #include "SymbolYAML.h" #include "Index.h" +#include "dex/DexIndex.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Errc.h" #include "llvm/Support/MemoryBuffer.h" @@ -203,5 +204,21 @@ return OS.str(); } +std::unique_ptr buildStaticIndex(llvm::StringRef YamlSymbolFile, + bool UseDex) { + auto Buffer = llvm::MemoryBuffer::getFile(YamlSymbolFile); + if (!Buffer) { + llvm::errs() << "Can't open " << YamlSymbolFile << "\n"; + return nullptr; + } + auto Slab = symbolsFromYAML(Buffer.get()->getBuffer()); + SymbolSlab::Builder SymsBuilder; + for (auto Sym : Slab) + SymsBuilder.insert(Sym); + + return UseDex ? dex::DexIndex::build(std::move(SymsBuilder).build()) + : MemIndex::build(std::move(SymsBuilder).build()); +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/tool/ClangdMain.cpp =================================================================== --- clang-tools-extra/clangd/tool/ClangdMain.cpp +++ clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -38,24 +38,6 @@ enum class PCHStorageFlag { Disk, Memory }; -// Build an in-memory static index for global symbols from a YAML-format file. -// The size of global symbols should be relatively small, so that all symbols -// can be managed in memory. -std::unique_ptr buildStaticIndex(llvm::StringRef YamlSymbolFile) { - auto Buffer = llvm::MemoryBuffer::getFile(YamlSymbolFile); - if (!Buffer) { - llvm::errs() << "Can't open " << YamlSymbolFile << "\n"; - return nullptr; - } - auto Slab = symbolsFromYAML(Buffer.get()->getBuffer()); - SymbolSlab::Builder SymsBuilder; - for (auto Sym : Slab) - SymsBuilder.insert(Sym); - - return UseDex ? dex::DexIndex::build(std::move(SymsBuilder).build()) - : MemIndex::build(std::move(SymsBuilder).build()); -} - } // namespace static llvm::cl::opt CompileCommandsDir( @@ -294,7 +276,7 @@ Opts.BuildDynamicSymbolIndex = EnableIndex; std::unique_ptr StaticIdx; if (EnableIndex && !YamlSymbolFile.empty()) { - StaticIdx = buildStaticIndex(YamlSymbolFile); + StaticIdx = buildStaticIndex(YamlSymbolFile, UseDex); Opts.StaticIndex = StaticIdx.get(); } Opts.AsyncThreadsCount = WorkerThreadsCount;