vdi-cloud/docs/evidence/linux-gpu-20261111/README.md

251 lines
34 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ubuntu、麒麟 GPU 链路优化实施记录
实施日期:2026-11-11。依据桌面上的《麒麟与Ubuntu云桌面画质帧率及延迟对齐说明_20261110.docx》,以及用户补充的“允许三桌面轮流使用同一块 GPU”。原 Word 文档保留为实施前说明。
## 已实施的链路
宿主为 i7-4720HQ,4 个物理核、8 个逻辑线程,约 23.35 GiB 内存。GTX 965M 2 GiB 是本轮三桌面轮流使用的设备。HD 4600 没有可用 mdev,不按共享 vGPU 处理。Ubuntu、麒麟各配置 8 vCPU、8 GiB;8 vCPU 不等于新增 8 个物理核。
| 项目 | Ubuntu VM102 | 麒麟 VM101 |
| --- | --- | --- |
| 会话 | GNOME Xorg、test2 自动登录 | UKUI / ukui-kwin_x11、test1 自动登录 |
| 渲染 | GTX 965M,glxinfo 与进程显存使用均已核实 | GTX 965M,glxinfo 与进程显存使用均已核实 |
| 驱动 | Ubuntu 官方 580.178.04 | 麒麟官方 580.95.05 |
| 实际捕获/编码 | NvFBC / CUDA / h264_nvenc | NvFBC / CUDA / h264_nvenc |
| 显示路径 | NVIDIA 渲染,modesetting PRIME 输出;虚拟源屏测试提高至约 119.9 Hz | NVIDIA 固定 2560×1440 整屏,无 RandR 物理输出 |
| 串流交付档位 | 2560×1440、45 FPS、25 Mbps、H.264 SDR | 2560×1440、45 FPS、25 Mbps、H.264 SDR |
| 光标 | 保留系统原生形状、本地移动和租约协议 | 保留系统原生形状、本地移动和租约协议 |
Sunshine 固定为 v2025.924.154138。当前 2026 构建在 Maxwell 上实际出现 CUDA kernel 不兼容,不能仅因为版本更新就替换。私有程序位于 `/opt/vdi-sunshine-maxwell/`,用户服务为 `vdi-sunshine.service`。旧的软件编码绑核已清除;未将整个 Sunshine 改为 SCHED_FIFO,也未把关闭提示音、窗口居中当作视频优化。
Ubuntu 尝试无 RandR 输出的 NVIDIA 整屏路径时,GNOME 实际黑屏,已回退到可用 PRIME 输出;它仍含显示复制,不能称全程零拷贝。麒麟旧内核的 PRIME 显存导入失败,改用驱动实际报告的整屏 NvFBC 捕获。适配器只在真实屏幕为 2K、驱动可采集且没有输出时枚举整屏,不伪造物理显示器或硬件支持。麒麟重启后桌面曾自动改大屏幕,已通过 ServerFlags 禁用自动添加/绑定其他 GPU,并固定 X screen。
麒麟 glibc 2.31 与该官方 Sunshine 构建不兼容,因此程序使用私有 runtime 的加载器和依赖库,未替换系统 glibc。初始依赖经 Ubuntu APT 签名仓库核对;补充的 libwayland-client、libffi8、libva 来自 Ubuntu 官方 HTTPS 仓库并记录下载散列,但本轮未额外完成它们的 APT 签名索引校验。KYSEC 保持开启,仅对本轮文件进行 verified 认证。
## 操作方式与隔离
平台设置 `VDI_EXCLUSIVE_GPU_NODE=starhe`、`VDI_EXCLUSIVE_GPU_VMIDS=100,101,102`。盒子退出串流后,选择下一台即可正常关闭上一台、等待 PVE 原任务和实际 stopped 状态、启动目标,再等待 Sunshine 响应。不会为了快速切换强制断电。**退出串流并不立即关闭虚拟机;选择另一台时才正常关闭上一台,因此切换前须保存当前桌面的工作。**
准备任务需要该终端已有桌面授权。共享组锁、持久任务预约、会话占用检查阻止相互抢占;票据签发和消费再次查实际 PVE 电源状态,不能依赖旧缓存。正在使用或管理任务未完成时拒绝切换。已知 PVE 操作结果不明时保留占用,管理员仅核对原 UPID,不自动重复提交。终端不接收 PVE root 凭据。
准备接口:`POST /api/v1/terminal/desktop-prepare`、`GET /api/v1/terminal/desktop-prepare/:id`。已知任务核对:管理员 `POST /api/v1/tasks/:id/gpu-reconcile`。未知 UPID 须人工核对 PVE 与任务记录,不能凭“现在看起来已开机”重发电源操作。管理端对共用组的普通 start/reboot 入口拒绝执行,须从终端选择页准备;正常 shutdown 及规格、快照操作受同一组预约约束。
Ubuntu 为唯一 onboot=1 的桌面,Windows 与麒麟 onboot=0,避免宿主启动时争用显卡。该模式是整卡轮流直通,不是三会话同时使用。将来迁移算力服务器仍需提供真正可并发的 GPU/编码会话容量,不能只提高显卡算力或显存就默认支持多 VM 共享。
客户端新增受范围校验的 `VDI_MOONLIGHT_BITRATE_KBPS`;盒子 `~/.config/vdi-terminal/render.conf` 的 `bitrate_kbps=25000` 由启动脚本按允许字段读取,不执行配置内容。缺少配置时继续使用原分辨率对应默认码率;本轮最终实际命令行已核实 25000。25 Mbps 是客户端请求档位,不等于持续视频净码率;Ubuntu 本轮 Sunshine 记录的视频编码预算为 18,988,000 bit/s,不能将二者混同,也不能用启动探测时的 1 Mbps 当作实际串流档位。
## 测量口径
拖框使用同几何和逐帧序号的 GTK / WinForms 参考窗口;盒子通过 XTest 注入,XGetImage 观察首次解码回显。一次拖框发送 300 次移动并检查松键。读取画面本身会阻塞发送循环,不能称真正恒定 60 Hz,也不能把“观察到的新画面次数”当作 Moonlight 呈现 FPS。
悬停、点击、掩码输入各 100 次,实际控件触发后更新唯一标记。点击计时从按下开始,包含人为 40 ms 按住时间;`click_release` 字段不能误读为从松键起算。输入为合成字符,无真实密码;提交页没有后台认证,所以不代表真实网站登录耗时。结果不包含 USB、真实面板扫描和人眼感知,不能作为物理零延迟证明。
### 早期与中间结果(30 Mbps,非最终验收)
| 配置 / 证据 | 拖框 P50 | P95 | 说明 |
| --- | ---: | ---: | --- |
| Ubuntu GPU、60 FPS | 124.14 ms | 157.50 ms | `ubuntu-gpu-60-drag.json` |
| Ubuntu GPU、45 FPS、源屏约 60 Hz | 126.60 ms | 159.28 ms | `ubuntu-gpu-45-drag.json` |
| Ubuntu GPU、45 FPS、源屏约 120 Hz | 97.59 ms | 128.94 ms | `ubuntu-gpu-source120-drag.json`;源屏提高频率,传输仍 45 FPS |
| 麒麟 GPU、60 FPS | 83.26 ms | 106.79 ms | `kylin-gpu-60-drag.json` |
| 麒麟 GPU、45 FPS | 81.22 ms | 101.44 ms | `kylin-gpu-45-drag.json` |
| Windows 旧参考 | 125.64 ms | 160.10 ms | `windows-baseline-drag.json`;测量时另一 VM 在驱动编译,不能用于宣称追平 |
`kylin-gpu-45-response.json` 的悬停 / 点击 / 掩码输入 P50 分别为 97.36 / 140.17 / 78.58 ms,P95 为 118.29 / 163.32 / 99.56 ms。`ubuntu-gpu-45-response.json` 为源屏 60 Hz 的中间结果,且网络延迟变化较大;不能与不同阶段网络条件混用。源屏 120 Hz 的一次 100 事件复测被 Wi-Fi 断开打断,该失败轮次不计入成功结果。
### 同档最终复测(45 FPS、客户端请求 25 Mbps)
各项为 P50 / P95,单位 ms。Windows 窗口实际由 WinForms 生成,Linux 为 GTK;JSON 中通用 method 文本仍写 GTK,应按这里解释。各系统顺序测量,无线环境并非严格恒定,因此只代表本轮观测,不能把所有差值归因于单一设置。
| 配置 | 拖框 | 悬停(100 次) | 点击(100 次) | 掩码字符(100 次) |
| --- | ---: | ---: | ---: | ---: |
| Windows | 84.88 / 121.39 | 63.63 / 101.82 | 141.37 / 153.49 | 90.05 / 105.07 |
| 麒麟,保留 XRender | 80.61 / 100.55 | 98.34 / 116.50 | 139.13 / 159.49 | 80.01 / 104.13 |
| Ubuntu,源屏约 120 Hz、定时捕获 | 91.38 / 117.43 | 118.43 / 151.82 | 174.60 / 211.69 | 88.02 / 120.11 |
原始证据分别为 `windows-final25-*`、`kylin-final25-*`、`ubuntu-final25-*`。拖框延迟已接近同档 Windows;麒麟悬停仍慢约 35 ms,Ubuntu 定时捕获时悬停慢约 55 ms、点击慢约 33 ms,不能宣称所有交互均已追平。Windows 悬停最大值还出现 845.91 ms 的孤立尖峰;P95 不能代替长稳验收,也不能隐去最大值。
麒麟额外测试 OpenGL 合成及 MaxFPS/RefreshRate=120:必须通过实际 D-Bus `compositingType=gl2` 才能生效,单改 Backend=OpenGL 会被系统恢复。实际 supportInformation 曾确认 NVIDIA OpenGL;其 Placeholder 源屏仍报告 60 Hz,不能声称变成真实 120 Hz 输出。拖框 97.07 / 109.11 ms,悬停 98.99 / 119.18 ms,点击 143.34 / 165.30 ms,未见收益,已恢复 `kwin-before-opengl120.conf`,不作为最终方案。证据保留为 `kylin-opengl120-25-*`。
Ubuntu 又测试仅在原生光标租约内启用 NvFBC `bPushModel=true`,由画面 damage 事件生成可采集帧,保留原 direct-capture 参数,不提高视频传输帧率。接口边界 14 情形通过、真实采集成功;拖框 81.42 / 99.50 ms,但悬停 119.14 / 156.67 ms、点击 172.05 / 250.00 ms、掩码输入 79.85 / 123.18 ms,未形成一致收益。测试期间还发生 AP 切换和断流,不能将拖框改善单独归因于 push。该实验的服务环境、适配器与 manifest 均已恢复,实验选项没有留在生产代码中;原始数据为 `ubuntu-push25-*`,不得将其当作当前保留配置的性能。回退后再次实际连接、核验 manifest、`nvfbc-v1`、2K/119.9 Hz 与硬件编码负载均通过。
### GPU 切换实测
已从选择页完成 Ubuntu→麒麟、麒麟→Windows、Windows→麒麟、麒麟→Ubuntu 的完整轮转。准备任务分别约 33、66、34、30 秒,含正常关机、开机和 Sunshine 就绪。最后一次 Ubuntu 冷启动后核对真实 2560×1440、约 119.9 Hz 源屏、NvFBC receipt 和 NVENC 编码负载均正常;桌面实际截图见 `ubuntu-final-desktop.jpg`,麒麟见 `kylin-final-desktop.png`。任务记录见 `gpu-switch-tasks.csv`,其中同一台重连的短任务不代表冷启动耗时。
实验重启 Sunshine 时另有一次准备任务在最终归属复核处失败,正常释放失败任务后,重新由用户界面准备成功;没有绕过复核或重复发送未知电源任务。不能把全部准备尝试描述为零失败。收尾仅 Ubuntu 运行,Windows、麒麟停止,盒子退出至选择页。
## 仍限制体验的部分
盒子是 RK3528,使用 RKMPP 硬解、DRM PRIME / NV12 帧和 EGL 呈现。60 FPS 串流实际接收/解码约 60,但呈现约 43,约 28% 帧被丢弃;盒子 GPU 曾达到 800 MHz 下约 90% 使用率。45 FPS 测试实际呈现约 43~44,排队和丢帧更少。客户端将部分“丢弃旧帧”记在 network jitter 栏,不能把这一栏全解释为 Wi-Fi 丢包。当前不构成稳定 2K60,也未完成直接 DRM scanout 绕开 GPU 合成的实现。
盒子当前走 5 GHz Wi-Fi,有线端口 NO-CARRIER。串流期间已发生 Wi-Fi 真正断开和重新关联,wpa_supplicant 原始记录含 reason=34 与关联拒绝;不是 Linux 编码器重启的推测。12:33、12:44 等记录还显示同 SSID 下尝试 2.4 GHz 接入失败,再关联 5 GHz;本轮没有修改路由器或锁定 BSSID。无线驱动为 `aicwf_sdio`,省电已关闭。网络延迟在不同测试从约 5 ms 上升到 16~40 ms,原生光标通道因此超时并正常结束串流。没有通过延长超时掩盖断网。证据见 `wifi-final.log`、`client-final.log`。提高服务器 GPU 算力不能消除盒子断网;下一步应优先让宿主与盒子稳定有线连接,再做同条件验收。
本轮核查宿主温度曾达 87~88°C,盒子约 76°C,需结合持续负载观察。存储 local 约 74.2%,local-lvm 约 93.8%,后者仅约 3.9 GiB 余量;未创建大快照或继续堆积大备份。迁移/扩容和稳定散热是长期运行条件,不能用持续写满测试验证性能。
收尾清理 Ubuntu 可再生成的 APT 安装缓存,约 772 MiB 降到 40 KiB,并执行根分区 fstrim。fstrim 报告的是发出的逻辑范围(约 28.4 GiB),不是宿主实际回收量。复查发现 Ubuntu 磁盘实际在 local 的 qcow2 文件中,local-lvm 实际使用率仍为 94.04%,不能宣称薄卷空间已释放。未删除系统、用户文件、回退备份或擅自扩大薄卷逻辑容量。
尚未完成 Word 文档提出的 10 分钟统一业务动态场景、每类 100 次真实拖窗/应用启动、物理相机延迟,以及 2 小时 / 8 小时长期验收。存在已捕获的 Wi-Fi 断流,故不得宣称已完成长稳或“全部操作与 Windows 完全相同”。
## 代码验证与回退
- 专用空测试数据库 `vdi_gpu_test_20261111`:共享组授权/占用、先关后开、缓存滞后票据、电源结果不明不重放、硬拒绝、原 UPID 核对和管理操作互斥。见 `exclusive-gpu-test.log`。该测试会清空自己的 fixture,严禁改为 live 数据库运行。
- 实际盒子编译并运行 6 项 CTest,含关机桌面可点、准备成功前不签发票据、失败不连接和码率范围验证。见 `kiosk-tests.log`。
- 麒麟实际 glibc 上,NvFBC ABI / 原参数不变 / 租约光标 / 整屏枚举 / 错版本拒绝等 10 情形通过。
- 两台 Linux 分别通过 host 回归:显示管理器重启后的旧就绪标记清除、manifest 不完整时不触碰运行中的捕获服务;本地 4 项光标输入边界测试通过。
- OpenAPI 与 TypeScript 类型已更新;控制台 typecheck 通过。Hardware、Snapshot、PowerBatch、DeviceIdentity、TerminalLifecycle 的专用数据库回归完整通过(344 秒),见 `maintenance-regressions.log`。
## 当前结论和下一步条件
### 后续修复:Ubuntu 双光标(2026-11-11)
用户反馈“一支鼠标拖着另一支”。现场核对:原生光标租约、适配器和 `nvfbc-v1` 均生效,但盒子根窗口截图仍能看到视频内箭头。原先仅确认 NvFBC 关闭光标参数和捕获就绪,未覆盖 PRIME 路径已将服务端软件光标画入画面的情形;这使本地即时光标与有视频延迟的光标叠加。
已在 Ubuntu 部署 guard 生命周期内的 XFixes 服务端光标隐藏,原生形状读取和盒子本地显示继续保留。配置标记是 `/home/test2/vdi-terminal/native-cursor-v1/hide-server-cursor`,未修改光标主题、移速、分辨率或编码档位。结束时先停视频生产者,再恢复服务端光标,显示连接断开也会释放隐藏状态。变更前 Python 文件备份在 `/var/backups/vdi-gpu-20261111/host-before-serverhide.py`。
Ubuntu 真实运行 3 项 host 回归全部通过,含捕获失败时停止/恢复顺序。盒子在三处纯桌面背景比较移动前后同一位置:超过 25 的通道变化像素数均为 0,最大通道差 0/1/0;同时本地原生光标保持 24×24、热点 (3,1)、254 个非透明像素,位置正确。见 `ubuntu-double-cursor-check.json`;该截图口径排除本地 X11 光标,因此用于检查视频中是否还有箭头,不冒充相机拍摄。随后 300 次拖框移动全部收到且松键成功,见 `ubuntu-cursorfix-drag.json`。退出后检查普通捕获已恢复、lease ready/drop-in 已清理;重新连接后重复三处检查仍通过,见 `ubuntu-double-cursor-reconnect.json` 和 `ubuntu-cursorfix-tests.log`。收尾保留 Ubuntu 串流供用户使用。这些检查用于验证重复光标和输入功能,不替代物理延迟或长稳验收。
已经实现三台轮流直通同一块 GTX 965M,Ubuntu、麒麟实际使用 GPU 渲染、NvFBC 捕获和 NVENC 编码;本轮不再依赖 4 核 CPU 承担 2K 软件编码。2K 画幅与 H.264 SDR 档位已对齐,拖框测得接近同档 Windows;当前保留的 Ubuntu 悬停、点击和麒麟悬停仍有可测差距,且反复出现无线断流,尚不满足“所有交互及长期稳定性与 Windows 一致”。分辨率相同也不等于已完成色彩或文字画质的客观一致性验收。
下一步应先给盒子接通稳定有线网络,宿主也保持有线;在固定网络、相同业务场景下重测并区分 GNOME/UKUI 重绘、显示复制与客户端呈现耗时,再决定是否重新试验事件触发捕获。若目标保持真 2K60,现有 RK3528 的 EGL 呈现路径还需继续减少复制/合成,或换实测可稳定 2K60 呈现的终端。当前 GTX 965M 已能完成单桌面硬编码,继续只加 VM CPU 核数不能解决无线断流和盒子呈现上限。
未来要求三个桌面同时运行时,需规划各 VM 可独立使用的物理 GPU,或硬件、驱动及授权均支持的 vGPU/编码方案,并按并发会话数验证;当前轮流直通方案不能直接变成同时共享。正式迁移前还应处理薄卷池余量与散热,再补齐 Word 中的长期及物理延迟验收。
PVE 变更前配置保存在 `/root/vdi-linux-gpu-20261111/{100,101,102}.conf.before`;Linux 备份在各自 `/var/backups/vdi-gpu-20261111/`。Ubuntu 的 headless 失败试验、PRIME 配置和提高源屏频率前脚本均有独立备份。回退显示配置时先退出串流,恢复对应 Xorg 与显示脚本,再正常重启显示管理器;必须目视确认桌面,不能只查服务 active。
平台部署前 API 镜像保留为 `vdi-cloud-live-api:before-gpu-20261111`,环境备份为工作站 `.local/live/env.before-gpu-20261111.bak`,不含于报告或仓库。盒子变更前文件在 `~/vdi-build/gpu-opt-20261111/`。回退共享组前先确认只有一台持有显卡,停用两项 group 环境变量并恢复 API/客户端;不要在 GPU 仍被别台使用时直接开机。
## 官方依据
- [Sunshine 配置](https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2configuration.html)、[发行记录](https://github.com/LizardByte/Sunshine/releases)。实际使用选项按已装版本核验。
- [NVIDIA Xorg 配置选项](https://download.nvidia.com/XFree86/Linux-x86_64/580.82.09/README/xconfigoptions.html)。
- [Proxmox PCI 直通说明](https://github.com/proxmox/pve-docs/blob/master/qm-pci-passthrough.adoc)。
设备能枚举、编码测试能启动和完整交互桌面可用是不同证据;本报告按真实串流、GPU 编码负载和画面核验分别记录。
## 补充:Windows 硬编码故障与恢复(2026-11-11)
用户反馈 Windows 鼠标卡顿后,实际查到 GTX 965M 的设备管理器错误码为 43,`nvidia-smi` 无法连接驱动;Sunshine 13:38 的真实连接日志为 `Creating encoder [libx264]`,并非 NVENC。这是独立于 Ubuntu 双光标的故障,不能用鼠标移速或无线网络解释全部表现。
与原 PVE 备份比对,Windows 的 CPU、内存、PCI 直通和 QEMU 参数一致,只有 `onboot: 1→0`。公共客户端请求码率曾从 30 改为 25 Mbps,对 Windows 也有影响;45 FPS 在 11 月 9 日的客户端日志中已存在。Windows 内曾执行临时交互参考测试,相关计划任务已清理。本次排障还重启过显卡设备、Sunshine 服务,并在用户允许后正常关开机;不能描述为“Windows 内完全没有操作”。Ubuntu 隐藏服务端重复光标的补丁没有部署到 Windows。
显卡设备重启、Windows 正常关开机和宿主侧专用 PCI 总线复位均未恢复 NVENC;总线复位后宿主曾显示 D0,但 Windows 启动后又报 Code 43,物理设备显示 D3hot,尚不能据此单独确定驱动失败的根因。用户随后明确同意正常重启整台 Proxmox 宿主;执行前再次检查三台 VM 和容器列表、备份 Ubuntu 配置,将仍为 1 的 Ubuntu `onboot` 改为 0,避免宿主恢复时自动争用显卡。先正常关闭 Windows,确认三台全部停止后提交宿主重启。
当前排他切换只核验电源归属和 Sunshine `serverinfo`,不能证明 NVIDIA 驱动与硬件编码健康。此前完成过轮转不代表已证明长期可重复可靠;在恢复后完成跨系统重切和真实 NVENC 验证前,不应宣称该共享显卡方案已通过稳定性验收。禁止仅凭“连接服务已响应”报告硬编码恢复。
### Windows 恢复结果(13:44—13:47)
宿主启动 ID 已从 `f078a704-350d-4c7d-8839-c192ebe7c4b5` 变为 `df157c5a-ae91-4225-b4b7-f6ab8c0ed8c9`,确认实际完成宿主重启。随后从盒子启动 Windows,NVIDIA 设备错误码恢复为 0,`nvidia-smi` 正常返回 GTX 965M / 582.78。13:44:44 实际连接为 `Creating encoder [h264_nvenc]`,随后明确创建 H.264 P1 编码器;连续检查 GPU 编码负载约 10%—11%,Sunshine CPU 采样为 0%,不再是此前的软件编码状态。日志中的 HEVC 10-bit 探测失败不是当前流,当前流已核对为 H.264 SDR。
盒子日志确认实际串流为 2560×1440 / 45 FPS、RKMPP H.264 硬解;画面可用。完成 30 步桌面背景拖框,画面出现对应选框,finally 中释放鼠标按键,未重建 Windows 临时计划任务。证据为 `windows-recovery-nvenc.log` 和 `windows-recovery-desktop-drag.jpg`。这是短时功能与硬编码恢复核验,没有重新完成物理输入延迟或长期稳定性验收。
本次收尾状态取代前文“保留 Ubuntu”的旧状态:Windows 正在运行并连接,Ubuntu、麒麟关闭;三台 onboot 均为 0。Ubuntu 自动启动改动前备份为 `/root/vdi-linux-gpu-20261111/102.conf.before-windows-recovery`。未更换 Windows 显卡驱动,未修改其 CPU、内存、鼠标速度或直通参数。宿主重启前的 `power/control=on` 是临时状态,没有创建持久化规则。
本次恢复表明整机重新初始化后显卡可以重新供 Windows 使用,但没有证明跨系统切换失败的唯一根因,也没有修复自动切换的硬编码健康校验缺口。当前先保留 Windows 使用;不得将这次恢复表述为“共享 GPU 切换问题已彻底解决”。
## 后续修复:Windows→Ubuntu 一直“进入中”(2026-11-11 14:07)
13:49 的 Ubuntu 准备任务在 `service-waiting` 阶段等待 180 秒后失败。Windows 已正常关闭,Ubuntu 已开机,但 Linux NVIDIA 驱动从开机起报告 `fallen off the bus and is not responding to commands`,GNOME/Xorg 会话反复失败,Sunshine 未启动。Ubuntu 内停止桌面并卸载、重载 NVIDIA 模块仍返回 `No such device`。该现象不能解释成单纯页面动画或需要重复点击。
确认 VM100/101 关闭、VM102 正常关机、VFIO 组无人持有,且上游桥只有 GTX 965M 后,对 GPU 执行 sysfs `remove`、等待两秒、桥 `rescan`,核验同一 PCI 身份、vfio-pci 驱动和 D0,再启动 Ubuntu。此次无需重启宿主即恢复 GNOME、NvFBC 与 NVENC。首次恢复任务耗时 25.41 秒。该实验与前一轮只写 PCI `reset` 不同;不能将两者混称为已重复验证过的同一方法。
为使此步骤在后续开机时自动执行,增加 `tools/pve-shared-gpu-hook.py` 并部署为 `local:snippets/vdi-shared-gpu-reset.py`,绑定 VM100/101/102。实现仅适用于 starhe 的指定 GTX 965M、PCI 桥和 IOMMU 拓扑。每次 pre-start 必须确认三台全部停止、VFIO 组无人使用;使用 flock 和开机阶段预留,避免两次准备同时穿过检查。初始化失败保留 failed 预留,后续启动被阻止,不自动重放结果未明的操作;post-start 记录归属,post-stop 核验后释放。GPU 返回 D0 只代表开机前设备条件,仍不替代来宾驱动和真实硬编码核验。
部署前备份:`/root/vdi-linux-gpu-20261111/{100,101,102}.conf.before-gpu-hook` 和 `storage.cfg.before-gpu-hook`。local 存储内容类型保留原值并增加 snippets。Windows PVE 配置此次新增 hookscript,未修改 Windows 来宾鼠标、应用、驱动或硬件资源配置;不能再用此前“仅 onboot 不同”的历史对比描述当前配置。
验证结果:4 项本地回归通过,覆盖运行/占用拦截、连续启动预留、初始化失败不重放、错误 VM 不能认领。宿主实测在 Windows 运行时调用另一个 VM 的 pre-start,会拒绝操作并报告运行者,未重置正在使用的 GPU。部署后从盒子完成 Ubuntu→Windows(73.88 秒)和 Windows→Ubuntu(41.01 秒),均未重启宿主。Windows 设备错误码为 0,实际串流 H.264 NVENC,编码负载约 11%;最终 Ubuntu 实际连接确认 NvFBC、2560×1440、H.264 NVENC,编码负载约 29%,服务 active。1 Mbps 日志属于编码探测,最终会话实际视频预算为 18.988 Mbps,客户端请求档位仍为 25 Mbps。双光标隐藏标记保持存在。
当前仅 Ubuntu 运行并留在盒子桌面,Windows、麒麟停止,GPU 预留归属 VM102/running。本轮验证了一次双向轮转,未重新测试麒麟轮转,也未完成数十次循环或长期稳定性验收;不据此保证任意次数切换均无故障。平台当前仍以 serverinfo 判断服务就绪,硬编码健康尚需另行加强,不能把本钩子说成编码健康检查。
证据:`gpu-hook-unit-tests.log`、`gpu-hook-active-guard-test.log`、`gpu-hook-switch-tasks.csv`、`gpu-hook-windows-nvenc.log`、`gpu-hook-ubuntu-nvenc.log`、`gpu-hook-final-state.log` 及两台最终桌面截图。
回退时先退出串流,并逐台确认 hookscript 当前仍为本次路径,再执行 `qm set <VMID> --delete hookscript`;此操作只去掉本次钩子,不整份覆盖其他 VM 配置。保留 snippets 内容类型不会重置显卡。如出现 failed/prepared 预留,必须先核对所有 VM 实际电源、原启动任务、VFIO 占用及 PCI 设备状态,再由管理员处理 `/run/vdi-shared-gpu/reservation.json`;不要直接清空预留并反复开机。
## 补充验证:麒麟共享显卡切换(2026-11-11 14:30)
用户要求验证麒麟。开始检查时,用户已从 Ubuntu 切到麒麟,平台初次准备耗时 37.68 秒;同机重连的 0.49 秒任务不计为冷启动。NVIDIA 580.95.05 正常,OpenGL renderer 为 GTX 965M,源画面为 2560×1440,实际连接日志确认 NvFBC 与 H.264 NVENC,GPU 编码负载约 25%。现场看到软件商店正在安装更新,先等待并核对 aptdaemon 无活动事务、包管理锁释放、`dpkg --audit` 无异常后,才开始关机轮转,未中断或主动执行软件更新。
随后从盒子完成以下四次正常关机、共享 GPU 初始化、开机和连接服务准备:
| 方向 | 准备耗时 | 结果 |
| --- | ---: | --- |
| 麒麟→Windows | 79.31 秒 | 实际 H.264 NVENC,GPU 编码负载约 10% |
| Windows→麒麟 | 40.75 秒 | NVIDIA OpenGL、NvFBC、实际 H.264 NVENC,编码负载约 22% |
| 麒麟→Ubuntu | 36.82 秒 | 真 2560×1440、NvFBC、实际 H.264 NVENC,编码负载约 29% |
| Ubuntu→麒麟 | 38.01 秒 | NVIDIA OpenGL、NvFBC、实际 H.264 NVENC,编码负载约 23% |
四次均成功,宿主启动 ID 始终为 `df157c5a-ae91-4225-b4b7-f6ab8c0ed8c9`,本轮没有重启宿主或修改三台 VM 的配置。耗时以平台数据库任务创建到完成计算,不包含人手退出、检查和再次点击的间隔;服务准备完成也不等于最终画面已经出现,因此另外核对实际 CLIENT CONNECTED、最终编码器、GPU 负载和桌面截图。
麒麟启动后显示过其自身锁屏,最终通过 logind 解锁当前测试会话,并核对实际桌面。未关闭锁屏策略或修改登录配置。麒麟开机早期来宾日志时间有八小时偏差,最终已核对 NTPSynchronized=yes、系统时间恢复;轮转顺序与耗时依据平台记录,日志按当前 boot 和实际 Sunshine PID 筛选,避免混入旧启动记录。未修改 RTC 或 NTP 配置。
最终盒子日志确认 2560×1440 / 45 FPS 串流、RKMPP H.264 硬解;45 是协商串流帧率,不代表重新实测了终端持续呈现 45 FPS。请求码率仍为 25 Mbps,最终视频预算为 18.988 Mbps,1 Mbps 记录属于编码器探测阶段。保留原有麒麟桌面与光标配置。
最后从盒子发送 30 步桌面背景拖框,实际解码画面显示对应选框,finally 中松开鼠标按键成功。此检查验证基本输入和视频回显,不是物理输入延迟、掉帧率或画质客观一致性测量。此次完成了麒麟与另外两台各一次双向切换,未据此宣称两小时/八小时长稳,或麒麟全部交互延迟已经与 Windows 完全一致。
收尾仅麒麟 VM101 运行并连接,GPU 预留为 VM101/running;Windows、Ubuntu 均停止。结果取代前文保留 Ubuntu 的收尾状态。
证据:`kylin-cycle-switch-tasks.csv`、`kylin-cycle-windows-nvenc.log`、`kylin-cycle-return-from-windows.log`、`kylin-cycle-ubuntu-nvenc.log`、`kylin-cycle-return-from-ubuntu.log`、`kylin-cycle-final-state.log`、`kylin-cycle-final-drag.jpg` 和 `kylin-cycle-final-desktop.jpg`。
## 补充优化:终端调度对照与无线扫描(2026-11-11 15:43)
本轮保持 2560×1440、45 FPS、客户端请求 25 Mbps、H.264 SDR。两台实际 NvFBC / NVENC 保持有效,未调整原生鼠标样式或移速。没有修改 Windows 来宾的驱动、鼠标、应用或资源配置;为测试按平台流程正常关闭 Windows 并切到 Linux。此次持久调整在共用盒子的网络配置中,因而也影响盒子连接 Windows 时的网络路径。
### 实际保留的调整
盒子三次无线断开记录中有 `reason=34`。15:22:58 断开后,反复尝试同名 2.4 GHz 热点并被拒绝,直到 15:23:25 才恢复 5 GHz。先仅设置 5 GHz,15:30:31 仍断开,15:30:44 恢复;说明限制频段不足以修复断开本身。
进一步将盒子现有 YXTech 配置固定到当前 5 GHz 接入点 `f8:ce:21:a7:b9:50`。NetworkManager 文档说明固定 BSSID 会禁用漫游及后台扫描;此前断开间隔约五分钟,扫描参与问题是推断,尚未证明是唯一根因。Wi-Fi 省电原本已关闭,本轮没有把它记为新增优化。
配置已通过 nmcli 写入 `/etc/netplan/90-NM-9212612f-4dd0-4cf0-a21b-85413c900acf.yaml`,核对 `band: 5GHz` 和 BSSID。每次试验前设置了 90 秒自动回退,重连和 SSH 验证成功后取消回退;没有留下活动回退定时器。配置备份位于盒子 `/var/backups/vdi-wifi-20261111/`,不是 PVE,备份不复制到仓库以免带入无线凭据。
15:32:29—15:43:09 的约 10 分 40 秒观察中,没有再次出现无线断开或关联拒绝,越过两个此前约五分钟的周期。期间主动切换麒麟、Ubuntu并重连,不是同一桌面连续串流十分钟,也不是长期稳定性验收。若移动盒子、更换接入点或该 AP 不可用,需解除 BSSID 限制;本轮没有改路由器。
### 未保留的调度试验
确认 SDL 渲染线程申请高优先级因权限失败。先由 root 仅把当前 Moonlight 的 PacerRender 线程从 nice 0 临时改为 -10,保持普通 TS 调度;未使用 SCHED_FIFO、文件 capabilities、全进程提权或更改用户权限上限。固定接入点后,两台分别在同一连接内顺序 A/B,每类 50 次。表内为 P50 / P95,单位 ms:
| 系统 | PacerRender nice | 悬停回显 | 点击回显(含40ms按住) | 掩码字符回显 |
| --- | ---: | ---: | ---: | ---: |
| Ubuntu | 0 | 122.5 / 141.6 | 173.0 / 195.6 | 83.7 / 120.5 |
| Ubuntu | -10 | 121.7 / 151.0 | 172.8 / 213.7 | 79.1 / 105.9 |
| 麒麟 | 0 | 103.1 / 127.6 | 147.0 / 165.5 | 81.9 / 103.6 |
| 麒麟 | -10 | 101.3 / 121.3 | 146.5 / 172.8 | 86.1 / 99.6 |
悬停及点击中位数没有稳定收益,部分 P95 反而上升,因此两台试验均恢复 nice 0,没有持久化提权。Ubuntu 固定 AP 前另有两轮 A/B,同样没有一致收益;被断网打断的 A2、B2 与麒麟第一次 B 不计为完整结果。不能把警告消失或某一类输入的单轮改善解释为整体延迟降低。
### 功能与呈现复查
| 系统 | 拖动回显 P50 / P95(ms) | 观察到的新位置更新/秒 | 输入验证 |
| --- | ---: | ---: | --- |
| Ubuntu | 90.9 / 109.8 | 35.4 | 300 次末位置可见,松键成功 |
| 麒麟 | 84.4 / 106.9 | 37.2 | 300 次末位置可见,松键成功 |
以上为 XTest 输入至首次观察到唯一解码标记,排除实体 USB 鼠标和屏幕扫描;更新/秒是 60 Hz 拖动下采样到的独特位置,不等于解码或显示帧率。GTK 的合成页面提交没有业务后端,不能代表真实密码认证或应用启动耗时。
Ubuntu 在来宾内部另测本地 X11 标记,悬停中位数约 21 ms、点击约 78 ms(含40ms按住)、掩码字符约 5 ms,每类30次。它与盒子端测量路径不同,只用于区分来宾处理与串流路径,不将差值当作可直接消除的延迟。
结束前的 Ubuntu 单会话统计:接收/解码约45.03 FPS、呈现44.18 FPS、平均网络6 ms(variance栏1 ms)、解码7.67 ms、排队4.62 ms。麒麟对应会话呈现43.85 FPS。无线条件不恒定,不能将这几次统计差异全归因于固定 AP。network jitter 栏还包含客户端丢弃旧帧,不能全当无线丢包。
Ubuntu 再次退出和重连后,三处背景检查均未发现视频内重复箭头,仍有24×24的本地原生光标。临时 GTK 参考窗口已停止,桌面实际截图核验通过。
### 深层显示链路和边界
盒子仍是 RKMPP 硬解、DRM PRIME / EGL 呈现。现场 GPU 约800 MHz、90%—93%负载,不能承诺真2K60。部署源码明确要求 DRM master 才能直接设置显示 plane;现有原生光标实现也显式要求 X11。改成 DRM 直出需要同时完成 VT/显示所有权、光标后端、退出恢复及快捷键验证。本轮没有停掉 X11 或把“Direct rendering disabled”当成一个可随意开启的选项;没有声称已实现新的直接扫描输出或完全零拷贝链路。
本轮主要消除已观察到的无效频段重试并测试固定 AP 的短期稳定性,尚未证明 Ubuntu/麒麟全部交互延迟与 Windows 相同。继续提高 CPU 核数不能解决盒子 GPU 呈现吞吐和无线驱动/AP层问题。两小时/八小时、物理相机延迟及统一真实业务场景验收仍未完成。
### 收尾与回退
仅 Ubuntu VM102 运行并留在盒子上,Windows、麒麟停止;宿主未重启,共享 GPU 钩子和三台 VM 配置未改。Ubuntu 双光标修复、麒麟原有合成设置均保留。PacerRender / InputSend / FFDecoder 最终均为 nice 0、TS。
在盒子上解除本轮网络限制(会短暂断网):
```sh
sudo nmcli connection modify uuid 9212612f-4dd0-4cf0-a21b-85413c900acf 802-11-wireless.bssid '' 802-11-wireless.band ''
sudo nmcli connection up uuid 9212612f-4dd0-4cf0-a21b-85413c900acf ifname wlan0
```
证据:`wifi-before-5ghz.log`、`wifi-fixed-ap-final.log`、`*-sched-fixed-ap.jsonl`、`*-fixed-ap-drag.json`、`ubuntu-local-screen-response.raw`、`ubuntu-fixed-ap-client-stats.log`、`ubuntu-fixed-ap-double-cursor.json`、`optimization-host-final-state.log`。测量脚本为 `box-sched-pair.py`、`response-probe-50.py`、`guest-local-response.py`。
依据:[NetworkManager 无线配置](https://networkmanager.dev/docs/api/latest/settings-802-11-wireless.html)、[SDL Linux线程优先级实现](https://github.com/libsdl-org/SDL/blob/release-2.30.11/src/core/linux/SDL_threadprio.c),以及现场部署的 Moonlight DRM / 原生光标源码。