Skip to content

Commit 159c068

Browse files
committed
[scudo] Refactor allocator config to support optional flags
Instead of explicitly disabling a feature by declaring the variable and set it to false, this change supports the optional flags. I.e., you can skip certain flags if you are not using it. This optional feature supports both forms, 1. Value: A parameter for a feature. E.g., EnableRandomOffset 2. Type: A C++ type implementing a feature. E.g., ConditionVariableT On the other hand, to access the flags will be through one of the wrappers, BaseConfig/PrimaryConfig/SecondaryConfig/CacheConfig (CacheConfig is embedded in SecondaryConfig). These wrappers have the getters to access the value and the type. When adding a new feature, we need to add it to `allocator_config.def` and mark the new variable with either *_REQUIRED_* or *_OPTIONAL_* macro so that the accessor will be generated properly. In addition, also remove the need of `UseConditionVariable` to flip on/off of condition variable. Now we only need to define the type of condition variable.
1 parent 5661188 commit 159c068

13 files changed

+378
-168
lines changed

compiler-rt/lib/scudo/standalone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ endif()
5858
set(SCUDO_HEADERS
5959
allocator_common.h
6060
allocator_config.h
61+
allocator_config_wrapper.h
6162
atomic_helpers.h
6263
bytemap.h
6364
checksum.h
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//===-- allocator_config.def ------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines all the flags and types supported in Scudo.
10+
11+
#ifndef BASE_REQUIRED_TEMPLATE_TYPE
12+
#define BASE_REQUIRED_TEMPLATE_TYPE(...)
13+
#endif
14+
#ifndef BASE_OPTIONAL
15+
#define BASE_OPTIONAL(...)
16+
#endif
17+
#ifndef PRIMARY_REQUIRED_TYPE
18+
#define PRIMARY_REQUIRED_TYPE(...)
19+
#endif
20+
#ifndef PRIMARY_REQUIRED
21+
#define PRIMARY_REQUIRED(...)
22+
#endif
23+
#ifndef PRIMARY_OPTIONAL
24+
#define PRIMARY_OPTIONAL(...)
25+
#endif
26+
#ifndef PRIMARY_OPTIONAL_TYPE
27+
#define PRIMARY_OPTIONAL_TYPE(...)
28+
#endif
29+
#ifndef SECONDARY_REQUIRED_TEMPLATE_TYPE
30+
#define SECONDARY_REQUIRED_TEMPLATE_TYPE(...)
31+
#endif
32+
#ifndef SECONDARY_CACHE_OPTIONAL
33+
#define SECONDARY_CACHE_OPTIONAL(...)
34+
#endif
35+
36+
// BASE_REQUIRED_TEMPLATE_TYPE(NAME)
37+
//
38+
// Thread-Specific Data Registry used, shared or exclusive.
39+
BASE_REQUIRED_TEMPLATE_TYPE(TSDRegistryT)
40+
41+
// Defines the type of Primary allocator to use.
42+
BASE_REQUIRED_TEMPLATE_TYPE(PrimaryT)
43+
44+
// Defines the type of Secondary allocator to use.
45+
BASE_REQUIRED_TEMPLATE_TYPE(SecondaryT)
46+
47+
// BASE_OPTIONAL(TYPE, NAME, DEFAULT)
48+
//
49+
// Indicates possible support for Memory Tagging.
50+
BASE_OPTIONAL(const bool, MaySupportMemoryTagging, false)
51+
52+
// PRIMARY_REQUIRED_TYPE(NAME)
53+
//
54+
// SizeClassMap to use with the Primary.
55+
PRIMARY_REQUIRED_TYPE(SizeClassMap)
56+
57+
// Defines the type and scale of a compact pointer. A compact pointer can
58+
// be understood as the offset of a pointer within the region it belongs
59+
// to, in increments of a power-of-2 scale. See `CompactPtrScale` also.
60+
PRIMARY_REQUIRED_TYPE(CompactPtrT)
61+
62+
// PRIMARY_REQUIRED(TYPE, NAME)
63+
//
64+
// The scale of a compact pointer. E.g., Ptr = Base + (CompactPtr << Scale).
65+
PRIMARY_REQUIRED(const uptr, CompactPtrScale)
66+
67+
// Log2 of the size of a size class region, as used by the Primary.
68+
PRIMARY_REQUIRED(const uptr, RegionSizeLog)
69+
70+
// Log2 of the size of block group, as used by the Primary. Each group
71+
// contains a range of memory addresses, blocks in the range will belong
72+
// to the same group. In general, single region may have 1 or 2MB group
73+
// size. Multiple regions will have the group size equal to the region
74+
// size because the region size is usually smaller than 1 MB.
75+
// Smaller value gives fine-grained control of memory usage but the
76+
// trade-off is that it may take longer time of deallocation.
77+
PRIMARY_REQUIRED(const uptr, GroupSizeLog)
78+
79+
// Call map for user memory with at least this size. Only used with primary64.
80+
PRIMARY_REQUIRED(const uptr, MapSizeIncrement)
81+
82+
// Defines the minimal & maximal release interval that can be set.
83+
PRIMARY_REQUIRED(const s32, MinReleaseToOsIntervalMs)
84+
PRIMARY_REQUIRED(const s32, MaxReleaseToOsIntervalMs)
85+
86+
// PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT)
87+
//
88+
// Indicates support for offsetting the start of a region by a random number of
89+
// pages. Only used with primary64.
90+
PRIMARY_OPTIONAL(const bool, EnableRandomOffset, false)
91+
92+
// PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT)
93+
//
94+
// Use condition variable to shorten the waiting time of refillment of
95+
// freelist. Note that this depends on the implementation of condition
96+
// variable on each platform and the performance may vary so that it doesn not
97+
// guarantee a performance benefit.
98+
PRIMARY_OPTIONAL_TYPE(ConditionVariableT, ConditionVariableDummy)
99+
100+
// SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME)
101+
//
102+
// Defines the type of Secondary Cache to use.
103+
SECONDARY_REQUIRED_TEMPLATE_TYPE(CacheT)
104+
105+
// SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT)
106+
//
107+
// Defines the type of cache used by the Secondary. Some additional
108+
// configuration entries can be necessary depending on the Cache.
109+
SECONDARY_CACHE_OPTIONAL(const u32, EntriesArraySize, 0)
110+
SECONDARY_CACHE_OPTIONAL(const u32, QuarantineSize, 0)
111+
SECONDARY_CACHE_OPTIONAL(const u32, DefaultMaxEntriesCount, 0)
112+
SECONDARY_CACHE_OPTIONAL(const u32, DefaultMaxEntrySize, 0)
113+
SECONDARY_CACHE_OPTIONAL(const s32, MinReleaseToOsIntervalMs, INT32_MIN)
114+
SECONDARY_CACHE_OPTIONAL(const s32, MaxReleaseToOsIntervalMs, INT32_MAX)
115+
116+
#undef SECONDARY_CACHE_OPTIONAL
117+
#undef SECONDARY_REQUIRED_TEMPLATE_TYPE
118+
#undef PRIMARY_OPTIONAL_TYPE
119+
#undef PRIMARY_OPTIONAL
120+
#undef PRIMARY_REQUIRED
121+
#undef PRIMARY_REQUIRED_TYPE
122+
#undef BASE_OPTIONAL
123+
#undef BASE_REQUIRED_TEMPLATE_TYPE

compiler-rt/lib/scudo/standalone/allocator_config.h

Lines changed: 4 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -38,80 +38,10 @@
3838

3939
namespace scudo {
4040

41-
// The combined allocator uses a structure as a template argument that
42-
// specifies the configuration options for the various subcomponents of the
43-
// allocator.
44-
//
45-
// struct ExampleConfig {
46-
// // Indicates possible support for Memory Tagging.
47-
// static const bool MaySupportMemoryTagging = false;
48-
//
49-
// // Thread-Specific Data Registry used, shared or exclusive.
50-
// template <class A> using TSDRegistryT = TSDRegistrySharedT<A, 8U, 4U>;
51-
//
52-
// struct Primary {
53-
// // SizeClassMap to use with the Primary.
54-
// using SizeClassMap = DefaultSizeClassMap;
55-
//
56-
// // Log2 of the size of a size class region, as used by the Primary.
57-
// static const uptr RegionSizeLog = 30U;
58-
//
59-
// // Log2 of the size of block group, as used by the Primary. Each group
60-
// // contains a range of memory addresses, blocks in the range will belong
61-
// // to the same group. In general, single region may have 1 or 2MB group
62-
// // size. Multiple regions will have the group size equal to the region
63-
// // size because the region size is usually smaller than 1 MB.
64-
// // Smaller value gives fine-grained control of memory usage but the
65-
// // trade-off is that it may take longer time of deallocation.
66-
// static const uptr GroupSizeLog = 20U;
67-
//
68-
// // Defines the type and scale of a compact pointer. A compact pointer can
69-
// // be understood as the offset of a pointer within the region it belongs
70-
// // to, in increments of a power-of-2 scale.
71-
// // eg: Ptr = Base + (CompactPtr << Scale).
72-
// typedef u32 CompactPtrT;
73-
// static const uptr CompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
74-
//
75-
// // Indicates support for offsetting the start of a region by
76-
// // a random number of pages. Only used with primary64.
77-
// static const bool EnableRandomOffset = true;
78-
//
79-
// // Call map for user memory with at least this size. Only used with
80-
// // primary64.
81-
// static const uptr MapSizeIncrement = 1UL << 18;
82-
//
83-
// // Defines the minimal & maximal release interval that can be set.
84-
// static const s32 MinReleaseToOsIntervalMs = INT32_MIN;
85-
// static const s32 MaxReleaseToOsIntervalMs = INT32_MAX;
86-
//
87-
// // Use condition variable to shorten the waiting time of refillment of
88-
// // freelist. Note that this depends on the implementation of condition
89-
// // variable on each platform and the performance may vary so that it
90-
// // doesn't guarantee a performance benefit.
91-
// // Note that both variables have to be defined to enable it.
92-
// static const bool UseConditionVariable = true;
93-
// using ConditionVariableT = ConditionVariableLinux;
94-
// };
95-
// // Defines the type of Primary allocator to use.
96-
// template <typename Config> using PrimaryT = SizeClassAllocator64<Config>;
97-
//
98-
// // Defines the type of cache used by the Secondary. Some additional
99-
// // configuration entries can be necessary depending on the Cache.
100-
// struct Secondary {
101-
// struct Cache {
102-
// static const u32 EntriesArraySize = 32U;
103-
// static const u32 QuarantineSize = 0U;
104-
// static const u32 DefaultMaxEntriesCount = 32U;
105-
// static const uptr DefaultMaxEntrySize = 1UL << 19;
106-
// static const s32 MinReleaseToOsIntervalMs = INT32_MIN;
107-
// static const s32 MaxReleaseToOsIntervalMs = INT32_MAX;
108-
// };
109-
// // Defines the type of Secondary Cache to use.
110-
// template <typename Config> using CacheT = MapAllocatorCache<Config>;
111-
// };
112-
// // Defines the type of Secondary allocator to use.
113-
// template <typename Config> using SecondaryT = MapAllocator<Config>;
114-
// };
41+
// Scudo uses a structure as a template argument that specifies the
42+
// configuration options for the various subcomponents of the allocator. See the
43+
// following configs as examples and check `allocator_config.def` for all the
44+
// available options.
11545

11646
#ifndef SCUDO_USE_CUSTOM_CONFIG
11747

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//===-- allocator_config_wrapper.h ------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
10+
#define SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
11+
12+
#include "condition_variable.h"
13+
#include "internal_defs.h"
14+
#include "secondary.h"
15+
16+
namespace {
17+
18+
template <typename T> struct removeConst {
19+
using type = T;
20+
};
21+
template <typename T> struct removeConst<const T> {
22+
using type = T;
23+
};
24+
25+
} // namespace
26+
27+
namespace scudo {
28+
29+
#define OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT) \
30+
template <typename Config, typename = TYPE> struct NAME##State { \
31+
static constexpr removeConst<TYPE>::type getValue() { return DEFAULT; } \
32+
}; \
33+
template <typename Config> \
34+
struct NAME##State<Config, decltype(Config::NAME)> { \
35+
static constexpr removeConst<TYPE>::type getValue() { \
36+
return Config::NAME; \
37+
} \
38+
};
39+
40+
#define OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT) \
41+
template <typename Config, typename Void = Config> struct NAME##Type { \
42+
static constexpr bool enabled() { return false; } \
43+
using NAME = DEFAULT; \
44+
}; \
45+
template <typename Config> \
46+
struct NAME##Type<Config, typename Config::NAME> { \
47+
static constexpr bool enabled() { return true; } \
48+
using NAME = typename Config::NAME; \
49+
};
50+
51+
template <typename AllocatorConfig> struct BaseConfig {
52+
#define BASE_REQUIRED_TEMPLATE_TYPE(NAME) \
53+
template <typename T> using NAME = typename AllocatorConfig::template NAME<T>;
54+
55+
#define BASE_OPTIONAL(TYPE, NAME, DEFAULT) \
56+
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT) \
57+
static constexpr removeConst<TYPE>::type get##NAME() { \
58+
return NAME##State<AllocatorConfig>::getValue(); \
59+
}
60+
61+
#include "allocator_config.def"
62+
}; // BaseConfig
63+
64+
template <typename AllocatorConfig> struct PrimaryConfig {
65+
// TODO: Pass this flag through template argument to remove this hard-coded
66+
// function.
67+
static constexpr bool getMaySupportMemoryTagging() {
68+
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
69+
}
70+
71+
#define PRIMARY_REQUIRED_TYPE(NAME) \
72+
using NAME = typename AllocatorConfig::Primary::NAME;
73+
74+
#define PRIMARY_REQUIRED(TYPE, NAME) \
75+
static constexpr removeConst<TYPE>::type get##NAME() { \
76+
return AllocatorConfig::Primary::NAME; \
77+
}
78+
79+
#define PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT) \
80+
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT) \
81+
static constexpr removeConst<TYPE>::type get##NAME() { \
82+
return NAME##State<typename AllocatorConfig::Primary>::getValue(); \
83+
}
84+
85+
#define PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT) \
86+
OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT) \
87+
static constexpr bool has##NAME() { \
88+
return NAME##Type<typename AllocatorConfig::Primary>::enabled(); \
89+
} \
90+
using NAME = typename NAME##Type<typename AllocatorConfig::Primary>::NAME;
91+
92+
#include "allocator_config.def"
93+
94+
}; // PrimaryConfig
95+
96+
template <typename AllocatorConfig> struct SecondaryConfig {
97+
// TODO: Pass this flag through template argument to remove this hard-coded
98+
// function.
99+
static constexpr bool getMaySupportMemoryTagging() {
100+
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
101+
}
102+
103+
#define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME) \
104+
template <typename T> \
105+
using NAME = typename AllocatorConfig::Secondary::template NAME<T>;
106+
#include "allocator_config.def"
107+
108+
struct CacheConfig {
109+
// TODO: Pass this flag through template argument to remove this hard-coded
110+
// function.
111+
static constexpr bool getMaySupportMemoryTagging() {
112+
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
113+
}
114+
115+
#define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT) \
116+
template <typename Config, typename = TYPE> struct NAME##State { \
117+
static constexpr removeConst<TYPE>::type getValue() { return DEFAULT; } \
118+
}; \
119+
template <typename Config> \
120+
struct NAME##State<Config, decltype(Config::Cache)> { \
121+
static constexpr removeConst<TYPE>::type getValue() { \
122+
return Config::Cache::NAME; \
123+
} \
124+
}; \
125+
static constexpr removeConst<TYPE>::type get##NAME() { \
126+
return NAME##State<typename AllocatorConfig::Secondary>::getValue(); \
127+
}
128+
#include "allocator_config.def"
129+
};
130+
}; // SecondaryConfig
131+
132+
} // namespace scudo
133+
134+
#endif // SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_

0 commit comments

Comments
 (0)