[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:
Kostya Kortchinsky 2019-09-11 14:48:41 +00:00
parent 5957a61ff8
commit 161cca266a
5 changed files with 44 additions and 15 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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).

View File

@ -12,6 +12,7 @@
#include <limits.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" {