93 lines
3.5 KiB
Python
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自动避开(正常); '派发少+延迟正常'=可能刚冷却过。")
|