Skip to content

Commit ea9687a

Browse files
pcercueinotaz
authored andcommitted
lightrec: Add the big-ass debugger
This debugger has this name because it doesn't even try to be suttle - it will run the dynarec and interpreter versions of Lightrec in parallel, comparing their behaviour at every exit point, and returning any issue as soon as they appear. By default, the emulator will print a checksum of the registers after each exit point. When a mismatch is found, it is advised to re-start the debugging setting the LIGHTREC_VERY_DEBUG=1 environment variable, and to set the LIGHTREC_BEGIN_CYCLES environment variable to the cycle value of the last known state. When the "very debug" mode is used, the interpreter and dynarec will exit after each single block, and the emulator will compute a checksum of the whole RAM and scratchpad and print all registers. This two-level debugging allows to find a mismatch point very fast, and then fine-tune until the exact breaking point is found. Signed-off-by: Paul Cercueil <paul@crapouillou.net>
1 parent 746146b commit ea9687a

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
3+
from time import sleep
4+
from sys import argv
5+
from os import environ
6+
import subprocess
7+
8+
def get_next_line(p):
9+
line = ""
10+
11+
while line[0:5] != "CYCLE":
12+
line = p.readline().decode()
13+
14+
if (len(line) == 0):
15+
sleep(0.001)
16+
elif line[0:5] != "CYCLE":
17+
print(line[:-1])
18+
19+
return line
20+
21+
def print_differences(inter, dynarec):
22+
inter_array = inter.split(" ")
23+
inter_dict = dict(zip(inter_array[::2], inter_array[1::2]))
24+
dynarec_array = dynarec.split(" ")
25+
dynarec_dict = dict(zip(dynarec_array[::2], dynarec_array[1::2]))
26+
27+
diff = dict([(k, (inter_dict[k], dynarec_dict[k])) for k in inter_dict.keys() if inter_dict[k] != dynarec_dict[k]])
28+
29+
print("\nDifferences:")
30+
print("{:15}{:15}{:15}".format("", "Interpreter", "Dynarec"))
31+
for k in diff:
32+
print("{:15}{:15}{:15}".format(k, diff[k][0], diff[k][1]))
33+
34+
def print_mismatch(inter, dynarec, oldline):
35+
print("\nMismatch!")
36+
print(inter + " - Interpreter")
37+
print(dynarec + " - Dynarec")
38+
print("State before the mismatch:")
39+
print(oldline)
40+
print_differences(inter, dynarec)
41+
42+
def read_loop(p1, p2):
43+
oldline = ""
44+
45+
while True:
46+
line1 = get_next_line(p1)
47+
line2 = get_next_line(p2)
48+
49+
if line1 != line2:
50+
# TODO: Proper matching
51+
52+
# Lightrec might be lagging behind
53+
#if line1[0:16] != line2[0:16]:
54+
if line1[6:16] != line2[6:16]:
55+
cycle1 = int(line1[6:16], 16)
56+
cycle2 = int(line2[6:16], 16)
57+
58+
if cycle1 < cycle2:
59+
print(line2[:-1] + " - Dynarec")
60+
61+
while cycle1 < cycle2:
62+
print(line1[:-1] + " - Interpreter lagging behind")
63+
print_differences(line1[:-1], line2[:-1])
64+
line1 = get_next_line(p1)
65+
cycle1 = int(line1[6:16], 16)
66+
67+
while cycle1 > cycle2:
68+
print(line2[:-1] + " - Dynarec lagging behind")
69+
print_differences(line1[:-1], line2[:-1])
70+
line2 = get_next_line(p2)
71+
cycle2 = int(line2[6:16], 16)
72+
73+
if line1 != line2:
74+
print_mismatch(line1[:-1], line2[:-1], oldline)
75+
break
76+
77+
if cycle2 < cycle1:
78+
print(line1[:-1] + " - Interpreter")
79+
80+
while cycle1 > cycle2:
81+
print(line2[:-1] + " - Dynarec lagging behind")
82+
print_differences(line1[:-1], line2[:-1])
83+
line2 = get_next_line(p2)
84+
cycle2 = int(line2[6:16], 16)
85+
86+
while cycle1 < cycle2:
87+
print(line1[:-1] + " - Interpreter lagging behind")
88+
print_differences(line1[:-1], line2[:-1])
89+
line1 = get_next_line(p1)
90+
cycle1 = int(line1[6:16], 16)
91+
92+
if line1 != line2:
93+
print_mismatch(line1[:-1], line2[:-1], oldline)
94+
break
95+
96+
if line1 == line2:
97+
oldline = line1[:-1]
98+
print(oldline[:16] + " - Match")
99+
continue
100+
101+
print_mismatch(line1[:-1], line2[:-1], oldline)
102+
break
103+
else:
104+
oldline = line1[:-1]
105+
106+
def main():
107+
with subprocess.Popen(['./pcsx'] + argv[1:], env={ **environ, 'LIGHTREC_DEBUG': '1', 'LIGHTREC_INTERPRETER': '1' }, stdout=subprocess.PIPE, bufsize=1) as fifo_int:
108+
with subprocess.Popen(['./pcsx'] + argv[1:], env={ **environ, 'LIGHTREC_DEBUG': '1' }, stdout=subprocess.PIPE, bufsize=1) as fifo_jit:
109+
read_loop(fifo_int.stdout, fifo_jit.stdout)
110+
111+
if __name__ == '__main__':
112+
main()

0 commit comments

Comments
 (0)