服务:plasma通知图标点击展开很卡

问题

面板上「通知」图标点开时很卡:点击后要等约 3 秒弹窗才出现。只有通知弹窗这样,音量 / 日历 / 网络等其它弹窗都正常;桌面本身不卡。

实测证据

检查结果
瞬时 CPU(每 0.1s 采 /proc/<pid>/stat 的 jiffies 增量)点开瞬间 plasmashell 烧满 1 个 CPU 核约 2 秒(两次点开 = 两次尖峰);kwin 峰值仅 18% ⇒ 合成器无责
是阻塞还是计算计算。主线程在该窗口最大「空隙」仅 0.498s,其余全是亚毫秒级调用 ⇒ 不是等待
系统监视器观感点击时该进程 CPU 从 0.1% 抬到 ~3% —— 与上一条同源(监视器显示的是平滑/均值,把尖峰摊平了)
QML 报错锚点Globals.qml:575: Unable to assign QString to int,每次打开弹窗恰好报一次

根因(上游源码定位)

plasma-workspace v6.6.6,applets/notifications/FullRepresentation.qml:51-63:

Connections {
function onExpandedChanged() { // 弹窗展开时
if (appletInterface.expanded) {
...
for (let i = 0; i < historyModel.count; i++) { // 遍历【全部历史】
let rowIdx = historyModel.index(i, 0);
historyModel.setData(rowIdx, true, ReadRole); // 逐条标记已读
}
}
}
}

⇒ 每次展开都对整个历史模型逐条 setData,每条触发一次 dataChanged + 委托重绘 ⇒ O(N) 次模型写入 + 大量重绘 ⇒ 烧满一个核约 2 秒。

这解释了全部现象:① 「积累一定内容后变慢」= N(历史总条数)在涨;② 「只有几条也慢」= 可见的几条 ≠ 遍历范围(N 是全部历史);③ 「只有通知弹窗」= 这段代码只在这里。

同路径另有上游类型 bug:Globals.qml:575 jobError: popup.jobError(声明为 int,实际给 QString)。

顺手修掉的另一个真问题:主题 colors 缺失导致 statx 风暴

排查中先发现:KDE 主题的可选文件 desktoptheme/<主题>/[variant/]colors 本机全缺 ⇒ 每次查找空扫整个 XDG_DATA_DIRS(88 个目录)。

strace 实测(80 秒窗口)数值
statx 调用总数1,375,763 次,其中 99% 是 ENOENT(找不到)
单条路径被查…/default/translucent/colors 617,864 次 + …/default/colors 617,840 次
常态 / 打开弹窗瞬间~500 次/秒 / 单次爆 8,400+

处置(已持久化 ✓):在 XDG_DATA_HOME(查找链第一位)补占位文件 ⇒ 实测 20 秒内 statx 归零。声明式落点 = plasma.nix 的 system.activationScripts.plasma-theme-colors(幂等,只补不覆盖)。

排查中走错的两条路(留档以免重蹈)

  1. 误判一:KDE 状态里的「残留引用」。卸掉 marktext/elisa 后,ksmserverrc 等四处仍留着指向旧 store 路径的条目,plasmashell 每次交互都在解析失败 ⇒ 清理后 Failed to resolve 归零。但这只清掉了真垃圾,不是卡的原因(相关 ≠ 因果)。
  2. 误判二:「CPU 平在 3.3%」。那是 ps 给的进程启动至今平均值,2 秒尖峰被摊平。改用 jiffies 增量才看见 100% 核。

转折点是停止推测、上量化工具:strace 统计 → jiffies 瞬时采样 → 上游源码比对。

最终裁决(2026-10-16):根因不修,改用「手动清理」

关键事实:通知历史是纯内存态、不落盘(plasmashell 打开的文件里没有通知库)⇒ 开机时 plasmashell 尚未启动,登录后历史天然从零开始;睡眠唤醒不重启 plasmashell,也不影响它。所以「每次开机清零」本身就已自动成立,无需机制。

真正的痛点:一次长登录会话内历史越攒越多 ⇒ 弹窗越来越慢(N 在涨)。

候选方案结论原因
给 plasma-workspace 打 QML 补丁(只标记未读项)放弃补丁已就位、并成功接入过 overlay;但需从源码重建 plasma-workspace(实测 20–30 分钟满 16 核),用户判定「连装一套 NixOS 都够了」,不值;且 KDE 版本一变就可能编不过
用户级 plasmoid 覆盖(家目录放一份改好的 applet)实测不可行该 applet 由 plasma_add_applet(… QML_ARGS …) 构建,QML 编进模块 + C++ 支撑;Plasma 确实去读了用户目录(说明用户级优先成立),但包结构校验不通过、标记未出现 ⇒ 文件级覆盖不被采用
定时重启 plasmashell(systemd user timer)否决没有「清空历史」的 DBus 接口,清空只能靠重启 plasmashell ⇒ ① 面板会闪(可见打断)② 定时器会变成「隐性常驻机制」,与睡眠唤醒纠缠(唤醒后可能补跑)
接受现状 + 卡了手动清(当前采用 ✓)采用零机制、零副作用;判据 = 变慢时右键通知图标 →「清除通知历史」即恢复

上游接口实测(本次一并记录):/org/freedesktop/Notifications 只有 CloseNotification(id) / Notify / GetCapabilities / Inhibit / UnInhibit / InvokeAction,没有「清空历史」类调用;/MainApplication 只有 Qt 通用方法。

当前运行时到底靠什么「不卡」(重要)

机制是否生效性质
主题 colors 占位生效 ✓(声明式,rebuild 也在)持久,但它治的是 statx 风暴(全桌面通用开销),不是弹窗专属
通知历史为空生效,但只是「现在空」瞬时——这才是「打开很快」的真正原因;历史再涨,慢会回来
QML 补丁 / 文件覆盖 / 定时任务均未启用见上表裁决

结论:现在不卡靠的是「历史是空的」,不是「修好了」。

复核命令

# 1) 点开弹窗时谁在烧 CPU(每 0.1s 采 jiffies 增量,100 jiffies/s = 1 核满载)
P=$(pgrep -f plasmashell | head -1)
while :; do awk '{print $14+$15}' /proc/$P/stat; sleep 0.1; done

# 2) 是否还有主题查找风暴(正常应接近 0)
sudo -n strace -f -e trace=statx -o /tmp/s.log -p $P -- sleep 20; grep -c desktoptheme.*colors /tmp/s.log

# 3) 主题 colors 占位文件在不在
find ~/.local/share/plasma/desktoptheme -name colors

# 4) 上游那一处是否已修(若有 ⇒ 升级 KDE 即自动解决)
# invent.kde.org → plasma/plasma-workspace → applets/notifications/FullRepresentation.qml
# 看 onExpandedChanged 里是否仍是「遍历全部历史逐条 setData」

边界与残留

  • 本机制是上游 QML 的性能问题,不是本机配置错误;换机/重装同样会遇到(随会话内历史累积加重)。
  • 唯一未做的待查:上游 master 版同一段是否已修(若已修 ⇒ 将来升级 KDE 自动解决,无需任何操作)。
  • 补丁文件留档:/etc/nixos/modules/system/laucher/plasma-notifications-readloop.patch(未启用;plasma.nix 里留了「如何重新启用」的注释)。
  • 用户级覆盖实验的残留已清理(备份见 ~/.hermes/cache/scratch/notif-plasmoid-override-attempt/)。
  • 另有一个与本次无关的既有报错:plasma-desktop-6.6.6/…/org.kde.plasma.icontasks/ 缺 mainscript(清理前后都在),待日后再看。