JIT: allocate and initialize the LSRA VarToRegMaps in one shot - #131400
JIT: allocate and initialize the LSRA VarToRegMaps in one shot#131400EgorBo wants to merge 2 commits into
Conversation
initVarRegMaps made two arena allocations per basic block and filled them a byte at a time, so the cost was O(blocks * tracked locals) of scalar stores plus 2 * blocks allocator calls. Allocate all of the in/out maps as a single block and fill it with one memset instead; the maps are only ever reached through inVarToRegMaps/outVarToRegMaps, which are not modified afterwards. No diffs. Throughput (SPMI, instructions retired): libraries.pmi -0.51% aspnet2.run -0.68% benchmarks.run_pgo -0.63% realworld.run -0.61% coreclr_tests.run -0.29% Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d486224-7977-4f41-8410-21bf27321cee
|
Azure Pipelines: Successfully started running 6 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
This PR optimizes LSRA variable-to-register boundary maps initialization by allocating all per-block in/out VarToRegMaps in one contiguous arena allocation and initializing them in bulk, reducing allocator churn and per-element scalar initialization overhead.
Changes:
- Allocate all block
in/outvar-to-reg maps as one contiguousregNumberSmall[]buffer. - Initialize the full buffer in one pass (using
memsetwhenregNumberSmallis 1 byte). - Point
inVarToRegMaps[i]/outVarToRegMaps[i]at the appropriate slices of the contiguous buffer.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d486224-7977-4f41-8410-21bf27321cee
| if (sizeof(regNumberSmall) == 1) | ||
| { | ||
| memset(maps, REG_STK, entryCount * sizeof(regNumberSmall)); | ||
| } | ||
| else | ||
| { | ||
| for (size_t j = 0; j < entryCount; j++) | ||
| { | ||
| inVarToRegMap[j] = REG_STK; | ||
| outVarToRegMap[j] = REG_STK; | ||
| maps[j] = REG_STK; | ||
| } |
There was a problem hiding this comment.
This can be just the loop everywhere, it should be optimized to memset.
TP gains may actually be a bit misleading, I am not sure if we count instructions executed inside memset.
There was a problem hiding this comment.
TP gains may actually be a bit misleading, I am not sure if we count instructions executed inside memset.
Disregard this, I double checked and we do statically link so clrjit does have its own memset copy. So it should be getting counted properly.
initVarRegMapsmade two arena allocations per basic block and filled them one byte at a time, so it costO(blocks * tracked locals)scalar stores plus2 * blocksallocator calls.All of the in/out maps are now allocated as a single block and filled with one
memset. They are only ever reached throughinVarToRegMaps/outVarToRegMaps, which are not modified after this point, so the maps can live contiguously. Keeping a block's in and out map adjacent also helps locality during resolution.