Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid scaning the used region if there are no free units #81525

Merged
merged 3 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Avoid scaning the used region if there are no free units
  • Loading branch information
cshung committed Feb 2, 2023
commit fa3449dc088abdf8f7f7e4af43513515bd688349
125 changes: 81 additions & 44 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3662,6 +3662,8 @@ bool region_allocator::init (uint8_t* start, uint8_t* end, size_t alignment, uin
global_region_end = (uint8_t*)align_region_down ((size_t)actual_end);
global_region_left_used = global_region_start;
global_region_right_used = global_region_end;
num_left_used_free_units = 0;
num_right_used_free_units = 0;

// Note: I am allocating a map that covers the whole reserved range.
// We can optimize it to only cover the current heap range.
Expand Down Expand Up @@ -3755,14 +3757,22 @@ void region_allocator::print_map (const char* msg)
}
current_index = region_map_right_start;
end_index = region_map_right_end;
if (i == 0)
{
assert (count_free_units == num_left_used_free_units);
}
else
{
assert (count_free_units == num_left_used_free_units + num_right_used_free_units);
}
}

count_free_units += (uint32_t)(region_map_right_start - region_map_left_end);
assert(count_free_units == total_free_units);

uint32_t total_regions = (uint32_t)((global_region_end - global_region_start) / region_alignment);

dprintf (REGIONS_LOG, ("[%s]-----end printing----[%d total, left used %zd, right used %zd]\n", heap_type, total_regions, (region_map_left_end - region_map_left_start), (region_map_right_end - region_map_right_start)));
dprintf (REGIONS_LOG, ("[%s]-----end printing----[%d total, left used %zd (free: %d), right used %zd (free: %d)]\n", heap_type, total_regions, (region_map_left_end - region_map_left_start), num_left_used_free_units, (region_map_right_end - region_map_right_start), num_right_used_free_units));
cshung marked this conversation as resolved.
Show resolved Hide resolved
#endif //_DEBUG
}

