Skip to content

feat(desktop): 状态栏内存详情显示压缩/换出、显存与 CPU、GPU 占用 - #1933

Merged
xiaoyumuxi merged 2 commits into
previewfrom
feat/memory-cpu-gpu-breakdown
Nov 14, 2026
Merged

xiaoyumuxi merged 2 commits into
previewfrom
feat/memory-cpu-gpu-breakdown

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Nov 14, 2026 •

Copy link
Copy Markdown
Collaborator

关联 Issue / Linked issue

PR 类型 / Type

  • feat:新功能或用户可见的改进
  • fix:缺陷修复
  • docs:文档、Agent Note、Skill 等规则文件
  • release:稳定版发布准备

改动说明 / What changes

背景 / Why

状态栏内存详情原来只显示一个数:macOS 是物理占用,Windows 是专用工作集。在 Windows 上 Lithe 看起来只占 108 MB,用户以为漏算了。实际上没有漏算,只是被系统压缩或换出的内存、Windows 的专用显存都不在这个数里;详情里也看不到 CPU 和 GPU 占用。

这次三端按同一种方式记录两个量:“内存中”是实际在内存里的部分,“压缩/换出”是被系统压缩或写到磁盘的部分。另外补上 GPU 显存和 CPU、GPU 占用。

改动 / Changes

读数(desktop/internal/sysinfo/)

  • Process 新增三个可选字段:

    • CompressedBytes:压缩或换出的部分,MemoryBytes 不包含它。
    • GPUMemoryBytes:MemoryBytes 不包含的显存。
    • CPUTime:累计 CPU 时间,单位微秒。

    还新增了 GPUEngines,即各 GPU 引擎的累计忙碌时间。Options.GPU 指定只为哪些进程读 GPU。

  • 各平台读取方式:

    平台 内存中 压缩/换出 显存 CPU 时间 GPU 引擎
    macOS(process_darwin.go) ri_phys_footprint 减 TASK_VM_INFO.compressed compressed 不报告,物理占用已经包含 ri_user_time + ri_system_time IOKit 加速器的 accumulatedGPUTime
    Windows(process_windows.go、新文件 gpu_windows.go) 专用工作集 PrivateUsage 减专用工作集。这是上限值,包含已提交但还没碰过的页 D3DKMT 专用显存段 GetProcessTimes D3DKMT 各节点的 RunningTime
    Linux(process_linux.go) statm 的常驻内存减共享页 /proc/<pid>/status 的 VmSwap 不报告 /proc/<pid>/stat 的 utime + stime 不报告
  • 读不到的字段留空,不当作 0。新增 process_linux_test.go,覆盖 status 与 stat 的解析。

汇总(desktop/internal/core/process_memory.go)

  • 请求和响应对齐 Core#45 的新字段:SampledAt、Previous、LogicalProcessors,以及各层可选的压缩、显存、CPU、GPU 和 Baseline。

采样与呈现(desktop/internal/workbench/memory_monitor.go)

  • 每次读数带 SampledAt,取 memoryEpoch 起算的单调时钟微秒。上一次响应的 Baseline 作为 Previous 原样带回,百分比由 Core 计算。
  • Windows 传 LogicalProcessors = runtime.NumCPU(),CPU 是占全部核心的比例,和任务管理器一致。macOS 按单核计,和活动监视器一致。
  • 只在详情打开时读 GPU,范围是主进程加上次基线里的进程。关闭时的读数不碰 GPU。
  • 采样间隔不变:关闭时 10 秒一次,打开时 2 秒一次。
  • 详情弹窗:
    • 顶部总计只算“内存中”。
    • 下面新增统计行:压缩/换出 · 显存 · CPU · GPU。
    • 图例和进程列表右侧依次是 CPU、GPU、内存中、压缩/换出四列,列标题与数值右对齐。
    • 没有数据的项和列都不显示。CPU、GPU 要第二次采样才出现。
    • 弹窗宽度从原值加宽到 540,数值列宽 80,保证“语言服务器 2 个进程”和较长的语言服务器名不被截断。
  • ⓘ 说明按平台改写,解释“内存中”“压缩/换出”的含义和各列口径。

文案(shared/i18n/)

  • 新增 11 个词条,中英齐全:
    • 说明:helpFigures
    • 列标题:columnCPU、columnGPU、columnInMemory、columnCompressed
    • 统计行:statCompressed、statGPUMemory、statCPU、statGPU、statSeparator
    • 百分比:percent
  • 改写 helpMacOS、helpWindows、helpLinux,重新生成 shared.generated.go。

测试、截图与其他

截图(深色中文 / 浅色英文):

dark
light

