From 94c2fb28d76c9c37849412a66b31d6861bce3155 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Wed, 6 Apr 2022 19:28:07 +0200 Subject: faster hashing of very long strings in SalLayoutGlyphsCache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tdf#147284 being a (pathological) testcase. Change-Id: I08d8dffb40193b461555bed818c040761e8d575b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132669 Tested-by: Jenkins Reviewed-by: Luboš Luňák --- vcl/inc/TextLayoutCache.hxx | 32 ++++++++++++++++++++++++++++++++ vcl/source/gdi/CommonSalLayout.cxx | 30 +----------------------------- vcl/source/gdi/impglyphitem.cxx | 6 ++++-- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/vcl/inc/TextLayoutCache.hxx b/vcl/inc/TextLayoutCache.hxx index 0ce0c19d8278..ecb85ea7043d 100644 --- a/vcl/inc/TextLayoutCache.hxx +++ b/vcl/inc/TextLayoutCache.hxx @@ -20,6 +20,8 @@ #pragma once #include +#include +#include #include @@ -48,6 +50,36 @@ public: std::vector runs; TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd); }; + +struct FirstCharsStringHash +{ + size_t operator()(const OUString& str) const + { + // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, + // and computing an entire hash could almost negate the gain of hashing. Hash just first + // characters, that should be good enough. + size_t hash + = rtl_ustr_hashCode_WithLength(str.getStr(), std::min(100, str.getLength())); + o3tl::hash_combine(hash, str.getLength()); + return hash; + } +}; + +struct FastStringCompareEqual +{ + bool operator()(const OUString& str1, const OUString& str2) const + { + // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, + // and OUString operator == compares backwards and using hard-written code, while + // memcmp() compares much faster. + if (str1.getLength() != str2.getLength()) + return false; + if (str1.getStr() == str2.getStr()) + return true; + return memcmp(str1.getStr(), str2.getStr(), str1.getLength() * sizeof(str1.getStr()[0])) + == 0; + } +}; } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 8dee28727997..2c8a4db8398f 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -154,40 +154,12 @@ namespace { return VerticalOrientation(nRet); } -struct FirstCharsStringHash -{ - size_t operator()( const OUString& str ) const - { - // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, - // and computing an entire hash could almost negate the gain of hashing. Hash just first - // characters, that should be good enough. - size_t hash = rtl_ustr_hashCode_WithLength( str.getStr(), std::min( 100, str.getLength())); - o3tl::hash_combine(hash, str.getLength()); - return hash; - } -}; - -struct ForwardStringCompareEqual -{ - bool operator()( const OUString& str1, const OUString& str2 ) const - { - // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, - // and OUString operator == compares backwards, which is inefficient for very long - // strings (bad memory prefetch). - if( str1.getLength() != str2.getLength()) - return false; - if( str1.getStr() == str2.getStr()) - return true; - return memcmp( str1.getStr(), str2.getStr(), str1.getLength() * sizeof( str1.getStr()[ 0 ] )) == 0; - } -}; - } // namespace std::shared_ptr GenericSalLayout::CreateTextLayoutCache(OUString const& rString) { typedef o3tl::lru_map, - FirstCharsStringHash, ForwardStringCompareEqual> Cache; + vcl::text::FirstCharsStringHash, vcl::text::FastStringCompareEqual> Cache; static vcl::DeleteOnDeinit< Cache > cache( 1000 ); if( Cache* map = cache.get()) { diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index eaf8cf5c8453..d320d27dad88 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -21,6 +21,7 @@ #include #include #include +#include SalLayoutGlyphs::SalLayoutGlyphs() {} @@ -146,7 +147,7 @@ SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const VclPtrGetFont()); o3tl::hash_combine(hashValue, static_cast(stream.GetData()), stream.GetSize()); - o3tl::hash_combine(hashValue, text); + o3tl::hash_combine(hashValue, vcl::text::FirstCharsStringHash()(text)); o3tl::hash_combine(hashValue, index); o3tl::hash_combine(hashValue, len); o3tl::hash_combine(hashValue, logicPos.X()); @@ -158,7 +159,8 @@ inline bool SalLayoutGlyphsCache::CachedGlyphsKey::operator==(const CachedGlyphs { return hashValue == other.hashValue && outputDevice == other.outputDevice && index == other.index && len == other.len && logicPos == other.logicPos - && logicWidth == other.logicWidth && text == other.text; + && logicWidth == other.logicWidth + && vcl::text::FastStringCompareEqual()(text, other.text); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit