Skip to content

Commit 79eb185

Browse files
Liblorcopybara-github
authored andcommitted
Prepare for the collection of a token identifier.
Introduce a field to collect a token identifier that can stem from the alloc-token instrumentation [0,1,2]. For now it is hard-coded to TokenId::kNoAllocToken and a separate commit will introduce the a mapping to the alloc-token instrumentation. [0] https://clang.llvm.org/docs/AllocToken.html [1] https://discourse.llvm.org/t/rfc-a-framework-for-allocator-partitioning-hints/87434 [2] llvm/llvm-project#156838 PiperOrigin-RevId: 828929199 Change-Id: I5afbf5ec03345c584a24ca2fc49fd7d225d77dbf
1 parent 35eb1a0 commit 79eb185

File tree

7 files changed

+95
-30
lines changed

7 files changed

+95
-30
lines changed

tcmalloc/allocation_sampling.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ ABSL_ATTRIBUTE_NOINLINE sized_ptr_t SampleifyAllocation(
122122
stack_trace.requested_size_returning = policy.size_returning();
123123
stack_trace.access_hint = static_cast<uint8_t>(policy.access());
124124
stack_trace.weight = weight;
125+
// TODO: b/446814339 - Complete populating this.
126+
stack_trace.token_id = TokenId::kNoAllocToken;
125127

126128
// How many allocations does this sample represent, given the sampling
127129
// frequency (weight) and its size.

tcmalloc/internal/logging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ struct StackTrace {
8888
// Timestamp of allocation.
8989
absl::Time allocation_time;
9090

91+
TokenId token_id;
92+
9193
Profile::Sample::GuardedStatus guarded_status;
9294

9395
// How the memory was allocated (new/malloc/etc.)

tcmalloc/internal/profile_builder.cc

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ struct SampleEqWithSubFields {
118118
auto fields = [](const Profile::Sample& s) {
119119
return std::tie(s.depth, s.requested_size, s.requested_alignment,
120120
s.requested_size_returning, s.allocated_size,
121-
s.access_hint, s.access_allocated, s.guarded_status,
122-
s.type);
121+
s.access_hint, s.access_allocated, s.token_id,
122+
s.guarded_status, s.type);
123123
};
124124
return fields(a) == fields(b) &&
125125
std::equal(a.stack, a.stack + a.depth, b.stack, b.stack + b.depth);
@@ -128,10 +128,11 @@ struct SampleEqWithSubFields {
128128

129129
struct SampleHashWithSubFields {
130130
size_t operator()(const Profile::Sample& s) const {
131-
return absl::HashOf(
132-
absl::MakeConstSpan(s.stack, s.depth), s.depth, s.requested_size,
133-
s.requested_alignment, s.requested_size_returning, s.allocated_size,
134-
s.access_hint, s.access_allocated, s.guarded_status, s.type);
131+
return absl::HashOf(absl::MakeConstSpan(s.stack, s.depth), s.depth,
132+
s.requested_size, s.requested_alignment,
133+
s.requested_size_returning, s.allocated_size,
134+
s.access_hint, s.access_allocated, s.token_id,
135+
s.guarded_status, s.type);
135136
}
136137
};
137138

@@ -696,6 +697,7 @@ absl::StatusOr<std::unique_ptr<perftools::profiles::Profile>> MakeProfileProto(
696697
const int access_allocated_id = builder.InternString("access_allocated");
697698
const int cold_id = builder.InternString("cold");
698699
const int hot_id = builder.InternString("hot");
700+
const int token_id = builder.InternString("token_id");
699701
const int allocation_type_id = builder.InternString("allocation type");
700702
const int new_id = builder.InternString("new");
701703
const int malloc_id = builder.InternString("malloc");
@@ -827,6 +829,8 @@ absl::StatusOr<std::unique_ptr<perftools::profiles::Profile>> MakeProfileProto(
827829
static_cast<uint8_t>(entry.access_hint));
828830
add_access_label(access_allocated_id, entry.access_allocated);
829831

832+
add_label(token_id, token_id, static_cast<uint8_t>(entry.token_id));
833+
830834
perftools::profiles::Label& type_label = *sample.add_label();
831835
type_label.set_key(allocation_type_id);
832836

tcmalloc/internal/profile_builder_test.cc

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ perftools::profiles::Profile MakeTestProfile(
355355
sample.stack[4] = reinterpret_cast<void*>(&ProfileAccessor::MakeProfile);
356356
sample.access_hint = hot_cold_t{254};
357357
sample.access_allocated = Profile::Sample::Access::Cold;
358+
sample.token_id = TokenId{0};
358359
sample.guarded_status = Profile::Sample::GuardedStatus::RateLimited;
359360
sample.type = Profile::Sample::AllocationType::New;
360361
samples.push_back(sample);
@@ -401,6 +402,7 @@ perftools::profiles::Profile MakeTestProfile(
401402
sample.stack[3] = reinterpret_cast<void*>(&RealPath);
402403
sample.access_hint = hot_cold_t{1};
403404
sample.access_allocated = Profile::Sample::Access::Hot;
405+
sample.token_id = TokenId{0};
404406
sample.guarded_status = Profile::Sample::GuardedStatus::NoAvailableSlots;
405407
sample.type = Profile::Sample::AllocationType::Malloc;
406408

@@ -440,6 +442,7 @@ perftools::profiles::Profile MakeTestProfile(
440442
sample.stack[2] = reinterpret_cast<void*>(&RealPath);
441443
sample.access_hint = hot_cold_t{0};
442444
sample.access_allocated = Profile::Sample::Access::Hot;
445+
sample.token_id = TokenId{0};
443446
sample.guarded_status = Profile::Sample::GuardedStatus::RateLimited;
444447
sample.type = Profile::Sample::AllocationType::AlignedMalloc;
445448
}
@@ -470,6 +473,7 @@ perftools::profiles::Profile MakeTestProfile(
470473
sample.stack[4] = reinterpret_cast<void*>(&ProfileAccessor::MakeProfile);
471474
sample.access_hint = hot_cold_t{253};
472475
sample.access_allocated = Profile::Sample::Access::Cold;
476+
sample.token_id = TokenId{1};
473477
sample.guarded_status = Profile::Sample::GuardedStatus::RateLimited;
474478
sample.type = Profile::Sample::AllocationType::New;
475479
samples.push_back(sample);
@@ -595,10 +599,13 @@ TEST(ProfileConverterTest, HeapProfile) {
595599
}
596600
}
597601

598-
EXPECT_THAT(label_to_units,
599-
IsSupersetOf({Pair("bytes", "bytes"), Pair("request", "bytes"),
600-
Pair("alignment", "bytes"),
601-
Pair("access_hint", "access_hint")}));
602+
EXPECT_THAT(label_to_units, IsSupersetOf({
603+
Pair("bytes", "bytes"),
604+
Pair("request", "bytes"),
605+
Pair("alignment", "bytes"),
606+
Pair("access_hint", "access_hint"),
607+
Pair("token_id", "token_id"),
608+
}));
602609

603610
EXPECT_THAT(
604611
label_to_units,
@@ -612,37 +619,42 @@ TEST(ProfileConverterTest, HeapProfile) {
612619
Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4),
613620
Pair("stale_scan_period", 10),
614621
Pair("access_hint", 254), Pair("access_allocated", "cold"),
615-
Pair("size_returning", 1), Pair("guarded_status", "RateLimited"),
622+
Pair("token_id", 0), Pair("size_returning", 1),
623+
Pair("guarded_status", "RateLimited"),
616624
Pair("allocation type", "new")),
617-
UnorderedElementsAre(Pair("bytes", 8), Pair("request", 4),
618-
Pair("stale_scan_period", 10),
619-
Pair("access_hint", 1),
620-
Pair("access_allocated", "hot"),
621-
Pair("guarded_status", "NoAvailableSlots"),
622-
Pair("allocation type", "malloc")),
623625
UnorderedElementsAre(
624-
Pair("bytes", 16), Pair("request", 16),
626+
Pair("bytes", 8), Pair("request", 4),
625627
Pair("stale_scan_period", 10),
626-
Pair("access_hint", 0), Pair("access_allocated", "hot"),
627-
Pair("size_returning", 1), Pair("guarded_status", "RateLimited"),
628-
Pair("allocation type", "aligned malloc")),
628+
Pair("access_hint", 1), Pair("access_allocated", "hot"),
629+
Pair("token_id", 0), Pair("guarded_status", "NoAvailableSlots"),
630+
Pair("allocation type", "malloc")),
631+
UnorderedElementsAre(Pair("bytes", 16), Pair("request", 16),
632+
Pair("stale_scan_period", 10),
633+
Pair("access_hint", 0),
634+
Pair("access_allocated", "hot"),
635+
Pair("token_id", 0), Pair("size_returning", 1),
636+
Pair("guarded_status", "RateLimited"),
637+
Pair("allocation type", "aligned malloc")),
629638
UnorderedElementsAre(
630639
Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4),
631640
Pair("stale_scan_period", 10),
632641
Pair("access_hint", 253), Pair("access_allocated", "cold"),
633-
Pair("size_returning", 1), Pair("guarded_status", "RateLimited"),
642+
Pair("token_id", 1), Pair("size_returning", 1),
643+
Pair("guarded_status", "RateLimited"),
634644
Pair("allocation type", "new")),
635645
UnorderedElementsAre(
636646
Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4),
637647
Pair("stale_scan_period", 10),
638648
Pair("access_hint", 253), Pair("access_allocated", "cold"),
639-
Pair("size_returning", 1), Pair("guarded_status", "Filtered"),
649+
Pair("token_id", 1), Pair("size_returning", 1),
650+
Pair("guarded_status", "Filtered"),
640651
Pair("allocation type", "new")),
641652
UnorderedElementsAre(
642653
Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4),
643654
Pair("stale_scan_period", 10),
644655
Pair("access_hint", 253), Pair("access_allocated", "cold"),
645-
Pair("size_returning", 1), Pair("guarded_status", "Guarded"),
656+
Pair("token_id", 1), Pair("size_returning", 1),
657+
Pair("guarded_status", "Guarded"),
646658
Pair("allocation type", "new"))));
647659

