filter out duplicate page entries before computing the buffer size

This commit is contained in:
Nikita Smith
2026-01-16 18:52:55 -08:00
parent 4ab89cd120
commit 8f47ce7616
3 changed files with 64 additions and 41 deletions
+8 -4
View File
@@ -26,16 +26,20 @@ void_node_concat_atomic(VoidNode **head, VoidNode *node)
node->next = ins_atomic_ptr_eval_assign(head, node); node->next = ins_atomic_ptr_eval_assign(head, node);
} }
internal void
u64_list_push_node(U64List *list, U64Node *n)
{
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
internal U64Node * internal U64Node *
u64_list_push(Arena *arena, U64List *list, U64 data) u64_list_push(Arena *arena, U64List *list, U64 data)
{ {
U64Node *n = push_array(arena, U64Node, 1); U64Node *n = push_array(arena, U64Node, 1);
n->next = 0; n->next = 0;
n->data = data; n->data = data;
u64_list_push_node(list, n);
SLLQueuePush(list->first, list->last, n);
++list->count;
return n; return n;
} }
+1
View File
@@ -30,6 +30,7 @@ typedef struct VoidNode
//////////////////////////////// ////////////////////////////////
internal void u64_list_push_node(U64List *list, U64Node *n);
internal U64Node * u64_list_push(Arena *arena, U64List *list, U64 data); internal U64Node * u64_list_push(Arena *arena, U64List *list, U64 data);
internal void u64_list_concat_in_place(U64List *list, U64List *to_concat); internal void u64_list_concat_in_place(U64List *list, U64List *to_concat);
internal U64Array u64_array_from_list(Arena *arena, U64List *list); internal U64Array u64_array_from_list(Arena *arena, U64List *list);
+54 -36
View File
@@ -3637,6 +3637,48 @@ THREAD_POOL_TASK_FUNC(lnk_gather_base_reloc_pages_task)
ProfEnd(); ProfEnd();
} }
internal
THREAD_POOL_TASK_FUNC(lnk_filter_out_duplicate_base_reloc_entries_task)
{
ProfBeginFunction();
Temp scratch = scratch_begin(0, 0);
LNK_BaseRelocsTask *task = raw_task;
HashTable *voff_ht = hash_table_init(scratch.arena, task->page_size);
for EachInRange(page_idx, task->serialize.ranges[task_id]) {
LNK_BaseRelocPage *page = &task->serialize.pages.v[page_idx];
U64List unique_entries32 = {0};
U64List unique_entries64 = {0};
// filter out duplicate 32-bit virtual offsets
for (U64Node *curr = page->entries_addr32->first, *next; curr != 0; curr = next) {
next = curr->next;
if (hash_table_search_u64(voff_ht, curr->data)) { continue; }
hash_table_push_u64_u64(scratch.arena, voff_ht, curr->data, 0);
u64_list_push_node(&unique_entries32, curr);
}
// filter out duplicate 64-bit virtual offsets
for (U64Node *curr = page->entries_addr64->first, *next; curr != 0; curr = next) {
next = curr->next;
if (hash_table_search_u64(voff_ht, curr->data)) { continue; }
hash_table_push_u64_u64(scratch.arena, voff_ht, curr->data, 0);
u64_list_push_node(&unique_entries64, curr);
}
*page->entries_addr32 = unique_entries32;
*page->entries_addr64 = unique_entries64;
// purge hash table for the next run
hash_table_purge(voff_ht);
}
scratch_end(scratch);
ProfEnd();
}
internal internal
THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task) THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task)
{ {
@@ -3644,37 +3686,10 @@ THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task)
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
LNK_BaseRelocsTask *task = raw_task; LNK_BaseRelocsTask *task = raw_task;
HashTable *voff_ht = hash_table_init(scratch.arena, task->page_size);
U64 voffs_max = task->page_size;
U32 *voffs32 = push_array(scratch.arena, U32, voffs_max);
U64 *voffs64 = push_array(scratch.arena, U64, voffs_max);
for EachInRange(page_idx, task->serialize.ranges[task_id]) { for EachInRange(page_idx, task->serialize.ranges[task_id]) {
LNK_BaseRelocPage *page = &task->serialize.pages.v[page_idx]; LNK_BaseRelocPage *page = &task->serialize.pages.v[page_idx];
// filter out duplicate 32-bit virtual offsets
U64 voff_count32 = 0;
for EachNode(voff_n, U64Node, page->entries_addr32->first) {
if (hash_table_search_u64(voff_ht, voff_n->data)) { continue; }
hash_table_push_u64_u64(scratch.arena, voff_ht, voff_n->data, 0);
voffs32[voff_count32] = voff_n->data;
voff_count32 += 1;
}
// filter out duplicate 64-bit virtual offsets
U64 voff_count64 = 0;
for EachNode(voff_n, U64Node, page->entries_addr64->first) {
if (hash_table_search_u64(voff_ht, voff_n->data)) { continue; }
hash_table_push_u64_u64(scratch.arena, voff_ht, voff_n->data, 0);
voffs64[voff_count64] = voff_n->data;
voff_count64 += 1;
}
// gather step is not deterministic
radsort(voffs32, voff_count32, u32_is_before);
radsort(voffs64, voff_count64, u64_is_before);
// find block bytes in the buffer // find block bytes in the buffer
void *block = task->serialize.buffer + page->buffer_offset; void *block = task->serialize.buffer + page->buffer_offset;
@@ -3685,18 +3700,22 @@ THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task)
U16 *reloc_arr_ptr = reloc_arr_base; U16 *reloc_arr_ptr = reloc_arr_base;
// write 32-bit relocation entries // write 32-bit relocation entries
for EachIndex(i, voff_count32) { U16 *reloc_entries32 = reloc_arr_ptr;
U64 rel_off = voffs32[i] - page->voff; for EachNode(n, U64Node, page->entries_addr32->first) {
U64 rel_off = n->data - page->voff;
*reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_HIGHLOW, rel_off); *reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_HIGHLOW, rel_off);
reloc_arr_ptr += 1; reloc_arr_ptr += 1;
} }
radsort(reloc_entries32, page->entries_addr32->count, u16_is_before);
// write 64-bit relocation entries // write 64-bit relocation entries
for EachIndex(i, voff_count64) { U16 *reloc_entries64 = reloc_arr_ptr;
U64 rel_off = voffs64[i] - page->voff; for EachNode(n, U64Node, page->entries_addr64->first) {
U64 rel_off = n->data - page->voff;
*reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_DIR64, rel_off); *reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_DIR64, rel_off);
reloc_arr_ptr += 1; reloc_arr_ptr += 1;
} }
radsort(reloc_entries64, page->entries_addr64->count, u16_is_before);
// compute block size // compute block size
U64 reloc_arr_size = IntFromPtr(reloc_arr_ptr - reloc_arr_base) * sizeof(reloc_arr_ptr[0]); U64 reloc_arr_size = IntFromPtr(reloc_arr_ptr - reloc_arr_base) * sizeof(reloc_arr_ptr[0]);
@@ -3710,9 +3729,6 @@ THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task)
// write page header // write page header
*page_voff_ptr = safe_cast_u32(page->voff); *page_voff_ptr = safe_cast_u32(page->voff);
*block_size_ptr = safe_cast_u32(block_size_aligned); *block_size_ptr = safe_cast_u32(block_size_aligned);
// purge hash table for the next run
hash_table_purge(voff_ht);
} }
scratch_end(scratch); scratch_end(scratch);
@@ -3786,6 +3802,10 @@ lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, U6
String8 base_relocs = {0}; String8 base_relocs = {0};
{ {
task.serialize.pages = pages;
task.serialize.ranges = tp_divide_work(scratch.arena, pages.count, tp->worker_count);
tp_for_parallel(tp, 0, tp->worker_count, lnk_filter_out_duplicate_base_reloc_entries_task, &task);
ProfBegin("Compute Buffer Size"); ProfBegin("Compute Buffer Size");
U64 buffer_size = 0; U64 buffer_size = 0;
for EachIndex(page_idx, pages.count) { for EachIndex(page_idx, pages.count) {
@@ -3804,8 +3824,6 @@ lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, U6
task.serialize.buffer_size = buffer_size; task.serialize.buffer_size = buffer_size;
task.serialize.buffer = buffer; task.serialize.buffer = buffer;
task.serialize.pages = pages;
task.serialize.ranges = tp_divide_work(scratch.arena, pages.count, tp->worker_count);
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_serialize_base_reloc_pages_task, &task, "Serialize"); tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_serialize_base_reloc_pages_task, &task, "Serialize");
base_relocs = str8(task.serialize.buffer, task.serialize.buffer_size); base_relocs = str8(task.serialize.buffer, task.serialize.buffer_size);