Files
ocr_data/tools/看OCR分布.py
2026-09-28 16:09:31 +08:00

93 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
"""
聚合 ./ocr_dispatch/<pid>.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自动避开(正常); '派发少+延迟正常'=可能刚冷却过。")