This commit is contained in:
2026-09-12 14:19:56 +08:00
commit 87ab0b794b
130 changed files with 30042 additions and 0 deletions

87
engine/schema.py Normal file
View File

@@ -0,0 +1,87 @@
from dataclasses import dataclass, field, asdict
import json
SCHEMA_VERSION = 4
@dataclass
class Environment:
python: str
platform: str
processor: str
timerResolution: float
@dataclass
class WallTime:
seconds: float
unit: str = "s"
@dataclass
class Calibration:
# v4 新增cProfile 开销校准系数,用于把 instrumented wall-time 折算为干净耗时。
# 用户脚本只 exec 一次(单跑架构)的代价是 wall-time 带 cProfile 开销;启动期
# 用同一段 tight-loop 各跑一次(裸 vs 仪器化ratio = instrumented / clean
# 用户 wall_time = instrumented_user / ratio。
ratio: float
# 校准负载名:方便 debug 时看出是哪段负载产生的系数;目前固定为 "tight-loop"
workloadName: str = "tight-loop"
# 校准负载在 cProfile 下的耗时(秒)—— 透传给 UI 方便 debug
instrumentedWorkloadSec: float = 0.0
# 校准负载裸跑的耗时(秒)
cleanWorkloadSec: float = 0.0
@dataclass
class FunctionNode:
id: str # "file:line:name"
file: str
line: int
name: str
cumtime: float
tottime: float
ncalls: int
percallTot: float
# 顶层模块名(用于 scope=all 时的 UI 分类):
# "<user>" 用户脚本 / "json" / "numpy" / "<frozen>" 等。
# 提取逻辑见 engine/structure._top_module这一层做归类
# 让 UI 不必重新解析文件路径(路径 normalize 在 OS 间不一致)。
module: str = ""
# 帧来源v3 新增;用于 UI 按 origin 分组):
# "user" 用户脚本 / "stdlib" 标准库 / "third_party" 第三方包 /
# "builtin" 内置C 实现的 builtin / "frozen" frozen importlib 等 /
# "other" 兜底(未匹配任何已知来源,例如奇怪的 <string> 帧)
#
# 优先用 sys.stdlib_module_names 校准3.10+),降级用路径启发式:
# /Lib/ 或 /lib/pythonX.Y/ → stdlib含 site-packages/dist-packages → third_party。
# 推导逻辑见 engine/structure._classify_origin。
origin: str = ""
@dataclass
class FlameNode:
name: str
value: float
children: list = field(default_factory=list)
@dataclass
class AnalysisResult:
schemaVersion: int
environment: Environment
config: dict
status: str # ok|syntax_error|runtime_error|timeout
error: dict | None
wallTime: WallTime | None
functions: list
flame: FlameNode | None
# v4 新增ok 状态下必有;非 ok语法错 / 运行时错 / 超时)下为 None。
# 见 Calibration 字段注释 —— 折算 wallTime 时需要,存到 result 里给 UI 看。
calibration: Calibration | None = None
def to_json(self) -> str:
# ensure_ascii=True默认在 GBK locale / 没设 PYTHONUTF8 的环境下
# stdout 不是合法 UTF-8UI 解析会挂。转义成纯 ASCII 后逐字节一致,
# JSON.parse 原生还原。主进程仍然会设那两个环境变量,这里是纵深防御。
return json.dumps(asdict(self), ensure_ascii=True)