• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Nix flake for RPython interpreters


Commit MetaInfo

Révision4a430c6d0514bed189fdc75fed602fad9a3811a5 (tree)
l'heure2024-04-20 10:32:57
AuteurCorbin <cds@corb...>
CommiterCorbin

Message de Log

bf: Hash-cons all ops.

This is so many lines of code, but it pays off. In exchange for around
30 lines of code, we get about a 50% improvement on Mandelbrot time
spent in JIT, and maybe a 10-15% speedup.

What's happening here? RPython JIT greens are compared by pointer when
they are structs, not by contents. There's no way to override this,
because the comparison is on the JIT's hot path for interp. Instead, we
have to hash-cons the entire structure of ops so that two ops will
compare equal by pointer when they are equal by contents. This could be
generated, somewhat, but there's no good answer for the linear scan on
loops or other variadic components.

So, the hash-consing means fewer code objects, which improves the JIT's
performance because it doesn't recompile equivalent code multiple times.

Change Summary

Modification

--- a/bf/bf.py
+++ b/bf/bf.py
@@ -8,6 +8,12 @@ import sys
88 from rpython.jit.codewriter.policy import JitPolicy
99 from rpython.rlib.jit import JitDriver, purefunction
1010
11+def opEq(ops1, ops2):
12+ if len(ops1) != len(ops2): return False
13+ for i, op in enumerate(ops1):
14+ if op is not ops2[i]: return False
15+ return True
16+
1117 def printableProgram(program): return program.asStr()
1218
1319 jitdriver = JitDriver(greens=['program'], reds=['position', 'tape'],
@@ -35,15 +41,23 @@ class Add(Op):
3541 def runOn(self, tape, position):
3642 tape[position] += self.imm
3743 return position
38-Inc = Add(1)
39-Dec = Add(-1)
44+addCache = {}
45+def add(imm):
46+ if imm not in addCache: addCache[imm] = Add(imm)
47+ return addCache[imm]
48+Inc = add(1)
49+Dec = add(-1)
4050 class Shift(Op):
4151 _immutable_fields_ = "width",
4252 def __init__(self, width): self.width = width
4353 def asStr(self): return "shift(%d)" % self.width
4454 def runOn(self, tape, position): return position + self.width
45-Left = Shift(-1)
46-Right = Shift(1)
55+shiftCache = {}
56+def shift(width):
57+ if width not in shiftCache: shiftCache[width] = Shift(width)
58+ return shiftCache[width]
59+Left = shift(-1)
60+Right = shift(1)
4761 class _Zero(Op):
4862 def asStr(self): return "0"
4963 def runOn(self, tape, position):
@@ -60,6 +74,11 @@ class ZeroScaleAdd(Op):
6074 tape[position + self.offset] += tape[position] * self.scale
6175 tape[position] = 0
6276 return position
77+scaleAddCache = {}
78+def scaleAdd(offset, scale):
79+ if (offset, scale) not in scaleAddCache:
80+ scaleAddCache[offset, scale] = ZeroScaleAdd(offset, scale)
81+ return scaleAddCache[offset, scale]
6382 class Loop(Op):
6483 _immutable_fields_ = "ops[*]",
6584 def __init__(self, ops): self.ops = ops
@@ -71,15 +90,22 @@ class Loop(Op):
7190 position=position, tape=tape)
7291 for op in self.ops: position = op.runOn(tape, position)
7392 return position
93+loopCache = []
94+def loop(ops):
95+ for l in loopCache:
96+ if opEq(ops, l.ops): return l
97+ rv = Loop(ops)
98+ loopCache.append(rv)
99+ return rv
74100
75101 def peep(ops):
76102 rv = []
77103 temp = ops[0]
78104 for op in ops[1:]:
79105 if isinstance(temp, Shift) and isinstance(op, Shift):
80- temp = Shift(temp.width + op.width)
106+ temp = shift(temp.width + op.width)
81107 elif isinstance(temp, Add) and isinstance(op, Add):
82- temp = Add(temp.imm + op.imm)
108+ temp = add(temp.imm + op.imm)
83109 else:
84110 rv.append(temp)
85111 temp = op
@@ -98,8 +124,8 @@ def loopish(ops):
98124 elif (len(ops) == 4 and
99125 isConstAdd(ops[0], -1) and isinstance(ops[2], Add) and
100126 oppositeShifts(ops[1], ops[3])):
101- return ZeroScaleAdd(ops[1].width, ops[2].imm)
102- return Loop(ops[:])
127+ return scaleAdd(ops[1].width, ops[2].imm)
128+ return loop(ops[:])
103129
104130 parseTable = {
105131 ',': Input, '.': Output,