From: notaz Date: Sat, 21 Feb 2026 01:37:06 +0000 (+0200) Subject: drc: more efficient state load X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9b9ecaf46d0975eec80c60dca0fb72fb25d5c54;p=pcsx_rearmed.git drc: more efficient state load maybe --- diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c index bdee4086..2af16a87 100644 --- a/libpcsxcore/lightrec/plugin.c +++ b/libpcsxcore/lightrec/plugin.c @@ -727,6 +727,7 @@ static void lightrec_plugin_notify(enum R3000Anote note, void *data) lightrec_plugin_sync_regs_to_pcsx(data == NULL); break; case R3000ACPU_NOTIFY_AFTER_LOAD: + case R3000ACPU_NOTIFY_AFTER_LOAD_STATE: lightrec_plugin_sync_regs_from_pcsx(data == NULL); if (data == NULL) lightrec_invalidate_all(lightrec_state); diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index b7eaa931..6c10c25a 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -920,7 +920,7 @@ int LoadState(const char *file) { if (Config.HLE) psxBiosCheckExe(biosBranchCheckOld, 0x60, 1); - psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); + psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD_STATE, NULL); result = 0; cleanup: diff --git a/libpcsxcore/new_dynarec/emu_if.c b/libpcsxcore/new_dynarec/emu_if.c index 48027464..c13e9825 100644 --- a/libpcsxcore/new_dynarec/emu_if.c +++ b/libpcsxcore/new_dynarec/emu_if.c @@ -60,23 +60,27 @@ void ndrc_freeze(void *f, int mode) SaveFuncs.write(f, addrs, size); } else { - bytes = SaveFuncs.read(f, header, sizeof(header)); - if (bytes != sizeof(header) || strcmp(header, header_save)) { - if (bytes > 0) - SaveFuncs.seek(f, -bytes, SEEK_CUR); - return; - } - SaveFuncs.read(f, &size, sizeof(size)); - if (size <= 0) - return; - if (size > sizeof(addrs)) { - bytes = size - sizeof(addrs); - SaveFuncs.seek(f, bytes, SEEK_CUR); - size = sizeof(addrs); - } - bytes = SaveFuncs.read(f, addrs, size); - if (bytes != size) - return; + do { + bytes = SaveFuncs.read(f, header, sizeof(header)); + if (bytes != sizeof(header) || strcmp(header, header_save)) { + if (bytes > 0) + SaveFuncs.seek(f, -bytes, SEEK_CUR); + break; + } + SaveFuncs.read(f, &size, sizeof(size)); + if (size <= 0) { + size = 0; + break; + } + if (size > sizeof(addrs)) { + bytes = size - sizeof(addrs); + SaveFuncs.seek(f, bytes, SEEK_CUR); + size = sizeof(addrs); + } + bytes = SaveFuncs.read(f, addrs, size); + if (bytes != size) + size = 0; + } while (0); if (psxCpu != &psxInt) new_dynarec_load_blocks(addrs, size); @@ -289,6 +293,9 @@ static void ari64_notify(enum R3000Anote note, void *data) { break; case R3000ACPU_NOTIFY_AFTER_LOAD: ari64_on_ext_change(data == NULL, 0); + // fallthrough + // for state load, we take no action to not duplicate ndrc_freeze() work + case R3000ACPU_NOTIFY_AFTER_LOAD_STATE: psxInt.Notify(note, data); break; } diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index b004b687..004d0363 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -325,7 +325,6 @@ static struct compile_info static u_int vsync_hack; #ifdef STAT_PRINT static int stat_bc_direct; - static int stat_bc_pre; static int stat_bc_restore; static int stat_ht_lookups; static int stat_jump_in_lookups; @@ -433,6 +432,7 @@ static void ndrc_write_invalidate_many(u_int addr, u_int end); static int new_recompile_block(u_int addr); static void invalidate_block(struct block_info *block); +static void block_clear_jump_outs(struct block_info *block, int unlink); static void exception_assemble(struct compile_state *st, int i, const struct regstat *i_regs, int ccadj_); @@ -1533,6 +1533,16 @@ static void blocks_clear(struct block_info **head) } } +static void unlink_jump(u_int target_vaddr, void *stub) +{ + void *host_addr = find_extjump_insn(stub); + inv_debug("INV: rm link to %08x (tc_offs %06zx->%06zx)\n", target_vaddr, + (u_char *)host_addr - ndrc->translation_cache, + (u_char *)stub - ndrc->translation_cache); + mark_clear_cache(host_addr); + set_jump_target(host_addr, stub); // point back to dyna_linker stub +} + // This is called when we write to a compiled block (see do_invstub) static void unlink_jumps_vaddr_range(u_int start, u_int end) { @@ -1549,13 +1559,7 @@ static void unlink_jumps_vaddr_range(u_int start, u_int end) continue; } - void *host_addr = find_extjump_insn(ji->e[i].stub); - inv_debug("INV: rm link to %08x (tc_offs %06zx->%06zx)\n", ji->e[i].target_vaddr, - (u_char *)host_addr - ndrc->translation_cache, - (u_char *)ji->e[i].stub - ndrc->translation_cache); - mark_clear_cache(host_addr); - set_jump_target(host_addr, ji->e[i].stub); // point back to dyna_linker stub - + unlink_jump(ji->e[i].target_vaddr, ji->e[i].stub); stat_dec(stat_links); ji->count--; if (i < ji->count) { @@ -1690,8 +1694,6 @@ void ndrc_write_invalidate_one(u_int addr) ndrc_write_invalidate_many(addr, addr + 4); } -// This is called when loading a save state. -// Anything could have changed, so invalidate everything. void new_dynarec_invalidate_all_pages(void) { struct block_info *block; @@ -1705,6 +1707,14 @@ void new_dynarec_invalidate_all_pages(void) invalidate_block(block); } } + for (page = 0; page < ARRAY_SIZE(jumps); page++) { + struct jump_info *ji = jumps[page]; + if (ji) { + assert(ji->count == 0); + free(ji); + jumps[page] = NULL; + } + } do_clear_cache(); mini_ht_clear(); @@ -6633,24 +6643,36 @@ void new_dynarec_load_blocks(const void *save, int size) uint32_t f; int i, b; - // restore clean blocks, if any + // update all block dirty-ness for (page = 0, b = i = 0; page < ARRAY_SIZE(blocks); page++) { for (block = blocks[page]; block != NULL; block = block->next_by_vaddr, b++) { - if (!block->is_dirty) + if (!block->source) // hack block? continue; assert(block->source && block->copy); - if (memcmp(block->source, block->copy, block->len)) + if (memcmp(block->source, block->copy, block->len)) { + invalidate_block(block); + block_clear_jump_outs(block, 1); continue; + } // see try_restore_block - block->is_dirty = 0; + block->is_dirty = block->inv_near_misses = 0; mark_invalid_code(block->start, block->len, 0); i++; } } inv_debug("load_blocks: %d/%d clean blocks\n", i, b); - // change GPRs for speculation to at least partially work.. + for (page = 0; page < ARRAY_SIZE(jumps); page++) { + if (jumps[page] && jumps[page]->count == 0) { + free(jumps[page]); + jumps[page] = NULL; + } + } + do_clear_cache(); + mini_ht_clear(); + + // change GPRs for speculation to at least partially work... memcpy(regs_save, &psxRegs.GPR, sizeof(regs_save)); for (i = 1; i < 32; i++) psxRegs.GPR.r[i] = 0x80000000; @@ -6682,12 +6704,12 @@ void new_dynarec_print_stats(void) lmem += sizeof(*ji) + ji->alloc * sizeof(ji->e[0]) + sizeof(size_t) * 2; } - printf("cc %3d,%3d,%3d lu%6d,%3d,%3d c%3d inv%3d,%3d tc_offs %06zx b %u l %u/%zd\n", - stat_bc_pre, stat_bc_direct, stat_bc_restore, + printf("cc %3d,%3d lu%6d,%3d,%3d c%3d inv%3d,%3d tc_offs %06zx b %u l %u/%zd\n", + stat_bc_direct, stat_bc_restore, stat_ht_lookups, stat_jump_in_lookups, stat_restore_tries, stat_restore_compares, stat_inv_addr_calls, stat_inv_hits, out - ndrc->translation_cache, stat_blocks, stat_links, lmem); - stat_bc_direct = stat_bc_pre = stat_bc_restore = + stat_bc_direct = stat_bc_restore = stat_ht_lookups = stat_jump_in_lookups = stat_restore_tries = stat_restore_compares = stat_inv_addr_calls = stat_inv_hits = 0; #endif @@ -9155,39 +9177,46 @@ static u_int *get_jump_outs(struct block_info *block) block->jump_in_cnt * sizeof(block->jump_in[0])); } -static void block_destroy(struct block_info *block) +static void block_clear_jump_outs(struct block_info *block, int unlink) { - u_int page = get_page(block->start); - struct block_info **b_pptr; u_int *jump_outs; - int i, j; - - if (block == block_last_compiled) - block_last_compiled = NULL; - invalidate_block(block); + int jo, i; jump_outs = get_jump_outs(block); - for (i = 0; i < block->jump_out_cnt; i++) { - u_int t_vaddr = jump_outs[i]; + for (jo = 0; jo < block->jump_out_cnt; jo++) { + u_int t_vaddr = jump_outs[jo]; u_int t_page = get_page(t_vaddr); struct jump_info *ji = jumps[t_page]; if (ji) - for (j = 0; j < ji->count; ) { + for (i = 0; i < ji->count; ) { uintptr_t j_tc_offs; - if (t_vaddr != ji->e[j].target_vaddr) { - j++; continue; + if (t_vaddr != ji->e[i].target_vaddr) { + i++; continue; } - j_tc_offs = (u_char *)ji->e[j].stub - ndrc->translation_cache; + j_tc_offs = (u_char *)ji->e[i].stub - ndrc->translation_cache; if (j_tc_offs < block->tc_offs || j_tc_offs >= block->tc_offs + block->tc_len) { - j++; continue; + i++; continue; } // remove the entry + if (unlink) + unlink_jump(ji->e[i].target_vaddr, ji->e[i].stub); stat_dec(stat_links); ji->count--; - if (j < ji->count) - ji->e[j] = ji->e[ji->count]; + if (i < ji->count) + ji->e[i] = ji->e[ji->count]; } } +} + +static void block_destroy(struct block_info *block) +{ + u_int page = get_page(block->start); + struct block_info **b_pptr; + + if (block == block_last_compiled) + block_last_compiled = NULL; + invalidate_block(block); + block_clear_jump_outs(block, 0); // rm from the blocks list for (b_pptr = &blocks[page]; *b_pptr; b_pptr = &((*b_pptr)->next_by_vaddr)) { diff --git a/libpcsxcore/psxinterpreter.c b/libpcsxcore/psxinterpreter.c index ad69c5f0..7f666e57 100644 --- a/libpcsxcore/psxinterpreter.c +++ b/libpcsxcore/psxinterpreter.c @@ -1253,6 +1253,7 @@ static void intNotify(enum R3000Anote note, void *data) { dloadFlush(&psxRegs); break; case R3000ACPU_NOTIFY_AFTER_LOAD: + case R3000ACPU_NOTIFY_AFTER_LOAD_STATE: dloadClear(&psxRegs); psxRegs.subCycle = 0; setupCop(psxRegs.CP0.n.SR); diff --git a/libpcsxcore/r3000a.h b/libpcsxcore/r3000a.h index 1de1ebd5..fb0f7c6c 100644 --- a/libpcsxcore/r3000a.h +++ b/libpcsxcore/r3000a.h @@ -48,8 +48,10 @@ enum R3000Aexception { enum R3000Anote { R3000ACPU_NOTIFY_CACHE_ISOLATED = 0, R3000ACPU_NOTIFY_CACHE_UNISOLATED = 1, + // this is to sync any cached cpu core state with one in psxRegs R3000ACPU_NOTIFY_BEFORE_SAVE, // data arg - hle if non-null - R3000ACPU_NOTIFY_AFTER_LOAD, + R3000ACPU_NOTIFY_AFTER_LOAD, // data arg - full ram if null + R3000ACPU_NOTIFY_AFTER_LOAD_STATE, // same, but only after savestate load }; enum blockExecCaller {