[llvm-branch-commits] [llvm] [llvm][mustache] Avoid excessive hash lookups in EscapeStringStream (PR #160166)
Paul Kirth via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Sep 22 11:20:50 PDT 2025
https://github.com/ilovepi created https://github.com/llvm/llvm-project/pull/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.
>From 29e37be8957bb486722fe52ba404501031b1691e Mon Sep 17 00:00:00 2001
From: Paul Kirth <pk1574 at gmail.com>
Date: Mon, 22 Sep 2025 16:26:04 +0000
Subject: [PATCH] [llvm][mustache] Avoid excessive hash lookups in
EscapeStringStream
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.
---
llvm/lib/Support/Mustache.cpp | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index c7cebe6b64fae..911fd5ee7fa01 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -428,19 +428,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;
}
}
@@ -448,6 +461,7 @@ class EscapeStringStream : public raw_ostream {
private:
EscapeMap &Escape;
+ SmallString<8> EscapeChars;
llvm::raw_ostream &WrappedStream;
};
More information about the llvm-branch-commits
mailing list