Re: [PATCH] libcpp: Optimize AArch64 search_line_fast
Alexander Monakov <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On Fri, 14 Aug 2026, Wilco Dijkstra wrote: > It's just measuring the throughput of the search_line_fast function for different sizes. > Then calculate the average from the speedup of each size times the frequency of the > distribution. As it happens, the old code was doing a lot of unnecessary initialization, > checks etc, so the speedup goes from ~85% for 1-16 chars to ~50% at 80 chars. Thanks. It's good to know that new code is that much faster for short lines, but I suspect averaging in this manner is not ideal if measurements are taken as if final branch is perfectly predictable. > > Yeah. When working on x86 SSSE3 implementation I noticed that at 16 characters > > per iteration, the branch that exits the loop tends to be pretty unpredictable > > on "typical" C++ sources, so moving to 32 characters per iteration helped with > > that a bit, even with 16-byte vectors (so two vector loads per iteration, etc) > > > > I wonder if you looked at something like that? Doing two 16-character matches > > per one iteration, then combining results into one GPR for the final CBZ? > > Not sure if there's a way to make the epilogue cheap enough, though. > > It's certainly possible to do so, but it would be hard to measure whether it ends up > faster. It probably means saving a trace and then replaying it. How did you measure > the effect of branch prediction on overall compile time? With 'perf stat -r 9 cc1plus -fsyntax-only -quiet t-rawstr.cc' where t-rawstr.cc is a big C++ file created by preprocessing '#include <regex>' (see Makefile in the attachment). It was posted with my SSSE3-based search_line_fast at https://inbox.sourceware.org/gcc-patches/[email protected]/ (attaching it again to this message) and my measurements can be seen at https://inbox.sourceware.org/gcc-patches/[email protected]/ > >> + const uchar *limit = (const uchar*) ((uintptr_t)end & ~15); > > > > This is not safe in absence of padding: when 's' itself is not aligned, > > and 'end' is close to it, this may move 'limit' to before 's', and then > > the load from *limit will pick up bytes prior to 's'. > > Yes that's why I read from limit to get a full vector and then just shift out any > chars before 's' - this magic removes 0-15 nibbles from the result mask based > on the alignment of 's': > > + mask >>= (uintptr_t)s * 4; Sorry, I missed that. Would have been worth a comment, if it wasn't going! > > Now, libcpp provides sufficient tail padding (at least 16 bytes, with '\n' > > at the beginning of padding area) so in context this is safe, but then > > the final aligned load should never be reached, and computing 'limit' is > > pointless. > > If we can safely read 16 bytes beyond 'end' then yes, the loop condition could be: > > while (s < end) > ... loop > // no tail code, just return end since it is known that *end == '\n'. > return end; No, I meant you can just have an infinite loop because the test in the loop will work properly when *end is reached. Alexander PS: unfortunately I didn't get a copy of your response to my inbox and had to fish it out of the mailing list archive
search-line-bench.tgz
(application/gzip, 1.7 KB) - not displayed