# -*- coding: utf-8 -*- """ 聚合 ./ocr_dispatch/.json (各 worker 进程写的派发计数), 看 119 个 OCR 端点各分到多少, 直接验证 P2C 负载均衡是否均匀。 用法: python3 tools/看OCR分布.py # 默认只统计最近5分钟内更新过的进程(活进程) python3 tools/看OCR分布.py --all # 包含所有(含已退出的旧进程文件) python3 tools/看OCR分布.py --fresh 120 # 只算最近120秒更新的 python3 tools/看OCR分布.py --top 20 # 只看派发最多/最少各20个 """ import argparse import json import os import time import glob ap = argparse.ArgumentParser() ap.add_argument("--dir", default="./ocr_dispatch", help="计数文件目录") ap.add_argument("--fresh", type=int, default=300, help="只统计最近N秒更新过的进程文件(默认300)") ap.add_argument("--all", action="store_true", help="统计所有文件(忽略新鲜度)") ap.add_argument("--top", type=int, default=0, help="只显示派发最多/最少各N个(0=全部)") args = ap.parse_args() if not os.path.isdir(args.dir): print(f"没有目录 {args.dir} —— 还没产生派发计数。") print("确认 config.tencentcloud.ocr.dispatch_log_every > 0, 且程序已跑一会儿(每1000次派发才落盘)。") raise SystemExit(0) now = time.time() files = glob.glob(os.path.join(args.dir, "*.json")) counts = {} # endpoint -> 总派发数 lat_sum = {} # endpoint -> 延迟加权和(按该进程total加权) lat_w = {} nproc = 0 grand = 0 for fp in files: try: if not args.all and (now - os.path.getmtime(fp)) > args.fresh: continue d = json.load(open(fp, encoding="utf-8")) except Exception: continue nproc += 1 for ep, c in (d.get("counts") or {}).items(): counts[ep] = counts.get(ep, 0) + c grand += c for ep, l in (d.get("lat_ewma") or {}).items(): tot = d.get("total", 0) or 0 lat_sum[ep] = lat_sum.get(ep, 0.0) + l * tot lat_w[ep] = lat_w.get(ep, 0) + tot if not counts: print(f"没有可统计的计数(活进程文件0个)。用 --all 看历史, 或确认程序在跑。") raise SystemExit(0) n = len(counts) avg = grand / n if n else 0 rows = [] for ep, c in counts.items(): lat = (lat_sum.get(ep, 0) / lat_w[ep]) if lat_w.get(ep) else 0.0 rows.append((c, ep, lat)) rows.sort(reverse=True) mx = rows[0][0] if rows else 0 mn = rows[-1][0] if rows else 0 import statistics cs = [r[0] for r in rows] std = statistics.pstdev(cs) if len(cs) > 1 else 0 print("=" * 60) print(f"统计进程数: {nproc} 端点数: {n} 总派发: {grand}") print(f"每端点平均: {avg:.0f} 最多: {mx} 最少: {mn} max/min: {(mx/mn) if mn else float('inf'):.2f}") print(f"标准差: {std:.0f} 变异系数(越小越均匀): {(std/avg*100) if avg else 0:.1f}%") print("=" * 60) show = rows note = "" if args.top and len(rows) > 2 * args.top: show = rows[:args.top] + [(-1, "...", -1)] + rows[-args.top:] note = f"(只显示最多/最少各 {args.top} 个)" print(f"端点派发明细 {note}:") print(f" {'端点':<24}{'派发数':>8}{'占比':>8}{'延迟ms':>8}") for c, ep, lat in show: if c < 0: print(" ...") continue print(f" {ep:<24}{c:>8}{c/grand*100:>7.1f}%{lat*1000:>7.0f}") print() print("判读: 变异系数 <15% 算很均匀; max/min 接近1最好。") print(" 某端点'派发少+延迟高'=它慢被P2C自动避开(正常); '派发少+延迟正常'=可能刚冷却过。")