forked from OSchip/llvm-project
[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 llvm-svn: 371628
This commit is contained in:
parent
5957a61ff8
commit
161cca266a
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <limits.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" {
|
||||
|
|
Loading…
Reference in New Issue