summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2017-11-30 18:59:30 +0000
committerAshod Nakashian <ashnakash@gmail.com>2017-12-18 07:17:06 +0100
commit9afbb77b635dc61bd75541adc1eb05f7bceed7cd (patch)
tree4f26d50fc6171b0552f40ed5901c7ae17a4d0f7d /sal
parent53e79c6eab3566b4c3476a5467370ad103bb6e5e (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.cxx70
-rw-r--r--sal/rtl/alloc_arena.cxx31
-rw-r--r--sal/rtl/alloc_arena.hxx8
-rw-r--r--sal/rtl/alloc_cache.cxx20
-rw-r--r--sal/rtl/alloc_global.cxx4
-rw-r--r--sal/rtl/strimp.cxx68
-rw-r--r--sal/rtl/strimp.hxx6
-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.map4
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*;