diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2017-12-07 21:19:09 +0000 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2017-12-15 10:22:03 +0000 |
commit | 556e121379494d4bed9738d9c7539ac5afc8f6f4 (patch) | |
tree | 26ac1061ee6916376bf2906b3259f5a067c7b3b3 /sal | |
parent | 6d03c1367f0955900194287805324a8b4144e124 (diff) |
sal: add pre-initialization scheme for allocations.
This saves several megabytes of dirtied pages for each LOK
client of Online.
Change-Id: I425a2e7896879f0a64d71fcc0655e9e1fa1256aa
Diffstat (limited to 'sal')
-rw-r--r-- | sal/CppunitTest_sal_rtl.mk | 1 | ||||
-rw-r--r-- | sal/qa/rtl/alloc/rtl_alloc.cxx | 70 | ||||
-rw-r--r-- | sal/rtl/alloc_arena.cxx | 28 | ||||
-rw-r--r-- | sal/rtl/alloc_arena.hxx | 5 | ||||
-rw-r--r-- | sal/rtl/alloc_cache.cxx | 18 | ||||
-rw-r--r-- | sal/rtl/strimp.cxx | 65 | ||||
-rw-r--r-- | sal/rtl/strimp.hxx | 10 | ||||
-rw-r--r-- | sal/rtl/string.cxx | 6 | ||||
-rw-r--r-- | sal/rtl/strtmpl.cxx | 4 | ||||
-rw-r--r-- | sal/rtl/ustring.cxx | 8 | ||||
-rw-r--r-- | sal/util/sal.map | 5 |
11 files changed, 211 insertions, 9 deletions
diff --git a/sal/CppunitTest_sal_rtl.mk b/sal/CppunitTest_sal_rtl.mk index 43533fc5ab1c..c4629a2c33db 100644 --- a/sal/CppunitTest_sal_rtl.mk +++ b/sal/CppunitTest_sal_rtl.mk @@ -54,6 +54,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sal_rtl,\ $(eval $(call gb_CppunitTest_set_include,sal_rtl,\ -I$(SRCDIR)/sal/qa/inc \ + -I$(SRCDIR) \ $$(INCLUDE) \ )) diff --git a/sal/qa/rtl/alloc/rtl_alloc.cxx b/sal/qa/rtl/alloc/rtl_alloc.cxx index 30aadcc94f69..6a4c1648ff53 100644 --- a/sal/qa/rtl/alloc/rtl_alloc.cxx +++ b/sal/qa/rtl/alloc/rtl_alloc.cxx @@ -18,11 +18,14 @@ */ #include <rtl/alloc.h> +#include <rtl/ustrbuf.hxx> #include <sal/types.h> #include <cppunit/TestFixture.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/plugin/TestPlugIn.h> +#include <sal/rtl/strimp.hxx> + #include <memory.h> namespace rtl_alloc @@ -132,8 +135,75 @@ public: CPPUNIT_TEST_SUITE_END(); }; +class TestPreinit : public CppUnit::TestFixture +{ +public: + TestPreinit() + { + } + + // initialise your test code values here. + void setUp() override + { + } + + void tearDown() override + { + } + + // insert your test code here. + + void test() + { + const char *sample = "Hello World"; + std::vector<OUString> aStrings; + + rtl_alloc_preInit(true); + + OUString aFoo("foo"); + + // fill some cache bits + for (int iter = 0; iter < 4; iter++) + { + for (int i = 1; i < 4096; i += 8) + { + OUStringBuffer aBuf(i); + aBuf.appendAscii(sample, (i/8) % (sizeof(sample)-1)); + OUString aStr = aBuf.makeStringAndClear(); + aStrings.push_back(aStr); + } + // free some pieces to make holes + for (size_t i = iter; i < aStrings.size(); i += 17) + aStrings[i] = aFoo; + } + + for (size_t i = 0; i < aStrings.size(); ++i) + { + CPPUNIT_ASSERT_MESSAGE( "not static before.", !(aStrings[i].pData->refCount & SAL_STRING_STATIC_FLAG) ); + } + + // should static-ize all the strings. + rtl_alloc_preInit(false); + + for (size_t i = 0; i < aStrings.size(); ++i) + CPPUNIT_ASSERT_MESSAGE( "static after.", (aStrings[i].pData->refCount & SAL_STRING_STATIC_FLAG) ); + } + + void test2() + { + // should never happen but lets try it again. + test(); + } + + CPPUNIT_TEST_SUITE(TestPreinit); + CPPUNIT_TEST(test); + CPPUNIT_TEST(test2); + CPPUNIT_TEST_SUITE_END(); +}; + CPPUNIT_TEST_SUITE_REGISTRATION(rtl_alloc::Memory); CPPUNIT_TEST_SUITE_REGISTRATION(rtl_alloc::TestZeroMemory); +CPPUNIT_TEST_SUITE_REGISTRATION(rtl_alloc::TestPreinit); } // namespace rtl_alloc CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sal/rtl/alloc_arena.cxx b/sal/rtl/alloc_arena.cxx index ba28f6f532f0..b8df460b4e88 100644 --- a/sal/rtl/alloc_arena.cxx +++ b/sal/rtl/alloc_arena.cxx @@ -17,6 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/config.h> + #include "alloc_arena.hxx" #include "alloc_impl.hxx" @@ -990,6 +992,32 @@ void SAL_CALL rtl_arena_free ( } } +void rtl_arena_foreach (rtl_arena_type *arena, ArenaForeachFn foreachFn, void *user_data) +{ + // quantum caches + if ((arena->m_qcache_max > 0) && (arena->m_qcache_ptr != nullptr)) + { + int i, n = (arena->m_qcache_max >> arena->m_quantum_shift); + for (i = 1; i <= n; i++) + { + if (arena->m_qcache_ptr[i - 1] != nullptr) + rtl_cache_foreach (arena->m_qcache_ptr[i - 1], + foreachFn, user_data); + } + } + + /* used segments */ + for (int i = 0, n = arena->m_hash_size; i < n; i++) + { + for (rtl_arena_segment_type *segment = arena->m_hash_table[i]; + segment != nullptr; segment = segment->m_fnext) + { + foreachFn(reinterpret_cast<void *>(segment->m_addr), + segment->m_size, user_data); + } + } +} + #if defined(SAL_UNX) #include <sys/mman.h> #elif defined(SAL_W32) diff --git a/sal/rtl/alloc_arena.hxx b/sal/rtl/alloc_arena.hxx index 6a846876ff17..0ac54d96e575 100644 --- a/sal/rtl/alloc_arena.hxx +++ b/sal/rtl/alloc_arena.hxx @@ -112,6 +112,11 @@ struct rtl_arena_st */ extern rtl_arena_type * gp_default_arena; +typedef void (*ArenaForeachFn)(void *addr, sal_Size size, void *user_data); + +void rtl_arena_foreach(rtl_arena_type *arena, ArenaForeachFn fn, void *user_data); +void rtl_cache_foreach(rtl_cache_type *arena, ArenaForeachFn foreachFn, void *user_data); + #endif // INCLUDED_SAL_RTL_ALLOC_ARENA_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/rtl/alloc_cache.cxx b/sal/rtl/alloc_cache.cxx index 091a5bf774ee..468bbdcdbf04 100644 --- a/sal/rtl/alloc_cache.cxx +++ b/sal/rtl/alloc_cache.cxx @@ -1153,6 +1153,24 @@ void SAL_CALL rtl_cache_free( } } +// FIXME: foreachFn called for free'd blocks and will break free-chains. +void rtl_cache_foreach(rtl_cache_type *cache, ArenaForeachFn foreachFn, void *user_data) +{ + for (rtl_cache_slab_type *cur = &(cache->m_used_head); + cur && cur->m_slab_next != &(cache->m_used_head); + cur = cur->m_slab_next) + { + for (char *item = reinterpret_cast<char *>(cur->m_data); + item < reinterpret_cast<char *>(cur->m_bp); + item += cache->m_type_size) + { + foreachFn(item, cache->m_type_size, user_data); + } + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); +} + #if defined(SAL_UNX) void SAL_CALL rtl_secureZeroMemory(void *Ptr, sal_Size Bytes) SAL_THROW_EXTERN_C() diff --git a/sal/rtl/strimp.cxx b/sal/rtl/strimp.cxx index db554644f6a9..a739bda8f155 100644 --- a/sal/rtl/strimp.cxx +++ b/sal/rtl/strimp.cxx @@ -16,8 +16,15 @@ * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/config.h> + +#include <assert.h> +#include <rtl/alloc.h> +#include <rtl/ustring.h> #include "strimp.hxx" +#include "alloc_impl.hxx" +#include "alloc_arena.hxx" sal_Int16 rtl_ImplGetDigit( sal_Unicode ch, sal_Int16 nRadix ) { @@ -49,4 +56,62 @@ bool rtl_ImplIsWhitespace( sal_Unicode c ) return false; } +/* + * TODO: add a slower, more awful, but more space efficient + * custom allocator for the pre-init phase. Existing slab + * allocator's minimum alloc size is 24bytes, and by default + * is 32 bytes. + */ +static rtl_arena_type *pre_arena = nullptr; + +rtl_allocateStringFn rtl_allocateString = rtl_allocateMemory; +rtl_freeStringFn rtl_freeString = rtl_freeMemory; + +extern "C" { +static void *pre_allocateStringFn(sal_Size n) +{ + sal_Size size = RTL_MEMORY_ALIGN(n + 4, 4); + char *addr = static_cast<char*>(rtl_arena_alloc(pre_arena, &size)); + assert(size>= 12); + reinterpret_cast<sal_uInt32*>(addr)[0] = size - 12; + return addr + 4; +} + +static void pre_freeStringFn(void *data) +{ + char *addr = static_cast<char*>(data) - 4; + sal_Size size = reinterpret_cast<sal_uInt32*>(addr)[0] + 12; + + rtl_arena_free(pre_arena, addr, size); +} +} // extern "C" + +static void mark_static(void *addr, sal_Size /* size */, void *) +{ + char *inner = static_cast<char*>(addr) + 4; + rtl_uString *str = reinterpret_cast<rtl_uString *>(inner); + str->refCount |= SAL_STRING_STATIC_FLAG; +} + +void SAL_CALL rtl_alloc_preInit (sal_Bool start) SAL_THROW_EXTERN_C() +{ + if (start) + { + rtl_allocateString = pre_allocateStringFn; + rtl_freeString = pre_freeStringFn; + pre_arena = rtl_arena_create("pre-init strings", 4, 0, + nullptr, rtl_arena_alloc, + rtl_arena_free, 0); + } + else // back to normal + { + rtl_arena_foreach(pre_arena, mark_static, nullptr); + rtl_allocateString = rtl_allocateMemory; + rtl_freeString = rtl_freeMemory; + + // TODO: also re-intialize main allocator as well. + } +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/rtl/strimp.hxx b/sal/rtl/strimp.hxx index c6325dedaa75..a5767fea6917 100644 --- a/sal/rtl/strimp.hxx +++ b/sal/rtl/strimp.hxx @@ -49,6 +49,16 @@ sal_Int16 rtl_ImplGetDigit( sal_Unicode ch, sal_Int16 nRadix ); bool rtl_ImplIsWhitespace( sal_Unicode c ); +extern "C" { + +typedef void *(*rtl_allocateStringFn)(sal_Size size); +typedef void (*rtl_freeStringFn)(void *); + +} + +extern rtl_allocateStringFn rtl_allocateString; +extern rtl_freeStringFn rtl_freeString; + // string lifetime instrumentation / diagnostics #if USE_SDT_PROBES # define PROBE_SNAME(n,b) n ## _ ## b diff --git a/sal/rtl/string.cxx b/sal/rtl/string.cxx index c7a868cb9957..20a2cda499c4 100644 --- a/sal/rtl/string.cxx +++ b/sal/rtl/string.cxx @@ -274,7 +274,7 @@ bool rtl_impl_convertUStringToString(rtl_String ** pTarget, &nInfo, &nSrcChars ); if (bCheckErrors && (nInfo & RTL_UNICODETOTEXT_INFO_ERROR) != 0) { - rtl_freeMemory(pTemp); + rtl_freeString(pTemp); rtl_destroyUnicodeToTextConverter(hConverter); return false; } @@ -283,7 +283,7 @@ bool rtl_impl_convertUStringToString(rtl_String ** pTarget, break; /* Buffer not big enough, try again with enough space */ - rtl_freeMemory( pTemp ); + rtl_freeString( pTemp ); /* Try with the max. count of characters with additional overhead for replacing functionality */ @@ -298,7 +298,7 @@ bool rtl_impl_convertUStringToString(rtl_String ** pTarget, rtl_String* pTemp2 = rtl_string_ImplAlloc( nDestBytes ); OSL_ASSERT(pTemp2 != nullptr); rtl_str_ImplCopy( pTemp2->buffer, pTemp->buffer, nDestBytes ); - rtl_freeMemory( pTemp ); + rtl_freeString( pTemp ); pTemp = pTemp2; } else diff --git a/sal/rtl/strtmpl.cxx b/sal/rtl/strtmpl.cxx index 62bb76ddfdd1..5fdab82f8b43 100644 --- a/sal/rtl/strtmpl.cxx +++ b/sal/rtl/strtmpl.cxx @@ -1149,7 +1149,7 @@ static IMPL_RTL_STRINGDATA* IMPL_RTL_STRINGNAME( ImplAlloc )( sal_Int32 nLen ) = (sal::static_int_cast< sal_uInt32 >(nLen) <= ((SAL_MAX_UINT32 - sizeof (IMPL_RTL_STRINGDATA)) / sizeof (IMPL_RTL_STRCODE))) - ? static_cast<IMPL_RTL_STRINGDATA *>(rtl_allocateMemory( + ? static_cast<IMPL_RTL_STRINGDATA *>(rtl_allocateString( sizeof (IMPL_RTL_STRINGDATA) + nLen * sizeof (IMPL_RTL_STRCODE))) : nullptr; if (pData != nullptr) { @@ -1230,7 +1230,7 @@ void SAL_CALL IMPL_RTL_STRINGNAME( release )( IMPL_RTL_STRINGDATA* pThis ) if ( !osl_atomic_decrement( &(pThis->refCount) ) ) { RTL_LOG_STRING_DELETE( pThis ); - rtl_freeMemory( pThis ); + rtl_freeString( pThis ); } } diff --git a/sal/rtl/ustring.cxx b/sal/rtl/ustring.cxx index 167cdf2eab6d..31e0cf10d363 100644 --- a/sal/rtl/ustring.cxx +++ b/sal/rtl/ustring.cxx @@ -830,7 +830,7 @@ retry: code here. Could be the case for apple encodings */ while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL ) { - rtl_freeMemory( pTemp ); + rtl_freeString( pTemp ); nNewLen += 8; pTemp = rtl_uString_ImplAlloc( nNewLen ); if (pTemp == nullptr) { @@ -859,7 +859,7 @@ retry: if (pTemp2 != nullptr) { rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars); - rtl_freeMemory(pTemp); + rtl_freeString(pTemp); pTemp = pTemp2; } else @@ -926,7 +926,7 @@ static void rtl_ustring_intern_internal( rtl_uString ** newStr, if( can_return && *newStr != str ) { /* we dupped, then found a match */ - rtl_freeMemory( str ); + rtl_freeString( str ); } } @@ -1077,7 +1077,7 @@ internRelease (rtl_uString *pThis) osl_releaseMutex( pPoolMutex ); } if (pFree) - rtl_freeMemory (pFree); + rtl_freeString (pFree); } sal_uInt32 SAL_CALL rtl_uString_iterateCodePoints( diff --git a/sal/util/sal.map b/sal/util/sal.map index 579119065121..86ad07525ee6 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -740,6 +740,11 @@ PRIVATE_1.4 { # LibreOffice 6.0 _ZN3sal19backtrace_to_stringEPNS_14BacktraceStateE; } PRIVATE_1.3; +PRIVATE_1.5 { # LibreOffice 6.1 + global: + rtl_alloc_preInit; +} PRIVATE_1.4; + PRIVATE_textenc.1 { # LibreOffice 3.6 global: _ZN3sal6detail7textenc20convertCharToUnicode*; |