不在本 PR 范围内 / Out of scope

  • 运行窗口 CPU/内存曲线改用原生进程表与 Core 汇总([Feature] 运行窗口 CPU/内存曲线改用原生进程表与 Core 汇总,删除 ps/PowerShell 采样 #1925 的第 3 步及之后)。
  • Windows 的 D3DKMT 读数(显存、GPU 引擎)还没有在 Windows 真机上对照任务管理器或 PDH 核对。验证机中途失联,由维护者自行测试和修正。
  • Linux 读数没有在真实 Linux 上运行,只做了交叉编译和解析单测,由维护者自行验证。
  • Core#45 已合入,PINNED_CORE_REVISION 已改为 main 上的 commit。

类型专属:feat

多平台对齐

  • 两端都具备:本 PR 同时实现 macOS 与 Windows(Linux 只是组件实现,不在矩阵平台范围内)
  • 只实现了 macOS:已为 Windows 提交跟进 Issue:#
  • 只实现了 Windows:已为 macOS 提交跟进 Issue:#
  • 刻意只属于某个平台(功能矩阵中另一端记为 platform-specific),理由:

范围检查 / Scope checks

功能矩阵 / Feature matrix

  • 已更新 shared/platform-feature-matrix/features/memory-monitor.json:两端的实现状态和验证状态、证据路径、owner、验证动作都如实填写;没有运行验证的保持 pending
  • 已运行 ./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh;改了平台实现路径的,还运行了 ./scripts/platform-feature-matrix/verify-platform-feature-matrix-change.sh origin/preview HEAD
  • 没有提交 .artifacts/ 下生成的矩阵视图
  • [N/A] 没有更新矩阵的,理由:已更新矩阵

插件归属 / Plugin ownership

  • 已在仓库根目录运行 develop-lithe 第三节“插件归属与宿主零依赖”的自查命令,结果为空
  • 新增或修改的测试只使用测试内联的合成插件、Core 契约 fixture 或插件市场索引快照;没有读取具体插件的插件包、仓库检出、构建产物或清单,没有使用真实插件 ID,没有“缺少插件时跳过”的测试(测试里的语言服务器是虚构的 Quill Tools)
  • 没有为具体插件提供的能力新建或更新宿主功能矩阵条目;宿主条目的证据和验证动作不引用插件的测试、插件包或插件仓库
  • 插件文案没有写进 shared/i18n/;插件的构建步骤、资源路径和补丁没有写进 scripts/resources/、docs/ci-builds.md、Agent Note 或 Skill
  • [N/A] 修改了通用扩展点、可能影响已发布插件的,已在受影响插件的仓库运行它的测试:没有修改插件扩展点

统一日志系统 / Structured logging

N/A:没有新增或改动生命周期里程碑、用户操作终态或失败路径的日志;读数失败沿用原有的“无法读取”呈现。

界面文案 / i18n

  • 宿主文案都走共享 i18n:在 shared/i18n/ 补齐中英词条,运行 node scripts/i18n/generate-i18n.mjs 并提交生成结果,没有手改生成文件;Viva 代码通过 desktop/internal/i18n/ 的接口读取
  • 插件提供的文字由插件自己翻译,没有写进 shared/i18n/(本 PR 不涉及插件文字)
  • 已运行 node scripts/i18n/verify-app-language-localization.mjs 和 node scripts/i18n/generate-i18n.mjs --check,没有放宽脚本或扩大豁免名单

逻辑归属 / Logic placement

  • 可共享的逻辑在 Rust Core:归属、求和、基线匹配和 CPU、GPU 百分比都在 Core#45,契约与 fixture 和实现同一个 PR;平台层只读原生计数器并呈现
  • [N/A] 修改平台层已有的可共享逻辑时已迁入 Core:没有在平台层新增可共享逻辑;运行窗口曲线的平台层汇总由 [Feature] 运行窗口 CPU/内存曲线改用原生进程表与 Core 汇总,删除 ps/PowerShell 采样 #1925 跟进
  • 工具或运行时专属的知识放在插件或成熟上游,宿主和 Core 没有按工具名加分支

性能与内存 / Performance and memory

  • 功能首次需要才启动;没有新增空闲轮询(沿用关闭 10 秒、打开 2 秒的采样,状态项隐藏时不读);GPU 只在详情打开时为主进程和上次基线里的进程读取;基线只保存实例内的进程
  • 主线程没有文件读写、目录遍历、进程启动:读进程表、读 GPU 和调用 Core 都在 a.background 里完成
  • [N/A] 性能基线:不涉及启动、打开项目、输入、滚动、大文件、长输出或搜索;没有新增依赖。D3DKMT 通过 gdi32.dll 已有的系统调用读取

设置 / Settings

N/A:没有新增或修改设置项。

插件契约 / Plugin contract

N/A:不涉及插件契约、能力版本、插件函数协议或宿主方法。Core#45 只改应用契约 processMemory.summarize。

发行包与资源 / Bundle and resources

  • 运行时不向已安装的 app bundle 或 Windows 安装目录写入;没有新增资源路径,已运行 ./scripts/desktop/verify/verify-runtime-bundle-immutability.sh
  • [N/A] 资源复用清单:没有新增下载、解压、生成或缓存资源

无用代码与重构 / Dead code and refactoring


验证 / Verification

命令或操作 平台 结果
LITHE_CORE_RUST_DIR=<Core#45 检出> scripts/desktop/desktop-go.sh test ./... -count=1 macOS 56 个包全部 ok
合并 preview 后,按固定的 Core 40711b1 跑 scripts/desktop/desktop-go.sh test ./... -count=1 macOS 全部 ok
rebase 到最新 preview 后:desktop-go.sh test ./internal/core/... ./internal/sysinfo/... ./internal/workbench/... ./internal/i18n/... -count=1 macOS 全部 ok
go vet ./internal/sysinfo/(GOOS/GOARCH = windows/amd64、windows/arm64、linux/amd64,CGO_ENABLED=0) 交叉编译 通过
临时探针读 Finder、Dock,对照 top -stats mem,cmprs,time macOS 内存中 + 压缩/换出等于 MEM(17.5+59.5≈77M、7.9+40.9≈49M),压缩/换出与 CMPRS 一致(59.5/58M、40.9/41M),CPU 时间与 TIME 一致(213.4 s / 3:33.45)
desktop-go.sh test -tags vivahead,lithevisual ./internal/workbench -run '^TestVisualMemoryDetails$' macOS 无头 四张截图生成,中英文都不截断
node scripts/i18n/generate-i18n.mjs --check、node scripts/i18n/verify-app-language-localization.mjs — 通过
verify-platform-feature-matrix.sh、verify-platform-feature-matrix-change.sh origin/preview HEAD — 通过(189 项能力)
scripts/desktop/verify/verify-runtime-bundle-immutability.sh — 通过(macOS 与 Windows 源码静态检查)
.agents/skills/write-stable-tests/scripts/verify-test-stability.sh 与逐项计时 macOS 通过,workbench 最长 380 ms,sysinfo 0 ms
Core:cargo test -p lithe-process -p lithe-core、cargo fmt --check、cargo clippy -D warnings、verify-rust-core-comments.sh macOS 837 个测试通过,其余都通过
插件归属自查 rg(第三节) — 结果为空

未能执行的检查和原因:

  • Windows 真机:D3DKMT 显存、GPU 引擎、CPU 百分比和“压缩/换出”读数没有对照任务管理器或 PDH。验证机(Tailscale 中继)在上传探针时失联,维护者决定自行测试和修正。
  • Windows 上的桌面测试没有运行,只做了交叉编译 vet。
  • Linux:没有在真实 Linux 上运行,只做了交叉编译与解析单测,维护者自行验证。
  • 原生窗口验收(macOS 与 Windows 整机打开详情对照系统工具)没有做,矩阵保持 pending。

提交前确认 / Final checks

  • 分支从 preview 创建并已 rebase 到最新的 preview(ad9f995a3);目标分支 preview
  • 以 Draft 提交,本地验证通过后才标记 ready
  • 没有无关改动,没有提交 .build/、target/、dist/、.artifacts/ 等产物,没有凭据、个人路径和未脱敏的日志或截图
  • 本次构建、测试或预览启动的 Lithe 应用和子进程已全部关闭,没有进程残留

- 三端统一记录“内存中”和“压缩/换出”:macOS 为物理占用减压缩量与压缩量,Windows 为专用工作集与私有提交减专用工作集(上限值),Linux 为常驻减共享与 VmSwap
- sysinfo 进程表新增累计 CPU 时间;Windows 通过 D3DKMT 读专用显存和各 GPU 引擎忙碌时间,只在详情打开时读取主进程和上次读数里的进程
- 采样带单调时钟的 sampledAt,Core 返回的基线下次原样带回,由 Core 计算 CPU、GPU 百分比;Windows 按全部逻辑处理器折算
- 详情弹窗新增统计行(压缩/换出、显存、CPU、GPU)和 CPU、GPU、内存中、压缩/换出四列,没有数据的项与列不显示;弹窗加宽到 540
- 补齐中英词条,更新 ⓘ 说明、截图与功能矩阵;固定 Core 到 Lithe-core-rust#45 的 c7213c2
@lithe-code-review

lithe-code-review Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ❓ 审查未完成

已由服务器取消。可以重新评论 @lithe review 召唤。

#1932 也改了 Core 固定版本。两边改的 #44、#45 都已合入 Core main,固定改为 main 上的 40711b1(即 #45 测过的 c7213c2 加上 #44),注释合并两条说明。
@xiaoyumuxi
xiaoyumuxi merged commit 9d0708f into preview Nov 14, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant