首次提交
This commit is contained in:
92
tools/看OCR分布.py
Normal file
92
tools/看OCR分布.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- 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自动避开(正常); '派发少+延迟正常'=可能刚冷却过。")
|
||||
Reference in New Issue
Block a user