[libcxx-commits] [PATCH] D155486: Optimize basic_string's memory usage

Martijn Vels via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 17 09:39:51 PDT 2023


mvels created this revision.
Herald added a project: All.
mvels requested review of this revision.
Herald added a project: libc++.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libc++.

- change __alignment from 16 to 8

The 16 value is likely inspired by the default glibc malloc() function returning 16 byte aligned memory. While this is true, this is not the underlying allocated capacity which for smaller allocs follows `8 + n * 16` which can be seen here: https://gcc.godbolt.org/z/WxeqWxqxY. Likewise, google's tcmalloc has finer grained allocations for all sizes from 64 - 128 bytes, meaning we also wast 8 bytes of allocation on every other allocation inside tcmalloc.

- change 'grow_by' to use precise size for the first SSO --> long allocation

The logic currently always at least doubles the capacity on growth. However, this causes any short or empty initialized string exceeding 22 bytes to be allocated to at least 48 bytes. (22 * 2 rounded up to 48). This is wasteful as there are likely plenty of strings that could be allocated into 40 (glibc) or 32 (tcmalloc) sized allocs.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155486

Files:
  libcxx/include/string
  libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp


Index: libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
===================================================================
--- libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
+++ libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -13,12 +13,9 @@
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
-#include <string>
 
-#include "test_macros.h"
-
-// alignment of the string heap buffer is hardcoded to 16
-static const std::size_t alignment = 16;
+// alignment of the string heap buffer is hard coded to 8.
+static const std::size_t alignment = 8;
 
 template <class = int>
 TEST_CONSTEXPR_CXX20 void full_size() {
Index: libcxx/include/string
===================================================================
--- libcxx/include/string
+++ libcxx/include/string
@@ -1872,7 +1872,7 @@
         _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
         size_type __align_it(size_type __s) _NOEXCEPT
             {return (__s + (__a-1)) & ~(__a-1);}
-    enum {__alignment = 16};
+    enum {__alignment = 8};
     static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     size_type __recommend(size_type __s) _NOEXCEPT
     {
@@ -2318,10 +2318,20 @@
     size_type __ms = max_size();
     if (__delta_cap > __ms - __old_cap - 1)
         __throw_length_error();
-    pointer __old_p = __get_pointer();
-    size_type __cap = __old_cap < __ms / 2 - __alignment ?
-                          __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) :
-                          __ms - 1;
+    pointer __old_p;
+    size_type __cap;
+    if (__is_long()) {
+        __old_p = __get_long_pointer();
+        __cap   = __old_cap < __ms / 2 - __alignment
+                    ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap))
+                    : __ms - 1;
+    } else {
+        // On first allocation SSO -> long, do not apply a minimum doubling
+        // of capacity/ This results in a minimum allocation size of 48 and we
+        // only need to guarantee amortized growth on subsequent growth.
+        __old_p = __get_short_pointer();
+        __cap   = __recommend(__old_cap + __delta_cap);
+    }
     auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
     pointer __p = __allocation.ptr;
     __begin_lifetime(__p, __allocation.count);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D155486.541093.patch
Type: text/x-patch
Size: 2377 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20230717/a131efdd/attachment.bin>


More information about the libcxx-commits mailing list