Index: clang-tools-extra/clangd/CMakeLists.txt =================================================================== --- clang-tools-extra/clangd/CMakeLists.txt +++ clang-tools-extra/clangd/CMakeLists.txt @@ -75,3 +75,7 @@ add_subdirectory(tool) add_subdirectory(global-symbol-builder) add_subdirectory(index/dex/dexp) + +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,114 @@ +//===--- IndexBenchmark.cpp - Clangd index 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/Dex.h" +#include "benchmark/benchmark.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" +#include +#include +#include + +const char *IndexFilename; +const char *LogFilename; + +namespace clang { +namespace clangd { +namespace { + +std::unique_ptr buildMem() { + return clang::clangd::loadIndex(IndexFilename, {}, false); +} + +std::unique_ptr buildDex() { + return clang::clangd::loadIndex(IndexFilename, {}, true); +} + +// This function processes user-provided Log file with fuzzy find requests in +// the following format: +// +// fuzzyFind("UnqualifiedName", scopes=["clang::", "clang::clangd::"]) +// +// It constructs vector of FuzzyFindRequests which is later used for the +// benchmarks. +std::vector extractQueriesFromLogs() { + 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 Temporary(Log); + llvm::SmallVector Strings; + Temporary.split(Strings, '\n'); + + clang::clangd::FuzzyFindRequest R; + R.MaxCandidateCount = 100; + + llvm::SmallVector CommaSeparatedValues; + + std::vector RealRequests; + for (auto Line : Strings) { + if (RequestMatcher.match(Line, &Matches)) { + R.Query = Matches[1]; + CommaSeparatedValues.clear(); + Line.split(CommaSeparatedValues, ','); + R.Scopes.clear(); + for (auto C : CommaSeparatedValues) { + R.Scopes.push_back(C); + } + RealRequests.push_back(R); + } + } + return RealRequests; +} + +static void MemQueries(benchmark::State &State) { + const auto Mem = buildMem(); + const auto Requests = extractQueriesFromLogs(); + for (auto _ : State) + for (const auto &Request : Requests) + Mem->fuzzyFind(Request, [](const Symbol &S) {}); +} +BENCHMARK(MemQueries); + +static void DexQueries(benchmark::State &State) { + const auto Dex = buildDex(); + const auto Requests = extractQueriesFromLogs(); + for (auto _ : State) + for (const auto &Request : Requests) + Dex->fuzzyFind(Request, [](const Symbol &S) {}); +} +BENCHMARK(DexQueries); + +} // namespace +} // namespace clangd +} // namespace clang + +// FIXME(kbobyrev): Add index building time benchmarks. +// FIXME(kbobyrev): Add memory consumption "benchmarks" by manually measuring +// in-memory index size and reporting it as time. +// FIXME(kbobyrev): Create a logger wrapper to suppress debugging info printer. +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; + } + IndexFilename = argv[1]; + LogFilename = argv[2]; + // Trim first two arguments of the benchmark invocation. + argv += 3; + argc -= 3; + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); +} Index: clang-tools-extra/test/clangd/Inputs/BenchmarkHeader.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clangd/Inputs/BenchmarkHeader.h @@ -0,0 +1,19 @@ +namespace clang { +namespace clangd { +namespace dex { +class Dex; +} // namespace dex +} // namespace clangd +} // namespace clang + +namespace llvm { +namespace sys { + +int getHostNumPhysicalCores(); + +} // namespace sys +} // namespace llvm + +namespace { +int Variable; +} // namespace Index: clang-tools-extra/test/clangd/Inputs/BenchmarkSource.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clangd/Inputs/BenchmarkSource.cpp @@ -0,0 +1 @@ +#include "BenchmarkHeader.h" Index: clang-tools-extra/test/clangd/Inputs/requests.log =================================================================== --- /dev/null +++ clang-tools-extra/test/clangd/Inputs/requests.log @@ -0,0 +1,5 @@ +V[09:08:34.301] Code complete: fuzzyFind("s", scopes=[llvm::]) +V[09:08:34.368] Code complete: fuzzyFind("sy", scopes=[llvm::]) +V[09:08:34.442] Code complete: fuzzyFind("sys", scopes=[llvm::]) +V[09:09:12.075] Code complete: fuzzyFind("Dex", scopes=[clang::clangd::, clang::, clang::clangd::dex::]) +V[09:09:12.075] Code complete: fuzzyFind("Variable", scopes=[]) Index: clang-tools-extra/test/clangd/index-tools.test =================================================================== --- /dev/null +++ clang-tools-extra/test/clangd/index-tools.test @@ -0,0 +1,2 @@ +# RUN: global-symbol-builder %p/Inputs/BenchmarkSource.cpp -- -I%p/Inputs > %t.index +# RUN: %clangd-benchmark-dir/IndexBenchmark %t.index %p/Inputs/requests.log --benchmark_min_time=0.01 Index: clang-tools-extra/test/lit.cfg =================================================================== --- clang-tools-extra/test/lit.cfg +++ clang-tools-extra/test/lit.cfg @@ -137,3 +137,9 @@ else: # exclude the clang-tidy test directory config.excludes.append('clang-tidy') + +clangd_benchmarks_dir = os.path.join(os.path.dirname(config.clang_tools_dir), + "tools", "clang", "tools", "extra", + "clangd", "benchmarks") +config.substitutions.append(('%clangd-benchmark-dir', + '%s' % (clangd_benchmarks_dir)))