[tsan] add metadata to the new tsan allocator

llvm-svn: 159002
This commit is contained in:
Kostya Serebryany 2012-06-22 16:13:28 +00:00
parent 052f60d384
commit 278ccdacdc
2 changed files with 58 additions and 6 deletions

View File

@ -96,10 +96,12 @@ class SizeClassAllocator64 {
CHECK_EQ(AllocBeg(), reinterpret_cast<uptr>(MmapFixedNoReserve(
AllocBeg(), AllocSize())));
}
NOINLINE
void *Allocate(uptr size) {
CHECK_LE(size, SizeClassMap::kMaxSize);
return AllocateBySizeClass(SizeClassMap::ClassID(size));
}
NOINLINE
void Deallocate(void *p) {
DeallocateBySizeClass(p, GetSizeClass(p));
}
@ -110,6 +112,13 @@ class SizeClassAllocator64 {
return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
}
uptr GetMetaData(void *p) {
uptr class_id = GetSizeClass(p);
uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), class_id);
return kSpaceBeg + (kRegionSize * (class_id + 1)) -
(1 + chunk_idx) * kMetadataSize;
}
uptr TotalMemoryUsedIncludingFreeLists() {
uptr res = 0;
for (uptr i = 0; i < kNumClasses; i++)
@ -125,6 +134,7 @@ class SizeClassAllocator64 {
static const uptr kNumClasses = 256; // Power of two <= 256
COMPILER_CHECK(kNumClasses <= SizeClassMap::kNumClasses);
static const uptr kRegionSize = kSpaceSize / kNumClasses;
COMPILER_CHECK((kRegionSize >> 32) > 0); // kRegionSize must be >= 2^32.
// Populate the free list with at most this number of bytes at once
// or with one element if its size is greater.
static const uptr kPopulateSize = 1 << 18;
@ -163,6 +173,14 @@ class SizeClassAllocator64 {
return res;
}
uptr GetChunkIdx(uptr chunk, uptr class_id) {
u32 offset = chunk % kRegionSize;
// Here we divide by a non-constant. This is costly.
// We require that kRegionSize is at least 2^32 so that offset is 32-bit.
// We save 2x by using 32-bit div, but may need to use a 256-way switch.
return offset / (u32)SizeClassMap::Size(class_id);
}
LifoListNode *PopulateFreeList(uptr class_id, RegionInfo *region) {
uptr size = SizeClassMap::Size(class_id);
uptr beg_idx = region->allocated;

View File

@ -47,13 +47,13 @@ TEST(SanitizerCommon, DefaultSizeClassMap) {
}
}
static const uptr kAllocatorSpace = 0x600000000000ULL;
static const uptr kAllocatorSize = 0x10000000000; // 1T.
TEST(SanitizerCommon, SizeClassAllocator64) {
const uptr space_beg = 0x600000000000ULL;
const uptr space_size = 0x10000000000; // 1T
const uptr metadata_size = 16;
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<space_beg, space_size,
metadata_size, SCMap> Allocator;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> Allocator;
Allocator a;
a.Init();
@ -76,11 +76,18 @@ TEST(SanitizerCommon, SizeClassAllocator64) {
CHECK(a.PointerIsMine(x));
uptr class_id = a.GetSizeClass(x);
CHECK_EQ(class_id, SCMap::ClassID(size));
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
metadata[0] = reinterpret_cast<uptr>(x) + 1;
metadata[1] = 0xABCD;
}
}
// Deallocate all.
for (uptr i = 0; i < allocated.size(); i++) {
a.Deallocate(allocated[i]);
void *x = allocated[i];
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
CHECK_EQ(metadata[1], 0xABCD);
a.Deallocate(x);
}
allocated.clear();
uptr total_allocated = a.TotalMemoryUsedIncludingFreeLists();
@ -91,3 +98,30 @@ TEST(SanitizerCommon, SizeClassAllocator64) {
a.TestOnlyUnmap();
}
TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> Allocator;
Allocator a;
a.Init();
static volatile uptr sink;
const uptr kNumAllocs = 10000;
void *allocated[kNumAllocs];
for (uptr i = 0; i < kNumAllocs; i++) {
uptr size = (i % 4096) + 1;
void *x = a.Allocate(size);
allocated[i] = x;
}
// Get Metadata kNumAllocs^2 times.
for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
sink = a.GetMetaData(allocated[i % kNumAllocs]);
}
for (uptr i = 0; i < kNumAllocs; i++) {
a.Deallocate(allocated[i]);
}
a.TestOnlyUnmap();
}