[sanitizer] use fewer size classes in the allocator to reduce the memory footprint. There is no all-size-fits-all constant here, but this change is positive or neutral on several large apps I've tested

llvm-svn: 176855
This commit is contained in:
Kostya Serebryany 2013-03-12 08:44:40 +00:00
parent 26d5bc7fdf
commit 138b155042
2 changed files with 30 additions and 28 deletions

View File

@ -26,15 +26,15 @@ namespace __sanitizer {
// SizeClassMap maps allocation sizes into size classes and back. // SizeClassMap maps allocation sizes into size classes and back.
// Class 0 corresponds to size 0. // Class 0 corresponds to size 0.
// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16). // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
// Next 8 classes: 256 + i * 32 (i = 1 to 8). // Next 4 classes: 256 + i * 64 (i = 1 to 4).
// Next 8 classes: 512 + i * 64 (i = 1 to 8). // Next 4 classes: 512 + i * 128 (i = 1 to 4).
// ... // ...
// Next 8 classes: 2^k + i * 2^(k-3) (i = 1 to 8). // Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4).
// Last class corresponds to kMaxSize = 1 << kMaxSizeLog. // Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
// //
// This structure of the size class map gives us: // This structure of the size class map gives us:
// - Efficient table-free class-to-size and size-to-class functions. // - Efficient table-free class-to-size and size-to-class functions.
// - Difference between two consequent size classes is betweed 12% and 6% // - Difference between two consequent size classes is betweed 14% and 25%
// //
// This class also gives a hint to a thread-caching allocator about the amount // This class also gives a hint to a thread-caching allocator about the amount
// of chunks that need to be cached per-thread: // of chunks that need to be cached per-thread:
@ -61,24 +61,28 @@ namespace __sanitizer {
// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15 // c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
// //
// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16 // c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
// c17 => s: 288 diff: +32 12% l 8 cached: 227 65376; id 17 // c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17
// c18 => s: 320 diff: +32 11% l 8 cached: 204 65280; id 18 // c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18
// c19 => s: 352 diff: +32 10% l 8 cached: 186 65472; id 19 // c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19
// c20 => s: 384 diff: +32 09% l 8 cached: 170 65280; id 20
// c21 => s: 416 diff: +32 08% l 8 cached: 157 65312; id 21
// c22 => s: 448 diff: +32 07% l 8 cached: 146 65408; id 22
// c23 => s: 480 diff: +32 07% l 8 cached: 136 65280; id 23
// //
// c24 => s: 512 diff: +32 06% l 9 cached: 128 65536; id 24 // c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20
// c25 => s: 576 diff: +64 12% l 9 cached: 113 65088; id 25 // c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21
// c26 => s: 640 diff: +64 11% l 9 cached: 102 65280; id 26 // c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22
// c27 => s: 704 diff: +64 10% l 9 cached: 93 65472; id 27 // c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23
// c28 => s: 768 diff: +64 09% l 9 cached: 85 65280; id 28
// c29 => s: 832 diff: +64 08% l 9 cached: 78 64896; id 29
// c30 => s: 896 diff: +64 07% l 9 cached: 73 65408; id 30
// c31 => s: 960 diff: +64 07% l 9 cached: 68 65280; id 31
// //
// c32 => s: 1024 diff: +64 06% l 10 cached: 64 65536; id 32 // c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24
// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25
// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26
// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27
//
// ...
//
// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48
// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49
// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50
// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51
//
// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog> template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog>
class SizeClassMap { class SizeClassMap {
@ -87,7 +91,7 @@ class SizeClassMap {
static const uptr kMinSize = 1 << kMinSizeLog; static const uptr kMinSize = 1 << kMinSizeLog;
static const uptr kMidSize = 1 << kMidSizeLog; static const uptr kMidSize = 1 << kMidSizeLog;
static const uptr kMidClass = kMidSize / kMinSize; static const uptr kMidClass = kMidSize / kMinSize;
static const uptr S = 3; static const uptr S = 2;
static const uptr M = (1 << S) - 1; static const uptr M = (1 << S) - 1;
public: public:
@ -185,10 +189,8 @@ class SizeClassMap {
} }
}; };
typedef SizeClassMap<17, 256, 16> typedef SizeClassMap<17, 256, 16> DefaultSizeClassMap;
DefaultSizeClassMap; typedef SizeClassMap<17, 64, 14> CompactSizeClassMap;
typedef SizeClassMap<17, 64, 14>
CompactSizeClassMap;
template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache; template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
// Memory allocator statistics // Memory allocator statistics

View File

@ -203,7 +203,7 @@ TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) {
cache.Init(0); cache.Init(0);
AllocatorStats stats; AllocatorStats stats;
stats.Init(); stats.Init();
a->AllocateBatch(&stats, &cache, 64); a->AllocateBatch(&stats, &cache, 32);
EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata. EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata.
a->TestOnlyUnmap(); a->TestOnlyUnmap();
EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing. EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing.
@ -225,7 +225,7 @@ TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
cache.Init(0); cache.Init(0);
AllocatorStats stats; AllocatorStats stats;
stats.Init(); stats.Init();
a->AllocateBatch(&stats, &cache, 64); a->AllocateBatch(&stats, &cache, 32);
EXPECT_EQ(TestMapUnmapCallback::map_count, 2); // alloc. EXPECT_EQ(TestMapUnmapCallback::map_count, 2); // alloc.
a->TestOnlyUnmap(); a->TestOnlyUnmap();
EXPECT_EQ(TestMapUnmapCallback::unmap_count, 2); // The whole thing + alloc. EXPECT_EQ(TestMapUnmapCallback::unmap_count, 2); // The whole thing + alloc.
@ -258,7 +258,7 @@ void FailInAssertionOnOOM() {
AllocatorStats stats; AllocatorStats stats;
stats.Init(); stats.Init();
for (int i = 0; i < 1000000; i++) { for (int i = 0; i < 1000000; i++) {
a.AllocateBatch(&stats, &cache, 64); a.AllocateBatch(&stats, &cache, 52);
} }
a.TestOnlyUnmap(); a.TestOnlyUnmap();