diff options
| author | Paul Kirth <paulkirth@google.com> | 2025-09-26 15:46:57 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-26 15:46:57 -0700 |
| commit | f9065fce8fd2bb664ed8dcb7582432b83c2114c4 (patch) | |
| tree | 33a7a32f11fd65ab731f1be0b7b5311ff865a928 /llvm | |
| parent | 220ad03d5b28dbd83dbb90896a7eb55b74004818 (diff) | |
| download | llvm-f9065fce8fd2bb664ed8dcb7582432b83c2114c4.zip llvm-f9065fce8fd2bb664ed8dcb7582432b83c2114c4.tar.gz llvm-f9065fce8fd2bb664ed8dcb7582432b83c2114c4.tar.bz2 | |
[llvm][mustache] Avoid excessive hash lookups in EscapeStringStream (#160166)
The naive char-by-char lookup performed OK, but we can skip ahead to the
next match, avoiding all the extra hash lookups in the key map. Likely
there is a faster method than this, but its already a 42% win in the
BM_Mustache_StringRendering/Escaped benchmark, and an order of magnitude
improvement for BM_Mustache_LargeOutputString.
| Benchmark | Before (ns) | After (ns) | Speedup |
| :--- | ---: | ---: | ---: |
| `StringRendering/Escaped` | 29,440,922 | 16,583,603 | ~44% |
| `LargeOutputString` | 15,139,251 | 929,891 | ~94% |
| `HugeArrayIteration` | 102,148,245 | 95,943,960 | ~6% |
| `PartialsRendering` | 308,330,014 | 303,556,563 | ~1.6% |
Unreported benchmarks, like those for parsing, had no significant
change.
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Support/Mustache.cpp | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp index be9cbfd..686688a 100644 --- a/llvm/lib/Support/Mustache.cpp +++ b/llvm/lib/Support/Mustache.cpp @@ -397,19 +397,32 @@ class EscapeStringStream : public raw_ostream { public: explicit EscapeStringStream(llvm::raw_ostream &WrappedStream, EscapeMap &Escape) - : Escape(Escape), WrappedStream(WrappedStream) { + : Escape(Escape), EscapeChars(Escape.keys().begin(), Escape.keys().end()), + WrappedStream(WrappedStream) { SetUnbuffered(); } protected: void write_impl(const char *Ptr, size_t Size) override { - llvm::StringRef Data(Ptr, Size); - for (char C : Data) { - auto It = Escape.find(C); - if (It != Escape.end()) - WrappedStream << It->getSecond(); - else - WrappedStream << C; + StringRef Data(Ptr, Size); + size_t Start = 0; + while (Start < Size) { + // Find the next character that needs to be escaped. + size_t Next = Data.find_first_of(EscapeChars.str(), Start); + + // If no escapable characters are found, write the rest of the string. + if (Next == StringRef::npos) { + WrappedStream << Data.substr(Start); + return; + } + + // Write the chunk of text before the escapable character. + if (Next > Start) + WrappedStream << Data.substr(Start, Next - Start); + + // Look up and write the escaped version of the character. + WrappedStream << Escape[Data[Next]]; + Start = Next + 1; } } @@ -417,6 +430,7 @@ protected: private: EscapeMap &Escape; + SmallString<8> EscapeChars; llvm::raw_ostream &WrappedStream; }; |