648660
EXPECT_THAT(extracted_samples,
@@ -743,6 +755,7 @@ TEST(ProfileBuilderTest, PeakHeapProfile) {
743755
sample.stack[2] = reinterpret_cast<void*>(&ProfileAccessor::MakeProfile);
744756
sample.access_hint = hot_cold_t{254};
745757
sample.access_allocated = Profile::Sample::Access::Cold;
758+
sample.token_id = TokenId{0};
746759
}
747760

748761
{
@@ -762,6 +775,7 @@ TEST(ProfileBuilderTest, PeakHeapProfile) {
762775
sample.stack[1] = reinterpret_cast<void*>(&RealPath);
763776
sample.access_hint = hot_cold_t{1};
764777
sample.access_allocated = Profile::Sample::Access::Hot;
778+
sample.token_id = TokenId{0};
765779
}
766780

767781
fake_profile->SetSamples(std::move(samples));
@@ -782,13 +796,14 @@ TEST(ProfileBuilderTest, PeakHeapProfile) {
782796
UnorderedElementsAre(
783797
Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4),
784798
Pair("access_hint", 254), Pair("access_allocated", "cold"),
785-
Pair("size_returning", 1), Pair("guarded_status", "NotAttempted"),
799+
Pair("token_id", 0), Pair("size_returning", 1),
800+
Pair("guarded_status", "NotAttempted"),
786801
Pair("allocation type", "new")),
787-
UnorderedElementsAre(Pair("bytes", 8), Pair("request", 4),
788-
Pair("access_hint", 1),
789-
Pair("access_allocated", "hot"),
790-
Pair("guarded_status", "NotAttempted"),
791-
Pair("allocation type", "new"))));
802+
UnorderedElementsAre(
803+
Pair("bytes", 8), Pair("request", 4),
804+
Pair("access_hint", 1), Pair("access_allocated", "hot"),
805+
Pair("token_id", 0), Pair("guarded_status", "NotAttempted"),
806+
Pair("allocation type", "new"))));
792807

