# analyze_enum_trace.py - 分析客户端「枚举读取」打点:确认读 enum 时字节游标是否推进 # # 数据来源:镜像站 module_24635.js 的 Kt.t7h 补丁(枚举读器)。它记录 # {enum: 枚举 kClass 名, pos0/pos1: 读前/读后的字节游标, bit: nullmap 位游标} # 节流 POST 到 serve.js 的 /__dump__/enum_trace.json。 # # 判读: # pos1 - pos0 == 0 → 该枚举不占字节(与源码 EnumCodecInfo/Kt 空实现一致); # pos1 - pos0 != 0 → 客户端确实为这个枚举读了字节,说明宽度不是常量。 # # 用法: python tools/analyze_enum_trace.py [--names names] import json import os import sys from collections import Counter, defaultdict Root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def Arg(Name, Def): if '--' + Name in sys.argv: I = sys.argv.index('--' + Name) if I + 1 < len(sys.argv): return sys.argv[I + 1] return Def NamesDir = os.path.abspath(Arg('names', os.path.join(Root, 'names'))) TracePath = os.path.join(NamesDir, 'enum_trace.json') FieldsPath = os.path.join(NamesDir, 'codec_fields.json') def Main(): if not os.path.exists(TracePath): print('缺少 ' + TracePath) print('请先用镜像站进一局战斗(Kt.t7h 已打枚举打点,会自动 POST)。') return 1 with open(TracePath, 'r', encoding='utf-8') as F: Data = json.load(F) Rows = Data.get('trace') or [] print('枚举打点:%d 条(采集于 %s)' % (len(Rows), Data.get('at', '?'))) with open(FieldsPath, 'r', encoding='utf-8') as F: Codecs = json.load(F).get('Codecs') or {} # 枚举类型名 → 用到它的 (codec, 字段) Users = defaultdict(list) for Key, C in Codecs.items(): for F in C.get('Fields') or []: T = str(F.get('Type') or '') if T.startswith('enum<') and T.endswith('>'): Users[T[5:-1]].append((Key, F.get('Name'))) Delta = Counter() ByEnum = defaultdict(Counter) for R in Rows: D = (R.get('pos1', -1) - R.get('pos0', -1)) if R.get('pos0', -1) >= 0 else -1 Delta[D] += 1 ByEnum[R.get('enum') or '?'][D] += 1 print(' 字节推进量分布(pos1-pos0):%s' % dict(Delta)) print(' 按枚举类型:') for Name, Cnt in sorted(ByEnum.items(), key=lambda X: -sum(X[1].values()))[:25]: Where = Users.get(Name) or [] Sample = ('%s.%s' % Where[0]) if Where else '?' print(' %-4s 次数=%-5d 推进=%s 使用处=%s%s' % (Name or '?', sum(Cnt.values()), dict(Cnt), Sample, (' 等 %d 处' % len(Where)) if len(Where) > 1 else '')) return 0 if __name__ == '__main__': sys.exit(Main())