lag-trace-pro
DSH web UI performance recorder: auto-captures page jank (long animation frames, long tasks, frame freezes) with context snapshots, stored under ~/.dsh/perf/
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 26, 2026
- Updated
- Aug 26, 2026
Introduction
lag-trace-pro
Web GUI 通用性能记录仪:自动抓取整个 DSH web UI 页面的卡顿——长动画帧、长任务、 前台帧冻结、布局偏移、慢输入事件,连同页面上下文快照(DOM 规模、composer 状态、 会话区规模、内存、窗口内资源请求)一起落盘,供事后归因分析。不限于输入框: 任何让主线程停顿的地方都会被记录。
安装(Install)
需要 DSH(DeepSeek Harness)与 web profile(dsh web):
# 1. 安装插件(pnpm git 依赖)
dsh plugin --profile web add github:lzxcs/lag-trace-pro
# 2. 在 ~/.dsh/profiles/web/cordis.patch.yml 末尾追加注入块:
- insert:
- id: lag-trace-pro
name: 'lag-trace-pro'
# 3. 重启 DSH Web(托盘菜单 → DSH Web 重启),浏览器 Ctrl+F5 刷新页面
# 4. 验证:
curl http://127.0.0.1:3080/__lag-trace-pro/status
卸载:dsh plugin --profile web remove lag-trace-pro,并删掉 cordis.patch.yml 中的注入块。
工作原理
- Browser half(
lib/client.js):性能探针常驻运行- Long Animation Frames(LoAF):单帧 ≥ 100ms,或 3 秒滑动窗口累计 ≥ 300ms 触发;自带 script / style-layout / paint 细分,能区分"脚本忙"与"布局绘制忙"
- Long Tasks:始终记录为明细;在无 LoAF 的引擎(Firefox)上同样驱动阈值
- 前台 rAF 帧间隔 ≥ 300ms(页面切后台不算,避免误报)
- CLS:布局偏移(≥0.05)作为上下文缓冲
- 慢输入事件(处理 >40ms)作为上下文缓冲
- 手动快照:Console 执行
window.__lagTraceFlush()立即记录一条 (低于阈值但想让 agent 看一眼的状态,随时可抓) - 触发后采集快照并
POST /__lag-trace-pro/record上报;2 秒冷却 - 查看面板:侧边栏底部与"归档会话"并列的 ⚡ 按钮(带未读角标); 每次捕获还会在右下角弹出可点击的提示条"已记录 Xms 卡顿 · 点击查看"
- Node half(
lib/index.js):回环路由 + 分层存储POST /__lag-trace-pro/record→ 追加写入热账本(60 秒内相同记录自动去重)GET /__lag-trace-pro/status→{ ok, file, lastWrite, counts, retention, metaFile }GET /__lag-trace-pro/list?limit=100→ 读热账本尾部窗口,返回最新limit条(新→旧)GET /__lag-trace-pro/summary?minutes=180→ 分钟级聚合(新→旧),供 AI/面板快速读取
数据分层与保留(AI 读取路径)
~/.dsh/perf/
├── lag-trace.jsonl 热账本:原始记录,保留 最近 N 条 / N 小时
├── lag-trace-day-YYYY-MM-DD.jsonl 按天归档:热账本滚动时追加,保留 N 天
├── lag-trace-summary.jsonl 分钟聚合:每分钟 1 行 JSON,保留 N 天
├── lag-trace-meta.json 元数据:布局 + 保留策略 + 各文件统计(AI 入口)
└── lag-trace.config.json (可选)保留策略覆盖
AI 读取顺序:meta.json(文件在哪、各多少条)→ summary.jsonl(分钟级:次数/最大时长/
停滞总量/脚本 vs 渲染占比/顶级 invoker/DOM 规模)→ 需要深挖再读 lag-trace.jsonl(最新原始)
或 lag-trace-day-*.jsonl(历史归档)。
摘要行(每分钟 1 行,JSON 可直接解析):
{"minute":"2026-08-25T06:35","count":12,"maxMs":321,"stallSumMs":2340,"scriptMs":880,
"renderPctAvg":57,"kinds":{"long-animation-frame":9,"stall-window":3},"phases":{"plain":12},
"scenes":{"switch":5,"stream":3,"other":4},
"domMin":3593,"domMax":6300,"convMax":5900,"heapMaxMB":580,
"topScripts":[["event-listener:DOMWebSocket.onmessage",".../client.js",312,15]],"notable":2}
保留策略(默认值,写 lag-trace.config.json 覆盖):
| 键 | 默认 | 含义 |
|---|---|---|
rawMaxRecords | 400 | 热账本最多原始记录数(超出即滚动归档) |
rawMaxAgeHours | 6 | 热账本中记录的最长年龄 |
archiveDays | 14 | 按天归档保留天数(到期自动删除) |
summaryDays | 7 | 分钟聚合保留天数 |
示例 lag-trace.config.json:{"rawMaxRecords":200,"rawMaxAgeHours":2,"archiveDays":30}
每次重启 Web 进程会对热账本做一次幂等回填(重建受影响分钟的摘要,不会重复计数)。
查看面板
点击侧边栏底部 ⚡ 按钮(未读角标 = 上次打开后新捕获条数)或点击捕获提示条:
- 列表:时间(本地时区)|场景徽章|触发类型 + 时长|DOM/会话区规模|composer phase
- 顶部两行筛选:触发类型(全部 / 冻结 / 长帧 / 累积 / 手动快照)× 场景(全部 / 切换 / 流式 / 其他,带条数)
- 场景定义:
switch= 标题变化后 5s 内(切会话的 DOM 重渲染成本);stream= 会话区节点持续增长(流式生成追加);other= 交互/静态页上的停顿 - 切换类记录只计角标、不弹通知条(渲染成本 ≠ 感知卡顿),其余捕获照常弹条
- 点击行展开详情:主线程损耗逐条(LoAF 的 script / style+layout / blocking 细分 与 attribution 容器)、近期事件、请求资源、页面状态(DOM、堆内存、标题、场景)
- 每条可"复制 JSON"(粘给 agent 做深度归因),也可"复制全部"
记录内容(每条)
| 字段 | 说明 |
|---|---|
trigger | 触发原因(long-animation-frame / stall-window / freeze / manual) |
scene | 场景标签:switch(标题变化 5s 内)/ stream(会话区增长中)/ other |
stalls | 最近 3s 的 LoAF/long-task 明细(LoAF 含 scriptDuration、styleAndLayoutDuration、blockingDuration 等细分 + 至多 3 条 attribution) |
resources | 最近 3s 的资源请求摘要(时长、大小、发起方) |
recent | 最近 2s 的 notable 事件(input 停顿 / paste / visibility / layout-shift / freeze) |
domNodes · transcriptNodes | DOM 规模(页面与会话区) |
composer.phase · composer.draftChars | 输入区状态(是否流式输出、草稿多长) |
pasteNearby | 触发前 1 秒内是否粘贴过 |
heapUsed | JS 堆占用(Chrome) |
loafSupported | 当前引擎是否支持 LoAF |
归因示例:stalls[].scriptDuration 占大头 → 脚本/渲染逻辑;styleAndLayoutDuration
占大头 → 布局抖动;pasteNearby: true + composer 刚变化 → 粘贴引发的重渲染流。
调参
阈值集中在 lib/client.js 顶部(SINGLE_MS、WINDOW_SUM_MS、FREEZE_MS、
COOLDOWN_MS),改后刷新页面即可(浏览器逻辑,无需重启宿主)。
局限
页面 JS 无法自动产生 DevTools 完整火焰图(需要 DevTools/CDP 权限);本插件抓的是 "事件级诊断包 + 上下文快照"。需要函数级归因时,配合一次手动 Performance 录制 即可闭环。