sots-re/verify/results/shim/br/cmp_aiorders.py

123 lines
5 KiB
Python

"""Compare two `aiorders` dumps under lane BP's proven noise mask.
The mask comes from lane BP's L/A pair, which wrote BYTE-IDENTICAL autosaves: any word that
differs between two runs with identical outputs cannot be a word the applier reads
(rule 26 (d) / lane CB's argument).
"""
import re, sys, collections
# list -> set of word indices that are PROVEN NOISE (BP section 3.4)
NOISE = {
1: {1, 5, 8, 11},
3: set(range(4, 12)),
5: set(range(8, 12)),
7: set(range(2, 12)),
8: set(range(1, 12)),
10: set(range(2, 12)),
12: set(range(5, 12)),
14: set(range(2, 12)),
23: set(range(2, 12)),
}
ELEM = re.compile(
r'aielem blk=(\d+) pid=(\d+) list=(\d+) idx=(\d+) node=(0x[0-9a-f]+) words=(\d+) .*hex=\[ ([0-9a-f ]+)\]')
LISTS = re.compile(r'ailists seq=(\d+) blk=(\d+) pid=(\d+) nonEmpty=(\d+) sizes\(1\.\.27\)=\[([ 0-9]+)\]')
BLK = re.compile(r'aiblk seq=(\d+) blk=(\d+)/(\d+) at=(0x[0-9a-f]+) pid=(\d+) rate=([^ ]+) target=([^ ]+) boost=([^ ]+) g4=([^ ]+) f3=([^ ]+) civ=(\d+)')
BATCH = re.compile(r'---- aibatch seq=(\d+) blocks=(0x[0-9a-f]+) n=(\d+) stride=(0x[0-9a-f]+) ----')
def parse(path):
elems, lists, blks, batches = {}, {}, {}, []
nodes = {}
for line in open(path):
m = ELEM.search(line)
if m:
blk, pid, lst, idx, node, nw, hexs = m.groups()
key = (int(blk), int(pid), int(lst), int(idx))
elems[key] = hexs.split()
nodes[key] = node
continue
m = LISTS.search(line)
if m:
seq, blk, pid, ne, sizes = m.groups()
lists[(int(seq), int(blk), int(pid))] = (int(ne), tuple(int(x) for x in sizes.split()))
continue
m = BLK.search(line)
if m:
g = m.groups()
blks[(int(g[0]), int(g[1]), int(g[4]))] = ('rate=' + g[5], 'boost=' + g[7],
'g4=' + g[8], 'f3=' + g[9], 'civ=' + g[10])
continue
m = BATCH.search(line)
if m:
batches.append((int(m.group(1)), int(m.group(3)), m.group(4)))
return elems, lists, blks, batches, nodes
def main(a, b, na='A', nb='B'):
ea, la, ba, bta, noda = parse(a)
eb, lb, bb, btb, nodb = parse(b)
print(f'== structure ==')
print(f' batches {na}: {bta}')
print(f' batches {nb}: {btb}')
print(f' elements {na}: {len(ea)} {nb}: {len(eb)}')
print(f' blocks {na}: {len(ba)} {nb}: {len(bb)}')
ka, kb = set(ea), set(eb)
if ka != kb:
print(f' !! element key sets DIFFER: only-{na}={sorted(ka-kb)} only-{nb}={sorted(kb-ka)}')
else:
print(f' element (blk,pid,list,idx) key sets: IDENTICAL')
if la != lb:
print(' !! ailists sizes differ:')
for k in sorted(set(la) | set(lb)):
if la.get(k) != lb.get(k):
print(f' {k}: {la.get(k)} vs {lb.get(k)}')
else:
print(' per-list sizes (all blocks): IDENTICAL')
# A gate whose SET flag is 0 carries an UNINITIALISED payload (lane L4's noise class, named
# as such in lane BP section 3.4). Compare only gates that are actually set.
def setonly(t):
return tuple(f for f in t if not re.match(r'[a-z0-9]+=0:', f))
gates_diff = [k for k in sorted(set(ba) | set(bb)) if setonly(ba.get(k, ())) != setonly(bb.get(k, ()))]
if gates_diff:
print(' !! aiblk gate fields differ:')
for k in gates_diff:
print(f' {k}: {setonly(ba.get(k, ()))} vs {setonly(bb.get(k, ()))}')
else:
print(' aiblk SET gate fields (rate/boost/g4/f3/civ): IDENTICAL '
'(unset gates carry uninitialised payloads - lane L4)')
print(f'\n== word diffs, masked ==')
masked = []
noise_hits = collections.Counter()
for k in sorted(ka & kb):
blk, pid, lst, idx = k
wa, wb = ea[k], eb[k]
for i, (x, y) in enumerate(zip(wa, wb)):
if x == y:
continue
if i in NOISE.get(lst, set()):
noise_hits[lst] += 1
else:
masked.append((blk, pid, lst, idx, i, x, y))
if not masked:
print(' NONE. Every differing word is inside the proven noise set.')
for blk, pid, lst, idx, i, x, y in masked:
print(f' blk={blk} pid={pid} list={lst:>2} idx={idx} word{i} '
f'{na}=0x{x} ({int(x,16)}) {nb}=0x{y} ({int(y,16)})')
print(f' (differing words inside the noise set, by list: {dict(sorted(noise_hits.items()))})')
print(f'\n== list 10 element order (systemId, fleetId) ==')
for nm, e in ((na, ea), (nb, eb)):
row = [(k[3], int(e[k][0], 16), int(e[k][1], 16))
for k in sorted(e) if k[2] == 10 and k[1] == 32]
print(f' {nm}: ' + ' '.join(f'({s},{f})' for _, s, f in row))
print(f'\n== list 8 element order (word0) ==')
for nm, e in ((na, ea), (nb, eb)):
row = [(k[3], int(e[k][0], 16)) for k in sorted(e) if k[2] == 8 and k[1] == 32]
print(f' {nm}: ' + ' '.join(f'idx{i}={v}' for i, v in row))
if __name__ == '__main__':
main(*sys.argv[1:])