summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2017-12-07 21:19:09 +0000
committerAndras Timar <andras.timar@collabora.com>2018-03-19 18:57:30 +0100
commitc49d98ae780063770fd2e7c0369211fa4e11a70a (patch)
tree4c6f2f5fc4c364e67fe3501668b34fb3991f094b /sal
parentdd43ea20eedf3dfbc516065d9dc23c8dab8938a9 (diff)
sal: add pre-initialization scheme for allocations.
This saves several megabytes of dirtied pages for each LOK client of Online. Change-Id: I425a2e7896879f0a64d71fcc0655e9e1fa1256aa (cherry picked from commit 556e121379494d4bed9738d9c7539ac5afc8f6f4)
Diffstat (limited to 'sal')
-rw-r--r--sal/CppunitTest_sal_rtl.mk1
-rw-r--r--sal/qa/rtl/alloc/rtl_alloc.cxx70
-rw-r--r--sal/rtl/alloc_arena.cxx28
-rw-r--r--sal/rtl/alloc_arena.hxx5
-rw-r--r--sal/rtl/alloc_cache.cxx18
-rw-r--r--sal/rtl/strimp.cxx65
-rw-r--r--sal/rtl/strimp.hxx10
-rw-r--r--sal/rtl/string.cxx6
-rw-r--r--sal/rtl/strtmpl.cxx4
-rw-r--r--sal/rtl/ustring.cxx8
-rw-r--r--sal/util/sal.map5
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 373de6d51ad9..2812ac037d7f 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 8dbcee763a95..d6f184a85b6c 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 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*;