include/vcl/glyphitemcache.hxx | 17 ++++++++++------- vcl/inc/TextLayoutCache.hxx | 32 ++++++++++++++++++++++++++++++++ vcl/source/gdi/CommonSalLayout.cxx | 30 +----------------------------- vcl/source/gdi/impglyphitem.cxx | 20 +++++++++++++++----- 4 files changed, 58 insertions(+), 41 deletions(-)
New commits: commit 94c2fb28d76c9c37849412a66b31d6861bce3155 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Apr 6 19:28:07 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Fri Apr 8 21:28:15 2022 +0200 faster hashing of very long strings in SalLayoutGlyphsCache 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 <l.lu...@collabora.com> 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 <sal/types.h> +#include <rtl/ustring.hxx> +#include <o3tl/hash_combine.hxx> #include <vcl/dllapi.h> @@ -48,6 +50,36 @@ public: std::vector<vcl::text::Run> 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<size_t>(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<size_t>( 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<const vcl::text::TextLayoutCache> GenericSalLayout::CreateTextLayoutCache(OUString const& rString) { typedef o3tl::lru_map<OUString, std::shared_ptr<const vcl::text::TextLayoutCache>, - 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 <vcl/glyphitemcache.hxx> #include <vcl/vcllayout.hxx> #include <tools/stream.hxx> +#include <TextLayoutCache.hxx> SalLayoutGlyphs::SalLayoutGlyphs() {} @@ -146,7 +147,7 @@ SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const VclPtr<const Output SvMemoryStream stream; WriteFont(stream, outputDevice->GetFont()); o3tl::hash_combine(hashValue, static_cast<const char*>(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: */ commit 1b593dbc62dc2ceebc3f8be30d7221c916098f6d Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Apr 6 18:52:21 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Fri Apr 8 21:27:59 2022 +0200 use vcl::text::TextLayoutCache in SalLayoutGlyphsCache Change-Id: I0ec22fe53e05319dec15456a916b10e97ea91a75 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132668 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx index 8c7cd01bbadc..83c77309a632 100644 --- a/include/vcl/glyphitemcache.hxx +++ b/include/vcl/glyphitemcache.hxx @@ -44,15 +44,18 @@ public: : mCachedGlyphs(size) { } - const SalLayoutGlyphs* GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, - const OUString& text) const + const SalLayoutGlyphs* + GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, const OUString& text, + const vcl::text::TextLayoutCache* layoutCache = nullptr) const { - return GetLayoutGlyphs(outputDevice, text, 0, text.getLength()); + return GetLayoutGlyphs(outputDevice, text, 0, text.getLength(), Point(0, 0), 0, + layoutCache); } - const SalLayoutGlyphs* GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, - const OUString& text, sal_Int32 nIndex, sal_Int32 nLen, - const Point& rLogicPos = Point(0, 0), - tools::Long nLogicWidth = 0) const; + const SalLayoutGlyphs* + GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, const OUString& text, sal_Int32 nIndex, + sal_Int32 nLen, const Point& rLogicPos = Point(0, 0), + tools::Long nLogicWidth = 0, + const vcl::text::TextLayoutCache* layoutCache = nullptr) const; void clear() { mCachedGlyphs.clear(); } private: diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 3853691d7d00..eaf8cf5c8453 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -97,7 +97,8 @@ bool SalLayoutGlyphsImpl::IsValid() const const SalLayoutGlyphs* SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, const OUString& text, sal_Int32 nIndex, sal_Int32 nLen, const Point& rLogicPos, - tools::Long nLogicWidth) const + tools::Long nLogicWidth, + const vcl::text::TextLayoutCache* layoutCache) const { if (nLen == 0) return nullptr; @@ -112,8 +113,15 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, c // So in that case this is a cached failure. return nullptr; } - std::unique_ptr<SalLayout> layout = outputDevice->ImplLayout( - text, nIndex, nLen, rLogicPos, nLogicWidth, {}, SalLayoutFlags::GlyphItemsOnly); + std::shared_ptr<const vcl::text::TextLayoutCache> tmpLayoutCache; + if (layoutCache == nullptr) + { + tmpLayoutCache = OutputDevice::CreateTextLayoutCache(text); + layoutCache = tmpLayoutCache.get(); + } + std::unique_ptr<SalLayout> layout + = outputDevice->ImplLayout(text, nIndex, nLen, rLogicPos, nLogicWidth, {}, + SalLayoutFlags::GlyphItemsOnly, layoutCache); if (layout) { mCachedGlyphs.insert(std::make_pair(key, layout->GetGlyphs()));