[PATCH] D50839: [llvm] Optimize YAML::isNumeric

Kirill Bobyrev via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 16 06:00:44 PDT 2018


kbobyrev created this revision.
kbobyrev added reviewers: ilya-biryukov, ioeric.
Herald added a reviewer: javed.absar.
Herald added a subscriber: kristof.beyls.

This patch significantly improves performance of the YAML serializer by optimizing `YAML::isNumeric` function. This function is called on the most strings and is highly inefficient for two reasons:

- It uses `Regex`, which is parsed and compiled each time this function is called
- It uses multiple passes which are not necessary

This patch introduces stateful ad hoc YAML number parser which does not rely on `Regex`. It also fixes YAML number format inconsistency: current implementation supports C-stile octal number format (`01234567`) which was present in YAML 1.0 specialization (http://yaml.org/spec/1.0/), [Section 2.4. Tags, Example 2.19] but was deprecated and is no longer present in latest YAML 1.2 specification (http://yaml.org/spec/1.2/spec.html), see [Section 10.3.2. Tag Resolution]. Since the rest of the rest of the implementation does not support other deprecated YAML 1.0 numeric features such as sexagecimal numbers, commas as delimiters it is treated as inconsistency and not longer supported.

This performance bottleneck was identified while profiling Clangd's global-symbol-builder tool with my colleague @ilya-biryukov. The substantial part of the runtime was spent during a single-thread Reduce phase, which concludes with YAML serialization of collected symbol collection. Regex matching was accountable for approximately 45% of the whole runtime (which involves sharded Map phase), now it is reduced to 18% (which is spent in `clang::clangd::CanonicalIncludes` and can be also optimized because all used regexes are in fact either suffix matches or exact matches).

Benchmarking `global-symbol-builder` (using `hyperfine --warmup 2 --min-runs 5 'command 1' 'command 2'` tool by processing a reasonable amount of code (26 source files matched by `clang-tools-extra/clangd/*.cpp` with all transitive includes) confirmed our understanding of the performance bottleneck nature as it speeds up the command by the factor of 1.6x:

| Command    | Mean [s]    | Min…Max [s] |
| :---       | ---:        | ---:        |
| patch      | 84.7 ± 0.6  | 83.3…84.7   |
| master (https://reviews.llvm.org/rL339849) | 133.1 ± 0.8 | 132.4…134.6 |
|

Using smaller samples (e.g. by collecting symbols from `clang-tools-extra/clangd/AST.cpp` only) yields even better performance improvement, which is expected because Map phase takes less time compared to Reduce and is 2.05x faster:

| Command    | Mean [ms]      | Min…Max [ms]  |
| :---       | ---:           | ---:          |
| patch      | 7607.6 ± 109.5 | 7533.3…7796.4 |
| master (https://reviews.llvm.org/rL339849) | 3702.2 ± 48.7  | 3635.1…3752.3 |


https://reviews.llvm.org/D50839

Files:
  llvm/include/llvm/Support/YAMLTraits.h
  llvm/unittests/Support/YAMLIOTest.cpp

-------------- next part --------------
A non-text attachment was scrubbed...
Name: D50839.161008.patch
Type: text/x-patch
Size: 6730 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180816/3ec6d867/attachment-0001.bin>


More information about the cfe-commits mailing list