793808
ASSERT_GE(converted.sample().size(), 2);
794809
ASSERT_GE(converted.sample(0).location_id().size(), 2);
@@ -1023,6 +1038,7 @@ TEST(ProfileBuilderTest, SameTags) {
10231038
"access_hint",
10241039
"access_allocated",
10251040
"size_returning",
1041+
"token_id",
10261042
"guarded_status",
10271043
};
10281044
EXPECT_THAT(allocation_tags, testing::IsSupersetOf(lifetime_missing_tags));

tcmalloc/malloc_extension.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,31 @@ namespace tcmalloc {
6565
// as is.
6666
using hot_cold_t = __hot_cold_t;
6767

68+
// With the security partition feature, token IDs map to security partitions
69+
// using the below scheme. All token IDs less than or equal ALLOC_TOKEN_FALLBACK
70+
// (9) are generated by the compiler, whereas greater token IDs are defined to
71+
// distinguish uninstrumented allocations.
72+
enum class TokenId : uint8_t {
73+
// Alloc token instrumented allocations with identifier 0 (pointerless).
74+
kAllocToken0 = 0,
75+
// Alloc token instrumented allocations with identifier 1 (pointerful).
76+
kAllocToken1 = 1,
77+
#ifdef ALLOC_TOKEN_FALLBACK
78+
// Alloc token instrumented allocations with fallback identifier (pointerful).
79+
kAllocTokenFallback = ALLOC_TOKEN_FALLBACK,
80+
#else
81+
kAllocTokenFallback = kAllocToken0,
82+
#endif
83+
// Allocations without alloc-token instrumentation (pointerful).
84+
kNoAllocToken = 10,
85+
// Allocations whose partition is assigned at runtime to partition 0
86+
// (pointerless)
87+
kRuntimePartitionId0 = 128,
88+
// Allocations whose partition is assigned at runtime to partition 1
89+
// (pointerful)
90+
kRuntimePartitionId1 = 129,
91+
};
92+
6893
constexpr hot_cold_t kDefaultMinHotAccessHint =
6994
static_cast<tcmalloc::hot_cold_t>(1);
7095

@@ -174,6 +199,9 @@ class Profile final {
174199
// implementation constraints.
175200
Access access_allocated;
176201

202+
// The token id which is used to determine the partition.
203+
TokenId token_id;
204+
177205
// Whether this sample captures allocations where the deallocation event
178206
// was not observed. Thus the measurements are censored in the statistical
179207
// sense, see https://en.wikipedia.org/wiki/Censoring_(statistics)#Types.

tcmalloc/stack_trace_table.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ void StackTraceTable::AddTrace(double sample_weight, const StackTrace& t) {
9191
s->sample.allocated_size = allocated_size;
9292
s->sample.alloc_handle = t.sampled_alloc_handle;
9393
s->sample.access_hint = static_cast<hot_cold_t>(t.access_hint);
94+
s->sample.token_id = t.token_id;
9495
s->sample.access_allocated = t.cold_allocated ? Profile::Sample::Access::Cold
9596
: Profile::Sample::Access::Hot;
9697
s->sample.depth = t.depth;

tcmalloc/stack_trace_table_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct AllocationEntry {
4848
size_t allocated_size;
4949
MallocHook::AllocHandle alloc_handle;
5050
uint8_t access_hint;
51+
TokenId token_id;
5152
bool cold_allocated;
5253
int depth;
5354
void* stack[64];
@@ -152,6 +153,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
152153
t1.allocated_size = static_cast<uintptr_t>(1024);
153154
t1.sampled_alloc_handle = AllocHandle{1};
154155
t1.access_hint = 3;
156+
t1.token_id = TokenId::kAllocToken0;
155157
t1.cold_allocated = true;
156158
t1.depth = static_cast<uintptr_t>(2);
157159
t1.stack[0] = reinterpret_cast<void*>(1);
@@ -166,6 +168,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
166168
.allocated_size = 1024,
167169
.alloc_handle = AllocHandle{1},
168170
.access_hint = 3,
171+
.token_id = TokenId::kAllocToken0,
169172
.cold_allocated = true,
170173
.depth = 2,
171174
.stack = {reinterpret_cast<void*>(1), reinterpret_cast<void*>(2)},
@@ -177,6 +180,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
177180
t2.allocated_size = static_cast<uintptr_t>(512);
178181
t2.sampled_alloc_handle = AllocHandle{2};
179182
t2.access_hint = 254;
183+
t2.token_id = TokenId::kNoAllocToken;
180184
t2.cold_allocated = false;
181185
t2.depth = static_cast<uintptr_t>(2);
182186
t2.stack[0] = reinterpret_cast<void*>(2);
@@ -191,6 +195,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
191195
.allocated_size = 512,
192196
.alloc_handle = AllocHandle{2},
193197
.access_hint = 254,
198+
.token_id = TokenId::kNoAllocToken,
194199
.cold_allocated = false,
195200
.depth = 2,
196201
.stack = {reinterpret_cast<void*>(2), reinterpret_cast<void*>(1)},
@@ -227,6 +232,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
227232
.allocated_size = 1024,
228233
.alloc_handle = AllocHandle{1},
229234
.access_hint = 3,
235+
.token_id = TokenId::kAllocToken0,
230236
.cold_allocated = true,
231237
.depth = 2,
232238
.stack = {reinterpret_cast<void*>(1), reinterpret_cast<void*>(2)},
@@ -286,6 +292,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
286292
t3.allocated_size = static_cast<uintptr_t>(17);
287293
t3.sampled_alloc_handle = AllocHandle{3};
288294
t3.access_hint = 3;
295+
t3.token_id = TokenId::kAllocToken1;
289296
t3.cold_allocated = false;
290297
t3.depth = static_cast<uintptr_t>(2);
291298
t3.stack[0] = reinterpret_cast<void*>(1);
@@ -300,6 +307,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
300307
.allocated_size = 17,
301308
.alloc_handle = AllocHandle{3},
302309
.access_hint = 3,
310+
.token_id = TokenId::kAllocToken1,
303311
.cold_allocated = false,
304312
.depth = 2,
305313
.stack = {reinterpret_cast<void*>(1), reinterpret_cast<void*>(2)},
@@ -324,6 +332,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
324332
t4.allocated_size = static_cast<uintptr_t>(1024);
325333
t4.sampled_alloc_handle = AllocHandle{4};
326334
t4.access_hint = 3;
335+
t4.token_id = TokenId::kAllocToken0;
327336
t4.cold_allocated = false;
328337
t4.depth = static_cast<uintptr_t>(2);
329338
t4.stack[0] = reinterpret_cast<void*>(1);
@@ -338,6 +347,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
338347
.allocated_size = 1024,
339348
.alloc_handle = AllocHandle{4},
340349
.access_hint = 3,
350+
.token_id = TokenId::kAllocToken0,
341351
.cold_allocated = false,
342352
.depth = 2,
343353
.stack = {reinterpret_cast<void*>(1), reinterpret_cast<void*>(2)},
@@ -362,6 +372,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
362372
t5.allocated_size = static_cast<uintptr_t>(1024);
363373
t5.sampled_alloc_handle = AllocHandle{5};
364374
t5.access_hint = 4;
375+
t5.token_id = TokenId::kAllocToken0;
365376
t5.cold_allocated = true;
366377
t5.depth = static_cast<uintptr_t>(2);
367378
t5.stack[0] = reinterpret_cast<void*>(1);
@@ -376,6 +387,7 @@ TEST(StackTraceTableTest, StackTraceTable) {
376387
.allocated_size = 1024,
377388
.alloc_handle = AllocHandle{5},
378389
.access_hint = 4,
390+
.token_id = TokenId::kAllocToken0,
379391
.cold_allocated = true,
380392
.depth = 2,
381393
.stack = {reinterpret_cast<void*>(1), reinterpret_cast<void*>(2)},

0 commit comments

Comments
 (0)