diff --git a/code2/grime/fixed_arena.odin b/code2/grime/fixed_arena.odin index 2847810..b31b54f 100644 --- a/code2/grime/fixed_arena.odin +++ b/code2/grime/fixed_arena.odin @@ -172,6 +172,6 @@ when ODIN_DEBUG { farena_allocator :: #force_inline proc "contextless" (arena: ^FArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{proc_id = .FArena, data = arena} } } else { - farena_ainfo :: #force_inline proc "contextless" (arena: ^FArena) -> AllocatorInfo { return AllocatorInfo{procedure = farena_allocator_proc, data = arena} } - farena_allocator :: #force_inline proc "contextless" (arena: ^FArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = farena_odin_allocator_proc, data = arena} } + farena_ainfo :: #force_inline proc "contextless" (arena: ^FArena) -> AllocatorInfo { return AllocatorInfo{procedure = farena_allocator_proc, data = arena} } + farena_allocator :: #force_inline proc "contextless" (arena: ^FArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = farena_allocator_proc, data = arena} } } diff --git a/code2/grime/ring_buffer_fixed.odin b/code2/grime/fixed_ring_buffer.odin similarity index 100% rename from code2/grime/ring_buffer_fixed.odin rename to code2/grime/fixed_ring_buffer.odin diff --git a/code2/grime/key_table.odin b/code2/grime/key_table.odin new file mode 100644 index 0000000..d68cdf0 --- /dev/null +++ b/code2/grime/key_table.odin @@ -0,0 +1,141 @@ +package grime + +/* +Hassh Table based on John's Jai & Sean Barrett's +I don't like the table definition cntaining +the allocator, hash or compare procedure to be used. +So it has been stripped and instead applied on procedure site, +the parent container or is responsible for tracking that. + +TODO(Ed): Resolve appropriate Key-Table term for it. +*/ + +KT_Slot :: struct( + $TypeHash: typeid, + $TypeKey: typeid, + $TypeValue: typeid +) { + hash: TypeHash, + key: TypeKey, + value: TypeValue, +} + +KT :: struct($KT_Slot: typeid) { + load_factor_perent: int, + count: int, + allocated: int, + slots_filled: int, + slots: []KT_Slot, +} + +KT_Info :: struct { + key_width: int, + value_width: int, + slot_width: int, +} + +KT_Opaque :: struct { + count: int, + allocated: int, + slots_filled: int, + slots: []byte, +} + +KT_ByteMeta :: struct { + hash_width: int, + value_width: int, +} + +KT_COUNT_COLLISIONS :: #config(KT_COUNT_COLLISIONS, false) + +KT_HASH_NEVER_OCCUPIED :: 0 +KT_HASH_REMOVED :: 1 +KT_HASH_FIRST_VALID :: 2 +KT_LOAD_FACTOR_PERCENT :: 70 + +kt_byte_init :: proc(info: KT_Info, tbl_allocator: Odin_Allocator, kt: ^KT_Opaque, $HashType: typeid) +{ + #assert(size_of(HashType) >= 32) + assert(tbl_allocator.procedure != nil) + assert(info.value_width >= 32) + assert(info.slot_width >= 64) +} +kt_deinit :: proc(table: ^$KT / typeid, allocator: Odin_Allocator) +{ + +} + +kt_walk_table_body_proc :: #type proc($TypeHash: typeid, hash: TypeHash, kt: ^KT_Opaque, info: KT_Info, id: TypeHash) -> (should_break: bool) +kt_walk_table :: proc($TypeHash: typeid, hash: TypeHash, kt: ^KT_Opaque, info: KT_Info, $walk_body: kt_walk_table_body_proc) -> (index: TypeHash) +{ + mask := cast(TypeHash)(kt.allocated - 1) // Cast may truncate + if hash < KT_HASH_FIRST_VALID do hash += KT_HASH_FIRST_VALID + index : TypeHash = hash & mask + probe_increment: TypeHash = 1 + for id := transmute(TypeHash) kt.slots[info.slot_width * index:]; id != 0; + { + if #force_inline walk_body(hash, kt, info, id) do break + index = (index + probe_increment) & mask + probe_increment += 1 + } +} + +// Will not expand table if capacity reached, user must do that check beforehand. +// Will return existing if hash found +kt_byte_add :: proc(value: [^]byte, key: [^]byte, hash: $TypeHash, kt: ^KT_Opaque, info: KT_Info)-> [^]byte +{ + aasert(kt.slots_filled, kt.allocated) + index := #force_inline kt_walk_table(hash, kt, info, + proc(hash: $TypeHash, kt: ^KT_Opaque, info: KT_Info, id: TypeHash) -> (should_break: bool) + { + if id == KT_HASH_REMOVED { + kt.slots_filled -= 1 + should_break = true + return + } + //TODO(Ed): Add collision tracking + return + }) + kt.count += 1 + kt.slots_filled += 1 + slot_offset := info.slot_width * index + entry := table.slots[info.slot_width * index:] + mem_copy_non_overlapping(entry, hash, size_of(TypeHash)) + mem_copy_non_overlapping(entry[size_of(hash):], key, info.key_width) + mem_copy_non_overlapping(entry[size_of(hash) + size_of(key):], value, info.value_width) + return entry +} + +// Will not expand table if capacity reached, user must do that check beforehand. +// Will override if hash exists +kt_byte_set :: proc() +{ + +} + +kt_remove :: proc() +{ + +} + +kt_byte_contains :: proc() +{ + +} + +kt_byte_find_pointer :: proc() +{ + +} + +kt_find :: proc() +{ + +} + +kt_find_multiple :: proc() +{ + +} + +kt_next_power_of_two :: #force_inline proc(x: int) -> int { power := 1; for ;x > power; do power += power; return power } diff --git a/code2/grime/key_table_1_layer_linear.odin b/code2/grime/key_table_1_layer_linear.odin index 3707792..8b8c15a 100644 --- a/code2/grime/key_table_1_layer_linear.odin +++ b/code2/grime/key_table_1_layer_linear.odin @@ -9,9 +9,9 @@ KT1L_Slot :: struct($Type: typeid) { value: Type, } KT1L_Meta :: struct { - slot_size: uintptr, - kt_value_offset: uintptr, - type_width: uintptr, + slot_size: int, + kt_value_offset: int, + type_width: int, type: typeid, } kt1l_populate_slice_a2_Slice_Byte :: proc(kt: ^[]byte, backing: AllocatorInfo, values: []byte, num_values: int, m: KT1L_Meta) { @@ -21,7 +21,7 @@ kt1l_populate_slice_a2_Slice_Byte :: proc(kt: ^[]byte, backing: AllocatorInfo, v kt^, _ = mem_alloc(table_size_bytes, ainfo = transmute(Odin_Allocator) backing) slice_assert(kt ^) kt_raw : SliceByte = transmute(SliceByte) kt^ - for id in 0 ..< cast(uintptr) num_values { + for id in 0 ..< num_values { slot_offset := id * m.slot_size // slot id slot_cursor := kt_raw.data[slot_offset:] // slots[id] type: KT1L_ // slot_key := transmute(^u64) slot_cursor // slots[id].key type: U64 @@ -30,7 +30,7 @@ kt1l_populate_slice_a2_Slice_Byte :: proc(kt: ^[]byte, backing: AllocatorInfo, v a2_cursor := cursor(values)[a2_offset:] // a2_entries[id] type: A2_ // a2_key := (transmute(^[]byte) a2_cursor) ^ // a2_entries[id].key type: // a2_value := slice(a2_cursor[m.type_width:], m.type_width) // a2_entries[id].value type: - mem_copy_non_overlapping(slot_cursor[m.kt_value_offset:], a2_cursor[m.type_width:], cast(int) m.type_width) // slots[id].value = a2_entries[id].value + mem_copy_non_overlapping(slot_cursor[m.kt_value_offset:], a2_cursor[m.type_width:], m.type_width) // slots[id].value = a2_entries[id].value (transmute([^]u64) slot_cursor)[0] = 0; hash64_djb8(transmute(^u64) slot_cursor, (transmute(^[]byte) a2_cursor) ^) // slots[id].key = hash64_djb8(a2_entries[id].key) } diff --git a/code2/grime/string_cache.odin b/code2/grime/string_cache.odin new file mode 100644 index 0000000..9bf56f9 --- /dev/null +++ b/code2/grime/string_cache.odin @@ -0,0 +1,28 @@ +package grime + +StrKey_U4 :: struct { + len: u32, // Length of string + offset: u32, // Offset in varena +} + +StrKT_U4_Cell_Depth :: 4 + +StrKT_U4_Slot :: KT1CX_Slot(StrKey_U4) +StrKT_U4_Cell :: KT1CX_Cell(StrKT_U4_Slot, 4) +StrKT_U4_Table :: KT1CX(StrKT_U4_Cell) + +VStrKT_U4 :: struct { + varena: VArena, // Backed by growing vmem + entries: StrKT_U4_Table +} + +vstrkt_u4_init :: proc(varena: ^VArena) -> (cache: ^VStrKT_U4) +{ + return nil +} + +vstrkt_u4_intern :: proc(cache: ^VStrKT_U4) -> StrKey_U4 +{ + // profile(#procedure) + return {} +} diff --git a/code2/grime/virtual_arena.odin b/code2/grime/virtual_arena.odin index 0ba77b2..631fe1a 100644 --- a/code2/grime/virtual_arena.odin +++ b/code2/grime/virtual_arena.odin @@ -292,6 +292,6 @@ when ODIN_DEBUG { varena_allocator :: #force_inline proc "contextless" (arena: ^VArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{proc_id = .VArena, data = arena} } } else { - varena_ainfo :: #force_inline proc "contextless" (arena: ^VArena) -> AllocatorInfo { return AllocatorInfo{procedure = varena_allocator_proc, data = arena} } - varena_allocator :: #force_inline proc "contextless" (arena: ^VArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = varena_odin_allocator_proc, data = arena} } + varena_ainfo :: #force_inline proc "contextless" (arena: ^VArena) -> AllocatorInfo { return AllocatorInfo{procedure = varena_allocator_proc, data = arena} } + varena_allocator :: #force_inline proc "contextless" (arena: ^VArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = varena_allocator_proc, data = arena} } } diff --git a/code2/host/host.odin b/code2/host/host.odin index 2af745b..e6c5e73 100644 --- a/code2/host/host.odin +++ b/code2/host/host.odin @@ -23,14 +23,14 @@ load_client_api :: proc(version_id: int) -> (loaded_module: Client_API) { file_copy_sync( Path_Sectr_Module, Path_Sectr_Live_Module, allocator = context.temp_allocator ) did_load: bool; lib, did_load = os_lib_load( Path_Sectr_Live_Module ) if ! did_load do panic( "Failed to load the sectr module.") - startup = cast( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup") - shutdown = cast( type_of( host_memory.client_api.shutdown)) os_lib_get_proc(lib, "sectr_shutdown") - tick_lane_startup = cast( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup") - job_worker_startup = cast( type_of( host_memory.client_api.job_worker_startup)) os_lib_get_proc(lib, "job_worker_startup") - hot_reload = cast( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload") - tick_lane = cast( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane") - clean_frame = cast( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame") - jobsys_worker_tick = cast( type_of( host_memory.client_api.jobsys_worker_tick)) os_lib_get_proc(lib, "jobsys_worker_tick") + startup = transmute( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup") + shutdown = transmute( type_of( host_memory.client_api.shutdown)) os_lib_get_proc(lib, "sectr_shutdown") + tick_lane_startup = transmute( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup") + job_worker_startup = transmute( type_of( host_memory.client_api.job_worker_startup)) os_lib_get_proc(lib, "job_worker_startup") + hot_reload = transmute( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload") + tick_lane = transmute( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane") + clean_frame = transmute( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame") + jobsys_worker_tick = transmute( type_of( host_memory.client_api.jobsys_worker_tick)) os_lib_get_proc(lib, "jobsys_worker_tick") if startup == nil do panic("Failed to load sectr.startup symbol" ) if shutdown == nil do panic("Failed to load sectr.shutdown symbol" ) if tick_lane_startup == nil do panic("Failed to load sectr.tick_lane_startup symbol" ) diff --git a/config/sectr_config.mdesk b/config/sectr_config.mdesk new file mode 100644 index 0000000..e69de29 diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 3fec489..ce812e9 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -216,8 +216,8 @@ push-location $path_root $build_args += $flag_microarch_zen5 $build_args += $flag_use_separate_modules $build_args += $flag_thread_count + $CoreCount_Physical - $build_args += $flag_optimize_none - # $build_args += $flag_optimize_minimal + # $build_args += $flag_optimize_none + $build_args += $flag_optimize_minimal # $build_args += $flag_optimize_speed # $build_args += $falg_optimize_aggressive $build_args += $flag_debug