From b8a64ffc9007579c99fc470d84425b4bd3f36acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 16 Sep 2020 09:31:52 +0200 Subject: [PATCH] Being a bit more efficient in how hot traces gets tracked. --- .../java/li/cil/circuity/vm/riscv/R5CPU.java | 59 +++++++++---------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/main/java/li/cil/circuity/vm/riscv/R5CPU.java b/src/main/java/li/cil/circuity/vm/riscv/R5CPU.java index 2e784bc6..773e53ec 100644 --- a/src/main/java/li/cil/circuity/vm/riscv/R5CPU.java +++ b/src/main/java/li/cil/circuity/vm/riscv/R5CPU.java @@ -80,6 +80,11 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController { // Translation look-aside buffer config. private static final int TLB_SIZE = 256; // Must be a power of two for fast modulo via `& (TLB_SIZE - 1)`. + // Knobs for tweaking dynamic binary translation. + private static final int HOT_TRACE_COUNT = 16; // Must be a power of to for (x - 1) masking. + private static final int TRACE_COUNT_THRESHOLD = 30; + private static final int EXPECTED_MAX_TRACE_COUNT = 1024; + /////////////////////////////////////////////////////////////////// // RV32I public int pc; // Program counter. @@ -139,17 +144,8 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController { /////////////////////////////////////////////////////////////////// // Dynamic binary translation - private static final int MAX_TRACKED_TRACES = 50; - private static final int MAX_TRACES = 1000; - private static final int TRACE_COUNT_THRESHOLD = 20; - private final HotTrace[] hotTraces = new HotTrace[MAX_TRACKED_TRACES]; - private final Int2ObjectMap traces = new Int2ObjectOpenHashMap<>(MAX_TRACES); - private TraceClassLoader traceClassLoader = new TraceClassLoader(); - - private static final class HotTrace { - public int pc = -1; - public int count; - } + private final HotTrace[] hotTraces = new HotTrace[HOT_TRACE_COUNT]; + private final Int2ObjectMap traces = new Int2ObjectOpenHashMap<>(EXPECTED_MAX_TRACE_COUNT); @FunctionalInterface public interface Trace { @@ -1029,31 +1025,21 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController { // return true; if (traces.containsKey(pc)) { - traces.get(pc).execute(this); + invokeTrace(traces.get(pc)); return true; } else { - int writeTrace = 0; - int writeTraceCount = hotTraces[0].count; - for (int i = 1; i < hotTraces.length && hotTraces[writeTrace].pc != pc; i++) { - final int count = hotTraces[i].count; - if (count < writeTraceCount || hotTraces[i].pc == pc) { - writeTrace = i; - writeTraceCount = count; - } - } + final int hotTraceIndex = (pc >> 1) & (HOT_TRACE_COUNT - 1); + final HotTrace hotTrace = hotTraces[hotTraceIndex]; + if (hotTrace.pc != pc) { + hotTrace.pc = pc; + hotTrace.count = 1; + } else if (++hotTrace.count >= TRACE_COUNT_THRESHOLD) { + hotTrace.pc = -1; - if (hotTraces[writeTrace].pc != pc) { - hotTraces[writeTrace].pc = pc; - hotTraces[writeTrace].count = 0; - } - hotTraces[writeTrace].count++; - - if (hotTraces[writeTrace].count >= TRACE_COUNT_THRESHOLD) { - final Trace trace = traceClassLoader.translateTrace(pc); + final Trace trace = translateTrace(pc); traces.put(pc, trace); - hotTraces[writeTrace].pc = -1; - hotTraces[writeTrace].count = 0; - trace.execute(this); + invokeTrace(trace); + return true; } } @@ -1061,6 +1047,10 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController { return false; } + private void invokeTrace(final Trace trace) throws R5Exception, MemoryAccessException { + trace.execute(this); + } + private void interpret() throws R5Exception, MemoryAccessException { // The idea here is to run many sequential instructions with very little overhead. // We only need to exit the inner loop when we either leave the page we started in, @@ -3367,6 +3357,11 @@ public class R5CPU implements Steppable, RealTimeCounter, InterruptController { public MemoryMappedDevice device; } + private static final class HotTrace { + public int pc = -1; + public int count; + } + public R5CPUStateSnapshot getState() { final R5CPUStateSnapshot state = new R5CPUStateSnapshot();