Back to home@lzxcs

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 halflib/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 halflib/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 覆盖):

默认含义
rawMaxRecords400热账本最多原始记录数(超出即滚动归档)
rawMaxAgeHours6热账本中记录的最长年龄
archiveDays14按天归档保留天数(到期自动删除)
summaryDays7分钟聚合保留天数

示例 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 含 scriptDurationstyleAndLayoutDurationblockingDuration 等细分 + 至多 3 条 attribution)
resources最近 3s 的资源请求摘要(时长、大小、发起方)
recent最近 2s 的 notable 事件(input 停顿 / paste / visibility / layout-shift / freeze)
domNodes · transcriptNodesDOM 规模(页面与会话区)
composer.phase · composer.draftChars输入区状态(是否流式输出、草稿多长)
pasteNearby触发前 1 秒内是否粘贴过
heapUsedJS 堆占用(Chrome)
loafSupported当前引擎是否支持 LoAF

归因示例:stalls[].scriptDuration 占大头 → 脚本/渲染逻辑;styleAndLayoutDuration 占大头 → 布局抖动;pasteNearby: true + composer 刚变化 → 粘贴引发的重渲染流。

调参

阈值集中在 lib/client.js 顶部(SINGLE_MSWINDOW_SUM_MSFREEZE_MSCOOLDOWN_MS),改后刷新页面即可(浏览器逻辑,无需重启宿主)。

局限

页面 JS 无法自动产生 DevTools 完整火焰图(需要 DevTools/CDP 权限);本插件抓的是 "事件级诊断包 + 上下文快照"。需要函数级归因时,配合一次手动 Performance 录制 即可闭环。