This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Add building benchmark and memory consumption tracking
AbandonedPublic

Authored by kbobyrev on Sep 13 2018, 10:36 AM.

Details

Reviewers
None
Summary

Split build stage into loading SymbolSlab from file and actual index building stage to simplify benchmarking distinct parts of index builds.

As for the memory consumption "benchmark", while this looks like misuse of benchmark library, this can be still when experimenting with index compression techniques as discussed offline.

Also, switch to ms for benchmark measurements time units and fix incorrect logger message ( BackingMemorySize is not initialized to correct value when the logger is called, callers should be responsible for memory usage logging).

Diff Detail

Event Timeline

kbobyrev created this revision.Sep 13 2018, 10:36 AM
kbobyrev updated this revision to Diff 165437.Sep 14 2018, 1:03 AM
  • Start measuring time in ms
  • Add Tokens' Data size for more precise memory usage estimation (accounts for ~1MB of Static Index in LLVM)
kbobyrev updated this revision to Diff 165440.Sep 14 2018, 1:11 AM

Move vlog message to the outer build(...) function: otherwise BackingMemorySize is not set to the correct value and log reports index overhead (instead of the complete index + slab) size.

The benchmark change looks fine to me. But I'm not very familiar with the trick, so I'll let Sam (who proposed the idea as you mentioned), stamp the patch.

