Index: clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp =================================================================== --- clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp +++ clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp @@ -12,6 +12,7 @@ #include "benchmark/benchmark.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include @@ -33,6 +34,25 @@ return loadIndex(IndexFilename, {}, true); } +SymbolSlab loadSlab() { + auto Buffer = llvm::MemoryBuffer::getFile(IndexFilename); + if (!Buffer) { + llvm::errs() << "Can't open " << IndexFilename << '\n'; + exit(1); + } + + auto Slab = readIndexFile((*Buffer)->getBuffer()); + if (!Slab) { + llvm::errs() << llvm::toString(Slab.takeError()) << '\n'; + exit(1); + } else if (!Slab->Symbols) { + llvm::errs() << "Couldn't read symbol slab from the index file: " + << IndexFilename << '\n'; + exit(1); + } + return std::move(*Slab->Symbols); +} + // Reads JSON array of serialized FuzzyFindRequest's from user-provided file. std::vector extractQueriesFromLogs() { std::ifstream InputStream(RequestsFilename); @@ -73,7 +93,7 @@ for (const auto &Request : Requests) Mem->fuzzyFind(Request, [](const Symbol &S) {}); } -BENCHMARK(MemQueries); +BENCHMARK(MemQueries)->Unit(benchmark::kMillisecond); static void DexQueries(benchmark::State &State) { const auto Dex = buildDex(); @@ -82,15 +102,72 @@ for (const auto &Request : Requests) Dex->fuzzyFind(Request, [](const Symbol &S) {}); } -BENCHMARK(DexQueries); +BENCHMARK(DexQueries)->Unit(benchmark::kMillisecond); + +// This is not a *real* benchmark: it shows size of built MemIndex (in bytes). +// Same for the next "benchmark". +// FIXME(kbobyrev): Track memory usage caused by different index parts: +// SymbolSlab and RefSlabs, InverseIndex, PostingLists of different types for +// Dex, etc. +static void MemSize(benchmark::State &State) { + const auto Mem = buildMem(); + for (auto _ : State) + // Divide size of Mem by 1000 so that it will be correctly displayed in the + // benchmark report (possible options for time units are ms, ns and us). + State.SetIterationTime(/*double Seconds=*/Mem->estimateMemoryUsage() / + 1000.0); + State.SetLabel("This tracks in-memory size of MemIndex (SymbolSlab + Index " + "overhead) in bytes"); +} +BENCHMARK(MemSize) + ->UseManualTime() + ->Unit(benchmark::kMillisecond) + ->Iterations(1); + +static void DexSize(benchmark::State &State) { + const auto Dex = buildDex(); + + for (auto _ : State) + State.SetIterationTime(Dex->estimateMemoryUsage() / 1000.0); + State.SetLabel("This tracks in-memory size of Dex (SymbolSlab + Index " + "overhead) in bytes"); +} +BENCHMARK(DexSize) + ->UseManualTime() + ->Unit(benchmark::kMillisecond) + ->Iterations(1); + +static void DexOverhead(benchmark::State &State) { + const auto Slab = loadSlab(); + const auto Dex = buildDex(); + for (auto _ : State) + State.SetIterationTime((Dex->estimateMemoryUsage() - Slab.bytes()) / + 1000.0); + State.SetLabel("This tracks in-memory size of Dex Index overhead (and " + "excludes underlying SymbolSlab size) in bytes"); +} +BENCHMARK(DexOverhead) + ->UseManualTime() + ->Unit(benchmark::kMillisecond) + ->Iterations(1); + +static void SymbolSlabLoading(benchmark::State &State) { + for (auto _ : State) + benchmark::DoNotOptimize(loadSlab()); +} +BENCHMARK(SymbolSlabLoading)->Unit(benchmark::kMillisecond); + +static void DexBuild(benchmark::State &State) { + auto Slab = loadSlab(); + for (auto _ : State) + benchmark::DoNotOptimize(dex::Dex::build(std::move(Slab), {})); +} +BENCHMARK(DexBuild)->Unit(benchmark::kMillisecond); } // 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) {