Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit ebe842d

Browse files
committed
[AArch64] Speed-up leak and address sanitizers on AArch64 for 48-bit VMA
This patch fixes google/sanitizers#703 On a Graviton-A1 aarch64 machine with 48-bit VMA, the time spent in LSan and ASan reduced from 2.5s to 0.01s when running clang -fsanitize=leak compiler-rt/test/lsan/TestCases/sanity_check_pure_c.c && time ./a.out clang -fsanitize=address compiler-rt/test/lsan/TestCases/sanity_check_pure_c.c && time ./a.out With this patch, LSan and ASan create both the 32 and 64 allocators and select at run time between the two allocators following a global variable that is initialized at init time to whether the allocator64 can be used in the virtual address space. Differential Revision: https://reviews.llvm.org/D60243 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@369441 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 90850a3 commit ebe842d

11 files changed

+346
-38
lines changed

lib/asan/asan_allocator.cpp

+6-8
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ static u32 RZSize2Log(u32 rz_size) {
4848
return res;
4949
}
5050

51-
static AsanAllocator &get_allocator();
52-
5351
// The memory chunk allocated from the underlying allocator looks like this:
5452
// L L L L L L H H U U U U U U R R
5553
// L -- left redzone words (0 or more bytes)
@@ -113,7 +111,7 @@ enum {
113111
struct AsanChunk: ChunkBase {
114112
uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
115113
uptr UsedSize(bool locked_version = false) {
116-
if (user_requested_size != SizeClassMap::kMaxSize)
114+
if (user_requested_size != get_allocator().KMaxSize())
117115
return user_requested_size;
118116
return *reinterpret_cast<uptr *>(
119117
get_allocator().GetMetaData(AllocBeg(locked_version)));
@@ -430,7 +428,7 @@ struct Allocator {
430428
bool using_primary_allocator = true;
431429
// If we are allocating from the secondary allocator, there will be no
432430
// automatic right redzone, so add the right redzone manually.
433-
if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) {
431+
if (!get_allocator().CanAllocate(needed_size, alignment)) {
434432
needed_size += rz_size;
435433
using_primary_allocator = false;
436434
}
@@ -499,7 +497,7 @@ struct Allocator {
499497
CHECK(allocator.FromPrimary(allocated));
500498
} else {
501499
CHECK(!allocator.FromPrimary(allocated));
502-
m->user_requested_size = SizeClassMap::kMaxSize;
500+
m->user_requested_size = get_allocator().KMaxSize();
503501
uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
504502
meta[0] = size;
505503
meta[1] = chunk_beg;
@@ -524,10 +522,10 @@ struct Allocator {
524522
thread_stats.mallocs++;
525523
thread_stats.malloced += size;
526524
thread_stats.malloced_redzones += needed_size - size;
527-
if (needed_size > SizeClassMap::kMaxSize)
525+
if (needed_size > get_allocator().KMaxSize())
528526
thread_stats.malloc_large++;
529527
else
530-
thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++;
528+
thread_stats.malloced_by_size[get_allocator().ClassID(needed_size)]++;
531529

532530
void *res = reinterpret_cast<void *>(user_beg);
533531
if (can_fill && fl.max_malloc_fill_size) {
@@ -791,7 +789,7 @@ struct Allocator {
791789

792790
static Allocator instance(LINKER_INITIALIZED);
793791

794-
static AsanAllocator &get_allocator() {
792+
AsanAllocator &get_allocator() {
795793
return instance.allocator;
796794
}
797795

lib/asan/asan_allocator.h

+59-22
Original file line numberDiff line numberDiff line change
@@ -118,39 +118,76 @@ struct AsanMapUnmapCallback {
118118
void OnUnmap(uptr p, uptr size) const;
119119
};
120120

121-
#if SANITIZER_CAN_USE_ALLOCATOR64
121+
#if defined(__aarch64__)
122+
// AArch64 supports 39, 42 and 48-bit VMA.
123+
const uptr kAllocatorSpace = ~(uptr)0;
124+
#if SANITIZER_ANDROID
125+
const uptr kAllocatorSize = 0x2000000000ULL; // 128G.
126+
typedef VeryCompactSizeClassMap SizeClassMap64;
127+
#else
128+
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
129+
typedef DefaultSizeClassMap SizeClassMap64;
130+
#endif
131+
132+
template <typename AddressSpaceViewTy>
133+
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
134+
static const uptr kSpaceBeg = kAllocatorSpace;
135+
static const uptr kSpaceSize = kAllocatorSize;
136+
static const uptr kMetadataSize = 0;
137+
typedef __asan::SizeClassMap64 SizeClassMap;
138+
typedef AsanMapUnmapCallback MapUnmapCallback;
139+
static const uptr kFlags = 0;
140+
using AddressSpaceView = AddressSpaceViewTy;
141+
};
142+
template <typename AddressSpaceView>
143+
using Allocator64ASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
144+
using Allocator64 = Allocator64ASVT<LocalAddressSpaceView>;
145+
146+
typedef CompactSizeClassMap SizeClassMap32;
147+
template <typename AddressSpaceViewTy>
148+
struct AP32 {
149+
static const uptr kSpaceBeg = 0;
150+
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
151+
static const uptr kMetadataSize = 16;
152+
typedef __asan::SizeClassMap32 SizeClassMap;
153+
static const uptr kRegionSizeLog = 20;
154+
using AddressSpaceView = AddressSpaceViewTy;
155+
typedef AsanMapUnmapCallback MapUnmapCallback;
156+
static const uptr kFlags = 0;
157+
};
158+
template <typename AddressSpaceView>
159+
using Allocator32ASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
160+
using Allocator32 = Allocator32ASVT<LocalAddressSpaceView>;
161+
using Allocator32or64 = RuntimeSelectAllocator<Allocator32, Allocator64>;
162+
163+
static const uptr kMaxNumberOfSizeClasses =
164+
SizeClassMap32::kNumClasses < SizeClassMap64::kNumClasses
165+
? SizeClassMap64::kNumClasses
166+
: SizeClassMap32::kNumClasses;
167+
168+
template <typename AddressSpaceView>
169+
using PrimaryAllocatorASVT =
170+
RuntimeSelectAllocator<Allocator32ASVT<AddressSpaceView>,
171+
Allocator64ASVT<AddressSpaceView>>;
172+
#elif SANITIZER_CAN_USE_ALLOCATOR64
122173
# if SANITIZER_FUCHSIA
123174
const uptr kAllocatorSpace = ~(uptr)0;
124175
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
125-
typedef DefaultSizeClassMap SizeClassMap;
126176
# elif defined(__powerpc64__)
127177
const uptr kAllocatorSpace = ~(uptr)0;
128178
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
129-
typedef DefaultSizeClassMap SizeClassMap;
130-
# elif defined(__aarch64__) && SANITIZER_ANDROID
131-
// Android needs to support 39, 42 and 48 bit VMA.
132-
const uptr kAllocatorSpace = ~(uptr)0;
133-
const uptr kAllocatorSize = 0x2000000000ULL; // 128G.
134-
typedef VeryCompactSizeClassMap SizeClassMap;
135-
# elif defined(__aarch64__)
136-
// AArch64/SANITIZER_CAN_USE_ALLOCATOR64 is only for 42-bit VMA
137-
// so no need to different values for different VMA.
138-
const uptr kAllocatorSpace = 0x10000000000ULL;
139-
const uptr kAllocatorSize = 0x10000000000ULL; // 3T.
140-
typedef DefaultSizeClassMap SizeClassMap;
141-
#elif defined(__sparc__)
179+
# elif defined(__sparc__)
142180
const uptr kAllocatorSpace = ~(uptr)0;
143181
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
144-
typedef DefaultSizeClassMap SizeClassMap;
145182
# elif SANITIZER_WINDOWS
146183
const uptr kAllocatorSpace = ~(uptr)0;
147184
const uptr kAllocatorSize = 0x8000000000ULL; // 500G
148-
typedef DefaultSizeClassMap SizeClassMap;
149185
# else
150186
const uptr kAllocatorSpace = 0x600000000000ULL;
151187
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
152-
typedef DefaultSizeClassMap SizeClassMap;
153188
# endif
189+
typedef DefaultSizeClassMap SizeClassMap;
190+
static const uptr kMaxNumberOfSizeClasses = SizeClassMap::kNumClasses;
154191
template <typename AddressSpaceViewTy>
155192
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
156193
static const uptr kSpaceBeg = kAllocatorSpace;
@@ -164,9 +201,9 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
164201

165202
template <typename AddressSpaceView>
166203
using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
167-
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
168204
#else // Fallback to SizeClassAllocator32.
169205
typedef CompactSizeClassMap SizeClassMap;
206+
static const uptr kMaxNumberOfSizeClasses = SizeClassMap::kNumClasses;
170207
template <typename AddressSpaceViewTy>
171208
struct AP32 {
172209
static const uptr kSpaceBeg = 0;
@@ -180,16 +217,14 @@ struct AP32 {
180217
};
181218
template <typename AddressSpaceView>
182219
using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;
183-
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
184220
#endif // SANITIZER_CAN_USE_ALLOCATOR64
185221

186-
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
187-
188222
template <typename AddressSpaceView>
189223
using AsanAllocatorASVT =
190224
CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>>;
191225
using AsanAllocator = AsanAllocatorASVT<LocalAddressSpaceView>;
192226
using AllocatorCache = AsanAllocator::AllocatorCache;
227+
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
193228

194229
struct AsanThreadLocalMallocStorage {
195230
uptr quarantine_cache[16];
@@ -226,5 +261,7 @@ void asan_mz_force_unlock();
226261
void PrintInternalAllocatorStats();
227262
void AsanSoftRssLimitExceededCallback(bool exceeded);
228263

264+
AsanAllocator &get_allocator();
265+
229266
} // namespace __asan
230267
#endif // ASAN_ALLOCATOR_H

lib/asan/asan_stats.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
// Code related to statistics collected by AddressSanitizer.
1212
//===----------------------------------------------------------------------===//
13+
#include "asan_allocator.h"
1314
#include "asan_interceptors.h"
1415
#include "asan_internal.h"
1516
#include "asan_stats.h"
@@ -30,9 +31,9 @@ void AsanStats::Clear() {
3031
}
3132

3233
static void PrintMallocStatsArray(const char *prefix,
33-
uptr (&array)[kNumberOfSizeClasses]) {
34+
uptr *array, uptr size) {
3435
Printf("%s", prefix);
35-
for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
36+
for (uptr i = 0; i < size; i++) {
3637
if (!array[i]) continue;
3738
Printf("%zu:%zu; ", i, array[i]);
3839
}
@@ -50,7 +51,8 @@ void AsanStats::Print() {
5051
(mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
5152
mmaps, munmaps);
5253

53-
PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
54+
PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size,
55+
get_allocator().KMaxSize());
5456
Printf("Stats: malloc large: %zu\n", malloc_large);
5557
}
5658

lib/asan/asan_stats.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct AsanStats {
3838
uptr munmaps;
3939
uptr munmaped;
4040
uptr malloc_large;
41-
uptr malloced_by_size[kNumberOfSizeClasses];
41+
uptr malloced_by_size[kMaxNumberOfSizeClasses];
4242

4343
// Ctor for global AsanStats (accumulated stats for dead threads).
4444
explicit AsanStats(LinkerInitialized) { }

lib/lsan/lsan_allocator.h

+41-4
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,46 @@ struct ChunkMetadata {
4949
u32 stack_trace_id;
5050
};
5151

52-
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
53-
defined(__arm__)
52+
#if defined(__aarch64__)
53+
template <typename AddressSpaceViewTy>
54+
struct AP32 {
55+
static const uptr kSpaceBeg = 0;
56+
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
57+
static const uptr kMetadataSize = sizeof(ChunkMetadata);
58+
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
59+
static const uptr kRegionSizeLog = 20;
60+
using AddressSpaceView = AddressSpaceViewTy;
61+
typedef NoOpMapUnmapCallback MapUnmapCallback;
62+
static const uptr kFlags = 0;
63+
};
64+
65+
const uptr kAllocatorSpace = 0x600000000000ULL;
66+
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
67+
68+
template <typename AddressSpaceViewTy>
69+
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
70+
static const uptr kSpaceBeg = kAllocatorSpace;
71+
static const uptr kSpaceSize = kAllocatorSize;
72+
static const uptr kMetadataSize = sizeof(ChunkMetadata);
73+
typedef DefaultSizeClassMap SizeClassMap;
74+
typedef NoOpMapUnmapCallback MapUnmapCallback;
75+
static const uptr kFlags = 0;
76+
using AddressSpaceView = AddressSpaceViewTy;
77+
};
78+
79+
template <typename AddressSpaceView>
80+
using Allocator32ASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
81+
template <typename AddressSpaceView>
82+
using Allocator64ASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
83+
84+
using Allocator32 = Allocator32ASVT<LocalAddressSpaceView>;
85+
using Allocator64 = Allocator64ASVT<LocalAddressSpaceView>;
86+
87+
template <typename AddressSpaceView>
88+
using PrimaryAllocatorASVT =
89+
RuntimeSelectAllocator<Allocator32ASVT<AddressSpaceView>,
90+
Allocator64ASVT<AddressSpaceView>>;
91+
#elif defined(__mips64) || defined(__i386__) || defined(__arm__)
5492
template <typename AddressSpaceViewTy>
5593
struct AP32 {
5694
static const uptr kSpaceBeg = 0;
@@ -64,7 +102,6 @@ struct AP32 {
64102
};
65103
template <typename AddressSpaceView>
66104
using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
67-
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
68105
#elif defined(__x86_64__) || defined(__powerpc64__)
69106
# if defined(__powerpc64__)
70107
const uptr kAllocatorSpace = 0xa0000000000ULL;
@@ -86,13 +123,13 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
86123

87124
template <typename AddressSpaceView>
88125
using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
89-
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
90126
#endif
91127

92128
template <typename AddressSpaceView>
93129
using AllocatorASVT = CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>>;
94130
using Allocator = AllocatorASVT<LocalAddressSpaceView>;
95131
using AllocatorCache = Allocator::AllocatorCache;
132+
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
96133

97134
Allocator::AllocatorCache *GetAllocatorCache();
98135

lib/sanitizer_common/sanitizer_allocator.h

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) {
7575
#include "sanitizer_allocator_local_cache.h"
7676
#include "sanitizer_allocator_secondary.h"
7777
#include "sanitizer_allocator_combined.h"
78+
#include "sanitizer_runtime_select_allocator.h"
7879

7980
} // namespace __sanitizer
8081

lib/sanitizer_common/sanitizer_allocator_combined.h

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class CombinedAllocator {
4141
secondary_.Init();
4242
}
4343

44+
bool CanAllocate(uptr size, uptr alignment) {
45+
return primary_.CanAllocate(size, alignment);
46+
}
47+
4448
void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
4549
// Returning 0 on malloc(0) may break a lot of code.
4650
if (size == 0)
@@ -194,6 +198,10 @@ class CombinedAllocator {
194198
secondary_.ForEachChunk(callback, arg);
195199
}
196200

201+
uptr KNumClasses() { return primary_.KNumClasses(); }
202+
uptr KMaxSize() { return primary_.KMaxSize(); }
203+
uptr ClassID(uptr size) { return primary_.ClassID(size); }
204+
197205
private:
198206
PrimaryAllocator primary_;
199207
SecondaryAllocator secondary_;

lib/sanitizer_common/sanitizer_allocator_primary32.h

+3
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ class SizeClassAllocator32 {
271271
typedef SizeClassMap SizeClassMapT;
272272
static const uptr kNumClasses = SizeClassMap::kNumClasses;
273273

274+
static uptr KNumClasses() { return SizeClassMap::kNumClasses; }
275+
static uptr KMaxSize() { return SizeClassMap::kMaxSize; }
276+
274277
private:
275278
static const uptr kRegionSize = 1 << kRegionSizeLog;
276279
static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;

lib/sanitizer_common/sanitizer_allocator_primary64.h

+3
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ class SizeClassAllocator64 {
319319
static const uptr kNumClasses = SizeClassMap::kNumClasses;
320320
static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
321321

322+
static uptr KNumClasses() { return SizeClassMap::kNumClasses; }
323+
static uptr KMaxSize() { return SizeClassMap::kMaxSize; }
324+
322325
// A packed array of counters. Each counter occupies 2^n bits, enough to store
323326
// counter's max_value. Ctor will try to allocate the required buffer via
324327
// mapper->MapPackedCounterArrayBuffer and the caller is expected to check

0 commit comments

Comments
 (0)