123 lines
5 KiB
Python
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:])
|