summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2019-09-11 14:48:41 +0000
committerKostya Kortchinsky <kostyak@google.com>2019-09-11 14:48:41 +0000
commitbc5544f437b576ea40b5008e44f93a03844a9423 (patch)
tree41db93cc5390a16c5d7bfe7bf1488f691e4d227e
parent460c5df7e72dc468923186dde9f8c3e45d0f54b2 (diff)
downloadcompiler-rt-bc5544f437b576ea40b5008e44f93a03844a9423.tar.gz
[scudo][standalone] Android related improvements
Summary: This changes a few things to improve memory footprint and performances on Android, and fixes a test compilation error: - add `stdlib.h` to `wrappers_c_test.cc` to address https://bugs.llvm.org/show_bug.cgi?id=42810 - change Android size class maps, based on benchmarks, to improve performances and lower the Svelte memory footprint. Also change the 32-bit region size for said configuration - change the `reallocate` logic to reallocate in place for sizes larger than the original chunk size, when they still fit in the same block. This addresses patterns from `memory_replay` dumps like the following: ``` 202: realloc 0xb48fd000 0xb4930650 12352 202: realloc 0xb48fd000 0xb48fd000 12420 202: realloc 0xb48fd000 0xb48fd000 12492 202: realloc 0xb48fd000 0xb48fd000 12564 202: realloc 0xb48fd000 0xb48fd000 12636 202: realloc 0xb48fd000 0xb48fd000 12708 202: realloc 0xb48fd000 0xb48fd000 12780 202: realloc 0xb48fd000 0xb48fd000 12852 202: realloc 0xb48fd000 0xb48fd000 12924 202: realloc 0xb48fd000 0xb48fd000 12996 202: realloc 0xb48fd000 0xb48fd000 13068 202: realloc 0xb48fd000 0xb48fd000 13140 202: realloc 0xb48fd000 0xb48fd000 13212 202: realloc 0xb48fd000 0xb48fd000 13284 202: realloc 0xb48fd000 0xb48fd000 13356 202: realloc 0xb48fd000 0xb48fd000 13428 202: realloc 0xb48fd000 0xb48fd000 13500 202: realloc 0xb48fd000 0xb48fd000 13572 202: realloc 0xb48fd000 0xb48fd000 13644 202: realloc 0xb48fd000 0xb48fd000 13716 202: realloc 0xb48fd000 0xb48fd000 13788 ... ``` In this situation we were deallocating the old chunk, and allocating a new one for every single one of those, but now we can keep the same chunk (we just updated the header), which saves some heap operations. Reviewers: hctim, morehouse, vitalybuka, eugenis, cferris, rengolin Reviewed By: morehouse Subscribers: srhines, delcypher, #sanitizers, llvm-commits Tags: #llvm, #sanitizers Differential Revision: https://reviews.llvm.org/D67293 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@371628 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/scudo/standalone/allocator_config.h4
-rw-r--r--lib/scudo/standalone/combined.h33
-rw-r--r--lib/scudo/standalone/size_class_map.h6
-rw-r--r--lib/scudo/standalone/tests/combined_test.cpp15
-rw-r--r--lib/scudo/standalone/tests/wrappers_c_test.cpp1
5 files changed, 44 insertions, 15 deletions
diff --git a/lib/scudo/standalone/allocator_config.h b/lib/scudo/standalone/allocator_config.h
index 06ec4f3f7..62c6f2875 100644
--- a/lib/scudo/standalone/allocator_config.h
+++ b/lib/scudo/standalone/allocator_config.h
@@ -53,8 +53,8 @@ struct AndroidSvelteConfig {
// 512MB regions
typedef SizeClassAllocator64<SizeClassMap, 29U> Primary;
#else
- // 256KB regions
- typedef SizeClassAllocator32<SizeClassMap, 18U> Primary;
+ // 64KB regions
+ typedef SizeClassAllocator32<SizeClassMap, 16U> Primary;
#endif
template <class A>
using TSDRegistryT = TSDRegistrySharedT<A, 1U>; // Shared, only 1 TSD.
diff --git a/lib/scudo/standalone/combined.h b/lib/scudo/standalone/combined.h
index 05a4ebcdf..b2dc25f78 100644
--- a/lib/scudo/standalone/combined.h
+++ b/lib/scudo/standalone/combined.h
@@ -311,18 +311,30 @@ public:
OldHeader.Origin, Chunk::Origin::Malloc);
}
- const uptr OldSize = getSize(OldPtr, &OldHeader);
- // If the new size is identical to the old one, or lower but within an
- // acceptable range, we just keep the old chunk, and update its header.
- if (UNLIKELY(NewSize == OldSize))
- return OldPtr;
- if (NewSize < OldSize) {
- const uptr Delta = OldSize - NewSize;
- if (Delta < (SizeClassMap::MaxSize / 2)) {
+ void *BlockBegin = getBlockBegin(OldPtr, &OldHeader);
+ uptr BlockEnd;
+ uptr OldSize;
+ const uptr ClassId = OldHeader.ClassId;
+ if (LIKELY(ClassId)) {
+ BlockEnd = reinterpret_cast<uptr>(BlockBegin) +
+ SizeClassMap::getSizeByClassId(ClassId);
+ OldSize = OldHeader.SizeOrUnusedBytes;
+ } else {
+ BlockEnd = SecondaryT::getBlockEnd(BlockBegin);
+ OldSize = BlockEnd -
+ (reinterpret_cast<uptr>(OldPtr) + OldHeader.SizeOrUnusedBytes);
+ }
+ // If the new chunk still fits in the previously allocated block (with a
+ // reasonable delta), we just keep the old block, and update the chunk
+ // header to reflect the size change.
+ if (reinterpret_cast<uptr>(OldPtr) + NewSize <= BlockEnd) {
+ const uptr Delta =
+ OldSize < NewSize ? NewSize - OldSize : OldSize - NewSize;
+ if (Delta <= SizeClassMap::MaxSize / 2) {
Chunk::UnpackedHeader NewHeader = OldHeader;
NewHeader.SizeOrUnusedBytes =
- (OldHeader.ClassId ? NewHeader.SizeOrUnusedBytes - Delta
- : NewHeader.SizeOrUnusedBytes + Delta) &
+ (ClassId ? NewSize
+ : BlockEnd - (reinterpret_cast<uptr>(OldPtr) + NewSize)) &
Chunk::SizeOrUnusedBytesMask;
Chunk::compareExchangeHeader(Cookie, OldPtr, &NewHeader, &OldHeader);
return OldPtr;
@@ -335,6 +347,7 @@ public:
// are currently unclear.
void *NewPtr = allocate(NewSize, Chunk::Origin::Malloc, Alignment);
if (NewPtr) {
+ const uptr OldSize = getSize(OldPtr, &OldHeader);
memcpy(NewPtr, OldPtr, Min(NewSize, OldSize));
quarantineOrDeallocateChunk(OldPtr, &OldHeader, OldSize);
}
diff --git a/lib/scudo/standalone/size_class_map.h b/lib/scudo/standalone/size_class_map.h
index fa52e6d9b..3b494afb3 100644
--- a/lib/scudo/standalone/size_class_map.h
+++ b/lib/scudo/standalone/size_class_map.h
@@ -137,11 +137,11 @@ typedef SizeClassMap<3, 5, 8, 17, 8, 10> DefaultSizeClassMap;
// TODO(kostyak): further tune class maps for Android & Fuchsia.
#if SCUDO_WORDSIZE == 64U
-typedef SizeClassMap<3, 5, 8, 15, 8, 10> SvelteSizeClassMap;
+typedef SizeClassMap<4, 4, 8, 14, 4, 10> SvelteSizeClassMap;
typedef SizeClassMap<3, 5, 8, 17, 14, 14> AndroidSizeClassMap;
#else
-typedef SizeClassMap<3, 4, 7, 15, 8, 10> SvelteSizeClassMap;
-typedef SizeClassMap<3, 4, 7, 17, 14, 14> AndroidSizeClassMap;
+typedef SizeClassMap<4, 3, 7, 14, 5, 10> SvelteSizeClassMap;
+typedef SizeClassMap<3, 5, 8, 17, 14, 14> AndroidSizeClassMap;
#endif
} // namespace scudo
diff --git a/lib/scudo/standalone/tests/combined_test.cpp b/lib/scudo/standalone/tests/combined_test.cpp
index c8801f955..c9c65690a 100644
--- a/lib/scudo/standalone/tests/combined_test.cpp
+++ b/lib/scudo/standalone/tests/combined_test.cpp
@@ -97,6 +97,21 @@ template <class Config> static void testAllocator() {
}
Allocator->deallocate(P, Origin);
+ // Check that reallocating a chunk to a slightly smaller or larger size
+ // returns the same chunk. This requires that all the sizes we iterate on use
+ // the same block size, but that should be the case for 2048 with our default
+ // class size maps.
+ P = Allocator->allocate(DataSize, Origin);
+ memset(P, Marker, DataSize);
+ for (scudo::sptr Delta = -32; Delta < 32; Delta += 8) {
+ const scudo::uptr NewSize = DataSize + Delta;
+ void *NewP = Allocator->reallocate(P, NewSize);
+ EXPECT_EQ(NewP, P);
+ for (scudo::uptr I = 0; I < scudo::Min(DataSize, NewSize); I++)
+ EXPECT_EQ((reinterpret_cast<char *>(NewP))[I], Marker);
+ }
+ Allocator->deallocate(P, Origin);
+
// Allocates a bunch of chunks, then iterate over all the chunks, ensuring
// they are the ones we allocated. This requires the allocator to not have any
// other allocated chunk at this point (eg: won't work with the Quarantine).
diff --git a/lib/scudo/standalone/tests/wrappers_c_test.cpp b/lib/scudo/standalone/tests/wrappers_c_test.cpp
index 6d6bbbf61..28c21ebc8 100644
--- a/lib/scudo/standalone/tests/wrappers_c_test.cpp
+++ b/lib/scudo/standalone/tests/wrappers_c_test.cpp
@@ -12,6 +12,7 @@
#include <limits.h>
#include <malloc.h>
+#include <stdlib.h>
#include <unistd.h>
extern "C" {