Skip to content

Commit bd74da9

Browse files
authored
perf: cache size and jump_target from first pass in to_bytecode (#200)
`ConcreteBytecode.to_bytecode` makes two passes over the instruction list. The first pass (finding jump targets) already calls `c_instr.get_jump_target(offset)` and `c_instr.size` for every instruction. The main loop then called both again — redundantly, at the same offsets. This change stashes `(size, jump_target)` per instruction into a list during the first pass and consumes it via an iterator in the main loop, eliminating all second calls to `get_jump_target` and `size`. | Hotspot | Before | After | |---|---|---| | `ConcreteBytecode.to_bytecode` own | 9.56% | 8.29% | | `ConcreteBytecode.to_bytecode` total | 19.55% | 15.55% | | `ConcreteInstr.get_jump_target` total | 2.74% | gone (< top 20) | | `ConcreteInstr.size` total | 1.30% | gone (< top 20) | | | Range | Avg | |---|---|---| | Before | 214–226 r/s | ~221 r/s | | After | 224–232 r/s | ~229 r/s | ~3.5% throughput improvement.
1 parent e5d1d74 commit bd74da9

1 file changed

Lines changed: 7 additions & 4 deletions

File tree

src/bytecode/concrete.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -782,16 +782,19 @@ def to_bytecode(
782782
c_instructions = self[:]
783783
self._remove_extended_args(c_instructions)
784784

785-
# Find jump targets
785+
# Find jump targets; stash (size, jump_target) to avoid recomputing in the main loop
786786
jump_targets: Set[int] = set()
787+
_instr_props: List[Tuple[int, Optional[int]]] = []
787788
offset = 0
788789
for c_instr in c_instructions:
789790
if isinstance(c_instr, SetLineno):
790791
continue
792+
size = c_instr.size
791793
target = c_instr.get_jump_target(offset)
794+
_instr_props.append((size, target))
792795
if target is not None:
793796
jump_targets.add(target)
794-
offset += c_instr.size // 2
797+
offset += size // 2
795798

796799
# On 3.11+ we need to also look at the exception table for jump targets
797800
for ex_entry in self.exception_table:
@@ -839,6 +842,7 @@ def to_bytecode(
839842
else:
840843
locals_lookup = self.varnames
841844

845+
_props_iter = iter(_instr_props)
842846
for lineno, c_instr in self._normalize_lineno(
843847
c_instructions, self.first_lineno
844848
):
@@ -864,8 +868,7 @@ def to_bytecode(
864868
tb_instrs[entry] = tb_instr
865869
instructions.append(tb_instr)
866870

867-
jump_target = c_instr.get_jump_target(offset)
868-
size = c_instr.size
871+
size, jump_target = next(_props_iter)
869872
# If an instruction uses extended args, those appear before the instruction
870873
# causing the instruction to appear at offset that accounts for extended
871874
# args. So we first update the offset to account for extended args, then

0 commit comments

Comments
 (0)