clang-tools-extra/clangd/index/dex/Dex.h
75 ↗(On Diff #165440)

It's a bit strange to log this in the constructor. And we only do the logging for one of the constructors. Maybe just have the user log the mem usage when they want?

kbobyrev updated this revision to Diff 165962.Sep 18 2018, 6:56 AM
kbobyrev marked an inline comment as done.

Rebase on top of master, move logging to symbol index build() caller side.

ioeric added inline comments.Sep 19 2018, 1:42 AM
clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
89

The hack might not be obvious for other people who run these benchmarks. Is it possible to print some extra message along with the result to explain the hack?

clang-tools-extra/clangd/index/dex/Dex.cpp
239 ↗(On Diff #165962)

Why do we need P.second.bytes() * sizeof(DocID)? Isn't P.second.bytes() already the memory size of the posting list?

kbobyrev added inline comments.Sep 20 2018, 1:23 AM
clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
89

Yes, that makes sense. I might try to use User-Defined Counters for that.

clang-tools-extra/clangd/index/dex/Dex.cpp
239 ↗(On Diff #165962)

Yes, the patch is out of sync. Will fix!

kbobyrev updated this revision to Diff 166240.Sep 20 2018, 2:07 AM
kbobyrev marked 4 inline comments as done.
kbobyrev updated this revision to Diff 166266.Sep 20 2018, 5:28 AM
kbobyrev retitled this revision from [clangd] Add a "benchmark" for tracking memory to [clangd] Add building benchmark and memory consumption tracking.
kbobyrev edited the summary of this revision. (Show Details)

Add symbol index building benchmarks, split loadIndex() into symbolsFromFile() and actual index build.

kbobyrev updated this revision to Diff 166269.Sep 20 2018, 5:29 AM

Add benchmark for SymbolSlab loading from file. This might be useful for RIFF/YAML symbol loader optimizations.

kbobyrev edited the summary of this revision. (Show Details)Sep 20 2018, 5:30 AM
kbobyrev updated this revision to Diff 166271.Sep 20 2018, 5:42 AM

Remove BuildMem benchmark, which collects data about MemIndex building time (which is essentially nothing and therefore not really interesting).

Also not sure about the trick:

  • Would be surprising to see the "ms" instead of "mbytes"
  • Time tends to vary between runs, so using Google Benchmark's capabilities to run multiple times and report aggregated times seems useful. Not so much for the memory usage: it's deterministic and running multiple times is just a waste of time.

I wonder if a separate (and trivial) C++ binary that would load the index and report the index size is any worse than the benchmark hack? What are the pros of the latter?

clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
91

Given the trick we use for display, how are we going to show two memory uses?

188

Since return 0 is implied for main in C++, there's no need to add one.
May add clarity though, so feel free to keep it!

clang-tools-extra/clangd/index/SymbolYAML.cpp
189 ↗(On Diff #166271)

Return llvm::Expected instead of Optional and create errors with the specified text instead.
This is a slightly better option for the library code (callers can report errors in various ways, e.g. one can imagine reporting it in the LSP instead of stderr)

200 ↗(On Diff #166271)

Same here: just propagate the error to the caller.

clang-tools-extra/clangd/index/dex/Dex.cpp
239 ↗(On Diff #166271)

Just to clarify: P.first.Data.size() is the size of the arena for all the symbols?

kbobyrev updated this revision to Diff 166462.Sep 21 2018, 5:44 AM
kbobyrev marked 4 inline comments as done.

Use llvm::Expected<SymbolSlab>, cleanup the patch.

kbobyrev added inline comments.Sep 21 2018, 6:32 AM
clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
91

As discussed offline, this hack also relies on the fact that benchmark has a dynamic nature of determining iterations count. Giving a large number of "time units" to the counter results in a single iteration.

I've tried to understand whether I could use any flags for User-Defined Counter that could just divide the number of iterations by IterationTime, but I could find one that would do exactly what is needed here. Also, I didn't find any way to manually set the iteration count.

clang-tools-extra/clangd/index/dex/Dex.cpp
239 ↗(On Diff #166271)

P is std::pair<Token, PostingList> here, so that would be Token.Data.size() which is the size of std::string stored in Token (e.g. trigram symbols for Trigram tokens, directory URI for ProximityPath tokens, etc). P is probably bad here, I'll change the naming to be more explicit.

lebedev.ri added inline comments.
clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
91

divide the number of iterations by IterationTime

And more unsolicited advices:
[[ https://github.com/google/benchmark/blob/1b44120cd16712f3b5decd95dc8ff2813574b273/include/benchmark/benchmark.h#L366-L368 | kIsIterationInvariantRate ]], but it is master-only, not in any release.
For now, do

State.counters["kIsIterationInvariantRate"] = benchmark::Counter(
                                                state.iterations(),
                                                benchmark::Counter::Flags::kIsRate);

If understood the question right.

Also, I didn't find any way to manually set the iteration count.

[[ https://github.com/google/benchmark/blob/1b44120cd16712f3b5decd95dc8ff2813574b273/include/benchmark/benchmark.h#L853-L859 | benchmark::Benchmark::Iterations() ]]

kbobyrev updated this revision to Diff 166481.EditedSep 21 2018, 7:35 AM
kbobyrev marked 3 inline comments as done.
  • Be more explicit about the nature of "benchmarks" with memory tracking logic via State::SetLabel(...).
  • Force single iteration for "benchmarks" with memory usage tracking
  • Add another "benchmark" with Dex memory overhead over plain SymbolSlab

Huge thanks to @lebedev.ri for helping! This looks much better to me now.

kbobyrev marked an inline comment as done.Sep 21 2018, 7:35 AM
ioeric added inline comments.Sep 21 2018, 8:12 AM
clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
89

Why did we move this benchmark (DexQueries)? It seems unnecessary.

108

nit: maybe divide by 1000.0 to avoid precision loss?

clang-tools-extra/clangd/index/SymbolYAML.cpp
187 ↗(On Diff #166481)

Could you put this near the old loadIndex to preserve the revision history?

sammccall requested changes to this revision.Sep 21 2018, 8:32 AM

This change does several things, and I think most of them need further thought. Can we discuss Monday?

clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
98

This looks like it'll be really stable, why does it need to be a benchmark vs say a dexp subcommand?

This revision now requires changes to proceed.Sep 21 2018, 8:32 AM
kbobyrev updated this revision to Diff 167067.Sep 26 2018, 1:04 AM
kbobyrev marked 2 inline comments as done.

Don't include misc changes elsewhere: focus on adding more benchmarks in this revision.

clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp
98

As discussed offline, this is meant to make it easier for people to investigate memory + performance changes and simplify the development pipeline as opposed to remembering multiple binaries and their options and running all these binaries after each change.

kbobyrev updated this revision to Diff 167267.Sep 27 2018, 3:30 AM

Pass data from I/O to readIndexFile(StringRef).

kbobyrev abandoned this revision.Dec 2 2019, 2:24 AM