Skip to content

Commit a39de5a

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents c36e5c3 + c55f039 commit a39de5a

File tree

4 files changed

+55
-67
lines changed

4 files changed

+55
-67
lines changed

include/runtime/arena.h

+28-51
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,22 @@ extern "C" {
1414

1515
size_t const HYPERBLOCK_SIZE = (size_t)BLOCK_SIZE * 1024 * 1024;
1616

17+
// After a garbage collect we change the tripwire to the amount of non-garbage times
18+
// this factor, so we do a decent amount of allocations between collections even
19+
// when there is very little garbage
20+
size_t const EXPAND_FACTOR = 2;
21+
22+
// We don't consider collecting garbage until at least this amount of space has
23+
// been allocated, to avoid collections near startup when there is little garbage.
24+
size_t const MIN_SPACE = 1024 * 1024;
25+
1726
// An arena can be used to allocate objects that can then be deallocated all at
1827
// once.
1928
class arena {
2029
public:
21-
arena(char id)
22-
: allocation_semispace_id(id) { }
30+
arena(char id, bool trigger_collection)
31+
: allocation_semispace_id(id)
32+
, trigger_collection(trigger_collection) { }
2333

2434
~arena() {
2535
if (current_addr_ptr)
@@ -36,17 +46,17 @@ class arena {
3646

3747
// Returns the address of the first byte that belongs in the given arena.
3848
// Returns nullptr if nothing has been allocated ever in that arena.
39-
char *arena_start_ptr() const { return current_addr_ptr; }
49+
char *start_ptr() const { return current_addr_ptr; }
4050

4151
// Returns a pointer to a location holding the address of last allocated
4252
// byte in the given arena plus 1.
4353
// This address is nullptr if nothing has been allocated ever in that arena.
44-
char *arena_end_ptr() { return allocation_ptr; }
54+
char *end_ptr() { return allocation_ptr; }
4555

4656
// Clears the current allocation space by setting its start back to its first
4757
// block. It is used during garbage collection to effectively collect all of the
48-
// arena. Resets the tripwire.
49-
void arena_clear();
58+
// arena.
59+
void arena_clear() { allocation_ptr = current_addr_ptr; }
5060

5161
// Resizes the last allocation.
5262
// Returns the address of the byte following the last newly allocated byte.
@@ -67,6 +77,14 @@ class arena {
6777
// It is used before garbage collection.
6878
void arena_swap_and_clear();
6979

80+
// Decide how much space to use in arena before setting the flag for a collection.
81+
// If an arena is going to request collections, updating this at the end of a
82+
// collection is mandatory.
83+
void update_tripwire() {
84+
size_t space = EXPAND_FACTOR * (allocation_ptr - current_addr_ptr);
85+
tripwire = current_addr_ptr + ((space < MIN_SPACE) ? MIN_SPACE : space);
86+
}
87+
7088
// Given two pointers to objects allocated in the same arena, return the number
7189
// of bytes they are apart. Undefined behavior will result if the pointers
7290
// don't belong to the same arena
@@ -92,20 +110,6 @@ class arena {
92110
static char get_arena_semispace_id_of_object(void *ptr);
93111

94112
private:
95-
//
96-
// We update the number of 1MB blocks actually written to, only when we need this value,
97-
// or before a garbage collection rather than trying to determine when we write to a fresh block.
98-
//
99-
void update_num_blocks() const {
100-
//
101-
// Calculate how many 1M blocks of the current arena we used.
102-
//
103-
size_t num_used_blocks
104-
= (allocation_ptr - current_addr_ptr - 1) / BLOCK_SIZE + 1;
105-
if (num_used_blocks > num_blocks)
106-
num_blocks = num_used_blocks;
107-
}
108-
109113
void initialize_semispace();
110114
//
111115
// Current semispace where allocations are being made.
@@ -114,16 +118,13 @@ class arena {
114118
char *allocation_ptr
115119
= nullptr; // next available location in current semispace
116120
char *tripwire = nullptr; // allocating past this triggers slow allocation
117-
mutable size_t num_blocks
118-
= 0; // notional number of BLOCK_SIZE blocks in current semispace
119121
char allocation_semispace_id; // id of current semispace
122+
bool const trigger_collection; // request collections?
120123
//
121124
// Semispace where allocations will be made during and after garbage collect.
122125
//
123126
char *collection_addr_ptr
124127
= nullptr; // pointer to start of collection address space
125-
size_t num_collection_blocks
126-
= 0; // notional number of BLOCK_SIZE blocks in collection semispace
127128
};
128129

129130
inline char arena::get_arena_semispace_id_of_object(void *ptr) {
@@ -139,10 +140,6 @@ inline char arena::get_arena_semispace_id_of_object(void *ptr) {
139140
return *reinterpret_cast<char *>(end_address);
140141
}
141142

142-
// Macro to define a new arena with the given ID. Supports IDs ranging from 0 to
143-
// 127.
144-
#define REGISTER_ARENA(name, id) thread_local arena name(id)
145-
146143
#ifdef __MACH__
147144
//
148145
// thread_local disabled for Apple
@@ -183,32 +180,12 @@ inline void *arena::kore_arena_alloc(size_t requested) {
183180
return result;
184181
}
185182

186-
inline void arena::arena_clear() {
187-
//
188-
// We set the allocation pointer to the first available address.
189-
//
190-
allocation_ptr = arena_start_ptr();
191-
//
192-
// If the number of blocks we've touched is >= threshold, we want to trigger
193-
// a garbage collection if we get within 1 block of the end of this area.
194-
// Otherwise we only want to generate a garbage collect if we allocate off the
195-
// end of this area.
196-
//
197-
tripwire = current_addr_ptr
198-
+ (num_blocks - (num_blocks >= get_gc_threshold())) * BLOCK_SIZE;
199-
}
200-
201183
inline void arena::arena_swap_and_clear() {
202-
update_num_blocks(); // so we save the correct number of touched blocks
203184
std::swap(current_addr_ptr, collection_addr_ptr);
204-
std::swap(num_blocks, num_collection_blocks);
205185
allocation_semispace_id = ~allocation_semispace_id;
206-
if (current_addr_ptr == nullptr) {
207-
//
208-
// The other semispace hasn't be initialized yet.
209-
//
210-
initialize_semispace();
211-
} else
186+
if (current_addr_ptr == nullptr)
187+
initialize_semispace(); // not yet initialized
188+
else
212189
arena_clear();
213190
}
214191
}

runtime/alloc/arena.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ void arena::initialize_semispace() {
7272
current_addr_ptr[HYPERBLOCK_SIZE - 1] = allocation_semispace_id;
7373
allocation_ptr = current_addr_ptr;
7474
//
75-
// We set the tripwire for this space so we get trigger a garbage collection when we pass BLOCK_SIZE of memory
76-
// allocated from this space.
75+
// If we're set to trigger garbage collections, set the tripwire for MIN_SPACE of allocations otherwise
76+
// set it out-of-bounds (but still legal for comparison).
7777
//
78-
tripwire = current_addr_ptr + BLOCK_SIZE;
79-
num_blocks = 1;
78+
tripwire
79+
= current_addr_ptr + (trigger_collection ? MIN_SPACE : HYPERBLOCK_SIZE);
8080
}

runtime/collect/collect.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ char *arena::evacuate(char *scan_ptr) {
255255
migrate_child(curr_block, layout_data->args, i, false);
256256
}
257257
}
258-
return move_ptr(scan_ptr, get_size(hdr, layout_int), arena_end_ptr());
258+
return move_ptr(scan_ptr, get_size(hdr, layout_int), end_ptr());
259259
}
260260

261261
// Contains the decision logic for collecting the old generation.
@@ -295,21 +295,21 @@ void kore_collect(
295295
if (!last_alloc_ptr) {
296296
last_alloc_ptr = youngspace_ptr();
297297
}
298-
char *current_alloc_ptr = youngspace.arena_end_ptr();
298+
char *current_alloc_ptr = youngspace.end_ptr();
299299
#endif
300300
kore_alloc_swap(collect_old);
301301
#ifdef GC_DBG
302302
for (int i = 0; i < 2048; i++) {
303303
numBytesLiveAtCollection[i] = 0;
304304
}
305305
#endif
306-
char *previous_oldspace_alloc_ptr = oldspace.arena_end_ptr();
306+
char *previous_oldspace_alloc_ptr = oldspace.end_ptr();
307307
for (int i = 0; i < nroots; i++) {
308308
migrate_root(roots, type_info, i);
309309
}
310310
migrate_static_roots();
311311
char *scan_ptr = youngspace_ptr();
312-
if (scan_ptr != youngspace.arena_end_ptr()) {
312+
if (scan_ptr != youngspace.end_ptr()) {
313313
MEM_LOG("Evacuating young generation\n");
314314
while (scan_ptr) {
315315
scan_ptr = youngspace.evacuate(scan_ptr);
@@ -320,7 +320,7 @@ void kore_collect(
320320
} else {
321321
scan_ptr = previous_oldspace_alloc_ptr;
322322
}
323-
if (scan_ptr != oldspace.arena_end_ptr()) {
323+
if (scan_ptr != oldspace.end_ptr()) {
324324
MEM_LOG("Evacuating old generation\n");
325325
while (scan_ptr) {
326326
scan_ptr = oldspace.evacuate(scan_ptr);
@@ -331,12 +331,13 @@ void kore_collect(
331331
= arena::ptr_diff(current_alloc_ptr, last_alloc_ptr);
332332
assert(numBytesAllocedSinceLastCollection >= 0);
333333
fwrite(&numBytesAllocedSinceLastCollection, sizeof(ssize_t), 1, stderr);
334-
last_alloc_ptr = youngspace.arena_end_ptr();
334+
last_alloc_ptr = youngspace.end_ptr();
335335
fwrite(
336336
numBytesLiveAtCollection, sizeof(numBytesLiveAtCollection[0]),
337337
sizeof(numBytesLiveAtCollection) / sizeof(numBytesLiveAtCollection[0]),
338338
stderr);
339339
#endif
340+
youngspace.update_tripwire();
340341
MEM_LOG("Finishing garbage collection\n");
341342
is_gc = false;
342343
}

runtime/lto/alloc.cpp

+16-6
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,26 @@
1111

1212
extern "C" {
1313

14-
REGISTER_ARENA(youngspace, YOUNGSPACE_ID);
15-
REGISTER_ARENA(oldspace, OLDSPACE_ID);
16-
REGISTER_ARENA(alwaysgcspace, ALWAYSGCSPACE_ID);
14+
// class arena supports ID from 0 to 127
15+
16+
// New data in allocated in the youngspace, which requests a
17+
// collection when is gets too full.
18+
thread_local arena youngspace(YOUNGSPACE_ID, true);
19+
20+
// Data that is old enough is migrated to the oldspace. The
21+
// migrated data is always live at this point so it never
22+
// requests a collection.
23+
thread_local arena oldspace(OLDSPACE_ID, false);
24+
25+
// Temporary data is doesn't use the garbage collector.
26+
thread_local arena alwaysgcspace(ALWAYSGCSPACE_ID, false);
1727

1828
char *youngspace_ptr() {
19-
return youngspace.arena_start_ptr();
29+
return youngspace.start_ptr();
2030
}
2131

2232
char *oldspace_ptr() {
23-
return oldspace.arena_start_ptr();
33+
return oldspace.start_ptr();
2434
}
2535

2636
char youngspace_collection_id() {
@@ -73,7 +83,7 @@ kore_resize_last_alloc(void *oldptr, size_t newrequest, size_t last_size) {
7383
newrequest = (newrequest + 7) & ~7;
7484
last_size = (last_size + 7) & ~7;
7585

76-
if (oldptr != youngspace.arena_end_ptr() - last_size) {
86+
if (oldptr != youngspace.end_ptr() - last_size) {
7787
MEM_LOG(
7888
"May only reallocate last allocation. Tried to reallocate %p to %zd\n",
7989
oldptr, newrequest);

0 commit comments

Comments
 (0)