Being a bit more efficient in how hot traces gets tracked.
This commit is contained in:
@@ -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<Trace> 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<Trace> 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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user