Jit: Use LazyMemoryRegion-backed bit sets - #14804
Conversation
|
Testing on my end, I do see a difference. Also, there is another use case for this PR, since it can replace the dolphin/Source/Core/Core/PowerPC/JitCommon/JitCache.h Lines 122 to 125 in cd3ea81 So, about that... |
|
That testing methodology sounds as least as good as mine. I've going into "Play Now" and noting down what the lowest observed FPS value is. Do you have a number for how much this PR improves performance in your scenario? What would the advantage of going above u8 be? In my implementation, I guess if you're calling SetBits/ClearBits with a moderate number of bits (let's say somewhere between 8 and 32), using something bigger than u8 could be faster because you either entirely skip the memset or the memset gets passed a size of 0, which lets it exit early... But I'm not sure if that's such a big advantage, and I also don't know if that's a common case. It looks like the JIT either calls ClearBits for a whole block (which probably has a lot of instructions?) or it calls SetBit/ClearBit for a single bit and there's no advantage to going above u8. If you're saying it's not showing up in the profiler, I would say let's not worry about it. |
|
It's not easy to measure, since the difference is not consistent, but it's something like "the intro uncapped is around 29 seconds, PR is around 0.5 seconds faster". With the uint size I was mostly referring to this PR also replacing |
Okay, so something like up to 2% faster. Thanks, that gives me a rough idea.
It's totally fine for the C++ code to use u8 and the assembly code to use u32, or whatever combination you want. Or we could change the JIT to use u8. But after thinking about it, I realized that using u32 or u64 unlocks the microoptimization of not having to mask the shift amount by 7, because both x86-64 and AArch64 mask the shift amount by 31 or 63 for free when you use a 32-bit or 64-bit shift instruction respectively. I'll go with u32. |
|
|
Isn't it the other way around? It should work on little endian only. I'll swap to u32 either way though. |
b673a08 to
fff8304
Compare
5c1a668 to
b99e6d2
Compare
If (offset + size) % BLOCK_SIZE was smaller than offset % BLOCK_SIZE, the loop terminated one iteration too early, potentially leaving a block read-only. None of the existing users of LazyMemoryRegion could trigger this bug, because they never made EnsureMemoryPagesWritable calls that straddled across two blocks, but the next commit will add a new use that does.
79c996c to
a48685f
Compare
ba0071f to
bca9590
Compare
bca9590 to
4790e5f
Compare
JitCache has been using a class called ValidBlockBitSet. This commit replaces it with a new class called LazyMemoryRegionBitSet, which works similarly but is backed by a LazyMemoryRegion, letting us skip allocating memory for parts of the bit set that correspond to emulated memory regions where the game isn't storing any code. I have also added optimized functions for setting or clearing long runs of bits. Additionally, this commit replaces JitBase's three std::unordered_sets that are keeping track of instructions with LazyMemoryRegionBitSets. Here the benefit is more speed than memory usage. This improves NBA Live 2005's menu performance by 1% or so in SuperSamus's testing.
8 MiB is excessively large for the new use cases, and probably a bit overkill for the old use cases too. Let's reduce it to 1 MiB.
Many callers of AlignUp are dividing immediately after aligning. Let's add a helper function for this so callers don't have to specify the alignment size twice.
4790e5f to
f93a8a9
Compare
|
FifoCI detected that this change impacts graphical rendering. Here are the behavior differences detected by the system: Detected differences
|
I was hoping this would help with NBA Live 2005's performance, but unfortunately it doesn't seem to have helped.I'll keep this open for a few days as a draft in case anyone wants to try it, but then I'll close it unless we find out it is in fact faster in some circumstance.New description:
JitCachehas been using a class calledValidBlockBitSet. This PR replaces it with a new class calledLazyMemoryRegionBitSet, which works similarly but is backed by aLazyMemoryRegion, letting us skip allocating memory for parts of the bit set that correspond to emulated memory regions where the game isn't storing any code. I have also added optimized functions for setting or clearing long runs of bits.Additionally, this PR replaces
JitBase's threestd::unordered_sets that are keeping track of instructions withLazyMemoryRegionBitSets. Here the benefit is more speed than memory usage. This improves NBA Live 2005's menu performance by 1% or so in SuperSamus's testing.