Expand Down Expand Up @@ -3846,59 +3856,74 @@ uint8_t* region_allocator::allocate (uint32_t num_units, allocate_direction dire

print_map ("before alloc");

while (((direction == allocate_forward) && (current_index < end_index)) ||
((direction == allocate_backward) && (current_index > end_index)))
if ((direction == allocate_forward) && (num_left_used_free_units >= num_units) ||
(direction == allocate_backward) && (num_right_used_free_units >= num_units))
{
uint32_t current_val = *(current_index - ((direction == -1) ? 1 : 0));
uint32_t current_num_units = get_num_units (current_val);
bool free_p = is_unit_memory_free (current_val);
dprintf (REGIONS_LOG, ("ALLOC[%s: %zd]%d->%d", (free_p ? "F" : "B"), (size_t)current_num_units,
(int)(current_index - region_map_left_start), (int)(current_index + current_num_units - region_map_left_start)));

if (free_p)
while (((direction == allocate_forward) && (current_index < end_index)) ||
((direction == allocate_backward) && (current_index > end_index)))
{
if (current_num_units >= num_units)
{
dprintf (REGIONS_LOG, ("found %zd contiguous free units(%d->%d), sufficient",
(size_t)current_num_units,
(int)(current_index - region_map_left_start),
(int)(current_index - region_map_left_start + current_num_units)));
uint32_t current_val = *(current_index - ((direction == -1) ? 1 : 0));
uint32_t current_num_units = get_num_units (current_val);
bool free_p = is_unit_memory_free (current_val);
dprintf (REGIONS_LOG, ("ALLOC[%s: %zd]%d->%d", (free_p ? "F" : "B"), (size_t)current_num_units,
(int)(current_index - region_map_left_start), (int)(current_index + current_num_units - region_map_left_start)));

uint32_t* busy_block;
uint32_t* free_block;
if (direction == 1)
{
busy_block = current_index;
free_block = current_index + num_units;
}
else
if (free_p)
{
if (current_num_units >= num_units)
{
busy_block = current_index - num_units;
free_block = current_index - current_num_units;
}
dprintf (REGIONS_LOG, ("found %zd contiguous free units(%d->%d), sufficient",
(size_t)current_num_units,
(int)(current_index - region_map_left_start),
(int)(current_index - region_map_left_start + current_num_units)));

make_busy_block (busy_block, num_units);
if ((current_num_units - num_units) > 0)
{
make_free_block (free_block, (current_num_units - num_units));
}
if (direction == allocate_forward)
{
assert (num_left_used_free_units >= num_units);
num_left_used_free_units -= num_units;
}
else
{
assert (num_right_used_free_units >= num_units);
num_right_used_free_units -= num_units;
}

total_free_units -= num_units;
print_map ("alloc: found in free");
uint32_t* busy_block;
uint32_t* free_block;
if (direction == 1)
{
busy_block = current_index;
free_block = current_index + num_units;
}
else
{
busy_block = current_index - num_units;
free_block = current_index - current_num_units;
}

make_busy_block (busy_block, num_units);
if ((current_num_units - num_units) > 0)
{
make_free_block (free_block, (current_num_units - num_units));
}

total_free_units -= num_units;
print_map ("alloc: found in free");

leave_spin_lock();
leave_spin_lock();

return region_address_of (busy_block);
return region_address_of (busy_block);
}
}
}

if (direction == allocate_forward)
{
current_index += current_num_units;
}
else
{
current_index -= current_num_units;
if (direction == allocate_forward)
{
current_index += current_num_units;
}
else
{
current_index -= current_num_units;
}
}
}

Expand Down Expand Up @@ -4014,6 +4039,16 @@ void region_allocator::delete_region_impl (uint8_t* region_start)

int free_block_size = current_val;
uint32_t* free_index = current_index;

if (free_index <= region_map_left_end)
{
num_left_used_free_units += free_block_size;
}
else
{
num_right_used_free_units += free_block_size;
}

if ((current_index != region_map_left_start) && (current_index != region_map_right_start))
{
uint32_t previous_val = *(current_index - 1);
Expand All @@ -4036,13 +4071,15 @@ void region_allocator::delete_region_impl (uint8_t* region_start)
}
if (region_end == global_region_left_used)
{
num_left_used_free_units -= free_block_size;
region_map_left_end = free_index;
dprintf (REGIONS_LOG, ("adjust global left used from %p to %p",
global_region_left_used, region_address_of (free_index)));
global_region_left_used = region_address_of (free_index);
}
else if (region_start == global_region_right_used)
{
num_right_used_free_units -= free_block_size;
region_map_right_start = free_index + free_block_size;
dprintf (REGIONS_LOG, ("adjust global right used from %p to %p",
global_region_right_used, region_address_of (free_index + free_block_size)));
Expand Down
17 changes: 10 additions & 7 deletions src/coreclr/gc/gcpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -5867,14 +5867,14 @@ typedef bool (*region_allocator_callback_fn)(uint8_t*);
//
// For each region we encode the info with a busy block in the map. This block has the
// same # of uints as the # of units this region occupies. And we store the # in
// the starting uint. These uints can be converted to bytes since we have multiple units
// for larger regions anyway. I haven't done that since this will need to be changed in
// the near future based on more optimal allocation strategies.
// the first and last uint. These uints can be converted to bytes since we have multiple
// units for larger regions anyway. I haven't done that since this will need to be changed
// in the near future based on more optimal allocation strategies.
//
// When we allocate, we search forward to find contiguous free units >= num_units
// We do take the opportunity to coalesce free blocks but we do not coalesce busy blocks.
// When we decommit a region, we simply mark its block free. Free blocks are coalesced
// opportunistically when we need to walk them.
// When we allocate, if we knew there could be free blocks that fits, we search forward to find
// contiguous free units >= num_units. Otherwise we simply allocate at the end. We coalesce
// free blocks but we do not coalesce busy blocks. When we delete a region, we mark the block
// free and coalesced them with its free neighbors if any.
//
// TODO: to accommodate 32-bit processes, we reserve in segment sizes and divide each seg
// into regions.
Expand All @@ -5900,6 +5900,9 @@ class region_allocator
uint32_t* region_map_right_start;
uint32_t* region_map_right_end;

uint32_t num_left_used_free_units;
uint32_t num_right_used_free_units;

uint8_t* region_address_of (uint32_t* map_index);
uint32_t* region_map_index_of (uint8_t* address);

Expand Down