diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2017-11-30 18:59:30 +0000 |
---|---|---|
committer | Ashod Nakashian <ashnakash@gmail.com> | 2017-12-18 07:17:06 +0100 |
commit | 9afbb77b635dc61bd75541adc1eb05f7bceed7cd (patch) | |
tree | 4f26d50fc6171b0552f40ed5901c7ae17a4d0f7d /sal | |
parent | 53e79c6eab3566b4c3476a5467370ad103bb6e5e (diff) |
sal: add pre-initialization scheme for allocations.
This saves several megabytes of dirtied pages for each LOK
client of Online.
Change-Id: I425a2e7896879f0a64d71fcc0655e9e1fa1256aa
Reviewed-on: https://gerrit.libreoffice.org/46592
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Diffstat (limited to 'sal')
-rw-r--r-- | sal/qa/rtl/alloc/rtl_alloc.cxx | 70 | ||||
-rw-r--r-- | sal/rtl/alloc_arena.cxx | 31 | ||||
-rw-r--r-- | sal/rtl/alloc_arena.hxx | 8 | ||||
-rw-r--r-- | sal/rtl/alloc_cache.cxx | 20 | ||||
-rw-r--r-- | sal/rtl/alloc_global.cxx | 4 | ||||
-rw-r--r-- | sal/rtl/strimp.cxx | 68 | ||||
-rw-r--r-- | sal/rtl/strimp.hxx | 6 | ||||
-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 | 4 |
11 files changed, 218 insertions, 11 deletions
diff --git a/sal/qa/rtl/alloc/rtl_alloc.cxx b/sal/qa/rtl/alloc/rtl_alloc.cxx index ed0a9def1dbe..9ea21456ca94 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> +#define SAL_STRING_STATIC_FLAG 0x40000000 + #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 234a3d5c6755..6e0a55dbb886 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" @@ -728,6 +730,35 @@ rtl_arena_activate ( return arena; } +extern "C" { +void rtl_arena_foreach(rtl_arena_type *arena, ArenaForeachFn foreachFn, void *user_data) SAL_THROW_EXTERN_C() +{ + // 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); + } + } +} +} // extern "C" + + /** rtl_arena_deactivate() */ void diff --git a/sal/rtl/alloc_arena.hxx b/sal/rtl/alloc_arena.hxx index da2ebeacc683..85a0b4b8c0b3 100644 --- a/sal/rtl/alloc_arena.hxx +++ b/sal/rtl/alloc_arena.hxx @@ -112,6 +112,14 @@ struct rtl_arena_st */ extern rtl_arena_type * gp_default_arena; +extern "C" { + +typedef void (*ArenaForeachFn)(void *addr, sal_Size size, void *user_data); +void SAL_CALL rtl_arena_foreach(rtl_arena_type *arena, ArenaForeachFn fn, void *user_data) SAL_THROW_EXTERN_C(); +void SAL_CALL rtl_cache_foreach(rtl_cache_type *arena, ArenaForeachFn foreachFn, void *user_data) SAL_THROW_EXTERN_C(); + +} + #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 d91908879c70..e6c7ddad24c7 100644 --- a/sal/rtl/alloc_cache.cxx +++ b/sal/rtl/alloc_cache.cxx @@ -1290,6 +1290,26 @@ SAL_CALL rtl_cache_free ( } } +// FIXME: foreachFn called for free'd blocks and will break free-chains. +extern "C" { +void SAL_CALL rtl_cache_foreach(rtl_cache_type *cache, ArenaForeachFn foreachFn, void *user_data) SAL_THROW_EXTERN_C() +{ + 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)); +} +} // extern "C" + #if defined(SAL_UNX) void SAL_CALL diff --git a/sal/rtl/alloc_global.cxx b/sal/rtl/alloc_global.cxx index 703a42b0902a..3f0ad42d928c 100644 --- a/sal/rtl/alloc_global.cxx +++ b/sal/rtl/alloc_global.cxx @@ -381,6 +381,8 @@ void SAL_CALL rtl_freeZeroMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() } } +/* ================================================================= */ + void* SAL_CALL rtl_allocateAlignedMemory (sal_Size Alignment, sal_Size Bytes) SAL_THROW_EXTERN_C() { return osl_aligned_alloc(Alignment, Bytes); @@ -391,6 +393,4 @@ void SAL_CALL rtl_freeAlignedMemory (void* Ptr) SAL_THROW_EXTERN_C() osl_aligned_free(Ptr); } -/* ================================================================= */ - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/rtl/strimp.cxx b/sal/rtl/strimp.cxx index db554644f6a9..39b08a4ff2c3 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,65 @@ 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 32bits. + */ +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); +} + +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; +} +} // extern "C" + +void SAL_CALL rtl_alloc_preInit (sal_Bool start) SAL_THROW_EXTERN_C() +{ + if (getenv("SAL_DISABLE_PREINIT")) + return; + + 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 5583a82f2249..3089a516ad97 100644 --- a/sal/rtl/strimp.hxx +++ b/sal/rtl/strimp.hxx @@ -49,6 +49,12 @@ sal_Int16 rtl_ImplGetDigit( sal_Unicode ch, sal_Int16 nRadix ); bool rtl_ImplIsWhitespace( sal_Unicode 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 863d6b870b3e..3678865c07f6 100644 --- a/sal/rtl/string.cxx +++ b/sal/rtl/string.cxx @@ -274,7 +274,7 @@ bool SAL_CALL 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 SAL_CALL 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 SAL_CALL 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 6748209fb50f..2bc1a71d5372 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 3d157270ef3c..a518bffc2f58 100644 --- a/sal/rtl/ustring.cxx +++ b/sal/rtl/ustring.cxx @@ -819,7 +819,7 @@ retry: code here. Could be the case for apple encodings */ while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL ) { - rtl_freeMemory( pTemp ); + rtl_freeString( pTemp ); nNewLen += 8; pTemp = rtl_uString_ImplAlloc( nNewLen ); if (pTemp == nullptr) { @@ -848,7 +848,7 @@ retry: if (pTemp2 != nullptr) { rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars); - rtl_freeMemory(pTemp); + rtl_freeString(pTemp); pTemp = pTemp2; } else @@ -932,7 +932,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 ); } } @@ -1083,7 +1083,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 c8f3a7426964..bbc0e926846c 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -728,6 +728,10 @@ PRIVATE_1.2 { # LibreOffice 3.5 sal_detail_logFormat; } PRIVATE_1.1; +PRIVATE_1.3 { # LibreOffice 6.1 + rtl_alloc_preInit; +} PRIVATE_1.2; + PRIVATE_textenc.1 { # LibreOffice 3.6 global: _ZN3sal6detail7textenc20convertCharToUnicode*; |