forked from OSchip/llvm-project
[sanitizer] factor out ByteMap from SizeClassAllocator32 so that it can be later replaced with a more memory-efficient implementation on 64-bit.
llvm-svn: 182234
This commit is contained in:
parent
29699c6365
commit
3469375e4f
|
@ -69,8 +69,12 @@ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
|
||||||
#elif SANITIZER_WORDSIZE == 32
|
#elif SANITIZER_WORDSIZE == 32
|
||||||
static const u64 kAddressSpaceSize = 1ULL << 32;
|
static const u64 kAddressSpaceSize = 1ULL << 32;
|
||||||
typedef CompactSizeClassMap SizeClassMap;
|
typedef CompactSizeClassMap SizeClassMap;
|
||||||
|
static const uptr kRegionSizeLog = 20;
|
||||||
|
static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
|
||||||
typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
|
typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
|
||||||
SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
|
SizeClassMap, kRegionSizeLog,
|
||||||
|
FlatByteMap<kFlatByteMapSize>,
|
||||||
|
AsanMapUnmapCallback> PrimaryAllocator;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||||
|
|
|
@ -561,6 +561,30 @@ class SizeClassAllocator64 {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Maps integers in rage [0, kSize) to u8 values.
|
||||||
|
template<u64 kSize>
|
||||||
|
class FlatByteMap {
|
||||||
|
public:
|
||||||
|
void TestOnlyInit() {
|
||||||
|
internal_memset(map_, 0, sizeof(map_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(uptr idx, u8 val) {
|
||||||
|
CHECK_LT(idx, kSize);
|
||||||
|
CHECK_EQ(0U, map_[idx]);
|
||||||
|
map_[idx] = val;
|
||||||
|
}
|
||||||
|
u8 operator[] (uptr idx) {
|
||||||
|
CHECK_LT(idx, kSize);
|
||||||
|
// FIXME: CHECK may be too expensive here.
|
||||||
|
return map_[idx];
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
u8 map_[kSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Also implement TwoLevelByteMap.
|
||||||
|
|
||||||
// SizeClassAllocator32 -- allocator for 32-bit address space.
|
// SizeClassAllocator32 -- allocator for 32-bit address space.
|
||||||
// This allocator can theoretically be used on 64-bit arch, but there it is less
|
// This allocator can theoretically be used on 64-bit arch, but there it is less
|
||||||
// efficient than SizeClassAllocator64.
|
// efficient than SizeClassAllocator64.
|
||||||
|
@ -572,7 +596,7 @@ class SizeClassAllocator64 {
|
||||||
// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
|
// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
|
||||||
// Since the regions are aligned by kRegionSize, there are exactly
|
// Since the regions are aligned by kRegionSize, there are exactly
|
||||||
// kNumPossibleRegions possible regions in the address space and so we keep
|
// kNumPossibleRegions possible regions in the address space and so we keep
|
||||||
// an u8 array possible_regions[kNumPossibleRegions] to store the size classes.
|
// a ByteMap possible_regions to store the size classes of each Region.
|
||||||
// 0 size class means the region is not used by the allocator.
|
// 0 size class means the region is not used by the allocator.
|
||||||
//
|
//
|
||||||
// One Region is used to allocate chunks of a single size class.
|
// One Region is used to allocate chunks of a single size class.
|
||||||
|
@ -583,16 +607,19 @@ class SizeClassAllocator64 {
|
||||||
// chache-line aligned.
|
// chache-line aligned.
|
||||||
template <const uptr kSpaceBeg, const u64 kSpaceSize,
|
template <const uptr kSpaceBeg, const u64 kSpaceSize,
|
||||||
const uptr kMetadataSize, class SizeClassMap,
|
const uptr kMetadataSize, class SizeClassMap,
|
||||||
|
const uptr kRegionSizeLog,
|
||||||
|
class ByteMap,
|
||||||
class MapUnmapCallback = NoOpMapUnmapCallback>
|
class MapUnmapCallback = NoOpMapUnmapCallback>
|
||||||
class SizeClassAllocator32 {
|
class SizeClassAllocator32 {
|
||||||
public:
|
public:
|
||||||
typedef typename SizeClassMap::TransferBatch Batch;
|
typedef typename SizeClassMap::TransferBatch Batch;
|
||||||
typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
|
typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
|
||||||
SizeClassMap, MapUnmapCallback> ThisT;
|
SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
|
||||||
typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
|
typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
state_ = reinterpret_cast<State *>(MapWithCallback(sizeof(State)));
|
possible_regions.TestOnlyInit();
|
||||||
|
internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MapWithCallback(uptr size) {
|
void *MapWithCallback(uptr size) {
|
||||||
|
@ -649,7 +676,7 @@ class SizeClassAllocator32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr GetSizeClass(void *p) {
|
uptr GetSizeClass(void *p) {
|
||||||
return state_->possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
|
return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
|
||||||
}
|
}
|
||||||
|
|
||||||
void *GetBlockBegin(void *p) {
|
void *GetBlockBegin(void *p) {
|
||||||
|
@ -674,16 +701,15 @@ class SizeClassAllocator32 {
|
||||||
// No need to lock here.
|
// No need to lock here.
|
||||||
uptr res = 0;
|
uptr res = 0;
|
||||||
for (uptr i = 0; i < kNumPossibleRegions; i++)
|
for (uptr i = 0; i < kNumPossibleRegions; i++)
|
||||||
if (state_->possible_regions[i])
|
if (possible_regions[i])
|
||||||
res += kRegionSize;
|
res += kRegionSize;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestOnlyUnmap() {
|
void TestOnlyUnmap() {
|
||||||
for (uptr i = 0; i < kNumPossibleRegions; i++)
|
for (uptr i = 0; i < kNumPossibleRegions; i++)
|
||||||
if (state_->possible_regions[i])
|
if (possible_regions[i])
|
||||||
UnmapWithCallback((i * kRegionSize), kRegionSize);
|
UnmapWithCallback((i * kRegionSize), kRegionSize);
|
||||||
UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
|
// ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
|
||||||
|
@ -706,8 +732,8 @@ class SizeClassAllocator32 {
|
||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
void ForEachChunk(const Callable &callback) {
|
void ForEachChunk(const Callable &callback) {
|
||||||
for (uptr region = 0; region < kNumPossibleRegions; region++)
|
for (uptr region = 0; region < kNumPossibleRegions; region++)
|
||||||
if (state_->possible_regions[region]) {
|
if (possible_regions[region]) {
|
||||||
uptr chunk_size = SizeClassMap::Size(state_->possible_regions[region]);
|
uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
|
||||||
uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
|
uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
|
||||||
uptr region_beg = region * kRegionSize;
|
uptr region_beg = region * kRegionSize;
|
||||||
for (uptr p = region_beg;
|
for (uptr p = region_beg;
|
||||||
|
@ -726,7 +752,6 @@ class SizeClassAllocator32 {
|
||||||
static const uptr kNumClasses = SizeClassMap::kNumClasses;
|
static const uptr kNumClasses = SizeClassMap::kNumClasses;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uptr kRegionSizeLog = SANITIZER_WORDSIZE == 64 ? 24 : 20;
|
|
||||||
static const uptr kRegionSize = 1 << kRegionSizeLog;
|
static const uptr kRegionSize = 1 << kRegionSizeLog;
|
||||||
static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
|
static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
|
||||||
|
|
||||||
|
@ -754,14 +779,13 @@ class SizeClassAllocator32 {
|
||||||
MapUnmapCallback().OnMap(res, kRegionSize);
|
MapUnmapCallback().OnMap(res, kRegionSize);
|
||||||
stat->Add(AllocatorStatMmapped, kRegionSize);
|
stat->Add(AllocatorStatMmapped, kRegionSize);
|
||||||
CHECK_EQ(0U, (res & (kRegionSize - 1)));
|
CHECK_EQ(0U, (res & (kRegionSize - 1)));
|
||||||
CHECK_EQ(0U, state_->possible_regions[ComputeRegionId(res)]);
|
possible_regions.set(ComputeRegionId(res), class_id);
|
||||||
state_->possible_regions[ComputeRegionId(res)] = class_id;
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
SizeClassInfo *GetSizeClassInfo(uptr class_id) {
|
SizeClassInfo *GetSizeClassInfo(uptr class_id) {
|
||||||
CHECK_LT(class_id, kNumClasses);
|
CHECK_LT(class_id, kNumClasses);
|
||||||
return &state_->size_class_info_array[class_id];
|
return &size_class_info_array[class_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
|
void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
|
||||||
|
@ -792,12 +816,9 @@ class SizeClassAllocator32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
ByteMap possible_regions;
|
||||||
u8 possible_regions[kNumPossibleRegions];
|
|
||||||
SizeClassInfo size_class_info_array[kNumClasses];
|
SizeClassInfo size_class_info_array[kNumClasses];
|
||||||
};
|
};
|
||||||
State *state_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Objects of this type should be used as local caches for SizeClassAllocator64
|
// Objects of this type should be used as local caches for SizeClassAllocator64
|
||||||
// or SizeClassAllocator32. Since the typical use of this class is to have one
|
// or SizeClassAllocator32. Since the typical use of this class is to have one
|
||||||
|
|
|
@ -41,8 +41,16 @@ typedef SizeClassAllocator64<
|
||||||
static const u64 kAddressSpaceSize = 1ULL << 32;
|
static const u64 kAddressSpaceSize = 1ULL << 32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
|
||||||
|
static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
|
||||||
|
|
||||||
typedef SizeClassAllocator32<
|
typedef SizeClassAllocator32<
|
||||||
0, kAddressSpaceSize, 16, CompactSizeClassMap> Allocator32Compact;
|
0, kAddressSpaceSize,
|
||||||
|
/*kMetadataSize*/16,
|
||||||
|
CompactSizeClassMap,
|
||||||
|
kRegionSizeLog,
|
||||||
|
FlatByteMap<kFlatByteMapSize> >
|
||||||
|
Allocator32Compact;
|
||||||
|
|
||||||
template <class SizeClassMap>
|
template <class SizeClassMap>
|
||||||
void TestSizeClassMap() {
|
void TestSizeClassMap() {
|
||||||
|
@ -254,20 +262,25 @@ TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
|
||||||
TestMapUnmapCallback::map_count = 0;
|
TestMapUnmapCallback::map_count = 0;
|
||||||
TestMapUnmapCallback::unmap_count = 0;
|
TestMapUnmapCallback::unmap_count = 0;
|
||||||
typedef SizeClassAllocator32<
|
typedef SizeClassAllocator32<
|
||||||
0, kAddressSpaceSize, 16, CompactSizeClassMap,
|
0, kAddressSpaceSize,
|
||||||
TestMapUnmapCallback> Allocator32WithCallBack;
|
/*kMetadataSize*/16,
|
||||||
|
CompactSizeClassMap,
|
||||||
|
kRegionSizeLog,
|
||||||
|
FlatByteMap<kFlatByteMapSize>,
|
||||||
|
TestMapUnmapCallback>
|
||||||
|
Allocator32WithCallBack;
|
||||||
Allocator32WithCallBack *a = new Allocator32WithCallBack;
|
Allocator32WithCallBack *a = new Allocator32WithCallBack;
|
||||||
a->Init();
|
a->Init();
|
||||||
EXPECT_EQ(TestMapUnmapCallback::map_count, 1); // Allocator state.
|
EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
|
||||||
SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache;
|
SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache;
|
||||||
memset(&cache, 0, sizeof(cache));
|
memset(&cache, 0, sizeof(cache));
|
||||||
cache.Init(0);
|
cache.Init(0);
|
||||||
AllocatorStats stats;
|
AllocatorStats stats;
|
||||||
stats.Init();
|
stats.Init();
|
||||||
a->AllocateBatch(&stats, &cache, 32);
|
a->AllocateBatch(&stats, &cache, 32);
|
||||||
EXPECT_EQ(TestMapUnmapCallback::map_count, 2); // alloc.
|
EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
|
||||||
a->TestOnlyUnmap();
|
a->TestOnlyUnmap();
|
||||||
EXPECT_EQ(TestMapUnmapCallback::unmap_count, 2); // The whole thing + alloc.
|
EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
|
||||||
delete a;
|
delete a;
|
||||||
// fprintf(stderr, "Map: %d Unmap: %d\n",
|
// fprintf(stderr, "Map: %d Unmap: %d\n",
|
||||||
// TestMapUnmapCallback::map_count,
|
// TestMapUnmapCallback::map_count,
|
||||||
|
|
Loading…
Reference in New Issue