分类: 随笔

  • 似乎修复了唤醒后键盘短暂失效的问题

    This entry is part 3 of 3 in the series 机械革命无界 15XPro

    之前一篇文章的评论区有人提到过机械革命15XPro 暴风雪在唤醒后键盘会短暂失效的问题,往往需要重新睡眠再唤醒才能激活键盘。经过我的排查后发现,在该问题出现时,有两个比较重要的 Log 线索:

    Aug 27 09:04:52 arch kernel: atkbd serio0: Failed to deactivate keyboard on isa0060/serio0
    Aug 27 09:04:52 zarch kernel: atkbd serio0: Failed to enable keyboard on isa0060/serio0

    根据 Claude 以及互联网上相关的讨论,这个问题大概率跟内置键盘的驱动有关,通常可以通过尝试不同的 i8042/atkbd 相关参数来解决。

    跟 Claude 讨论一番过后,我决定添加如下 kernel parameters:

    i8042.reset=1 i8042.nomux=1 i8042.nopnp i8042.noloop atkbd.reset=1

    实际体验下来,键盘失效的问题已经一周多都没有复现了。

  • 性能与公平:解决 Linux 桌面无响应的取舍之道

    已经记不得从什么时候开始,我的 Linux 桌面偶尔会遇到无响应的问题,这个问题经常跟比较重的磁盘读写相关,例如更新 JetBrains IDE,JetBrains IDE 创建索引。之所以会把无响应的问题归结到磁盘读写上,是因为卡顿往往跟内存占用、CPU 使用率、进程数无关。卡顿的表现为:鼠标可以移动,但是 KDE 桌面包括状态栏无法更新;Kitty 可以创建新的 Tab,但是 Fish 启动会卡住;已有终端下虽然可以流畅输入命令,但是执行命令会卡住。这个周末因为成都一直在下雨,不太方便出门,决定来尝试解决卡顿问题。

    我的电脑配置如下:

    出现问题的固态硬盘型号是 KINGSTON SNVS1000G, SMART 信息如下:

    # nvme smart-log /dev/nvme1
    Smart Log for NVME device:nvme1 namespace-id:ffffffff
    critical_warning			: 0
    temperature				: 89 °F (305 K)
    available_spare				: 100%
    available_spare_threshold		: 10%
    percentage_used				: 31%
    endurance group critical warning summary: 0
    Data Units Read				: 61665672 (31.57 TB)
    Data Units Written			: 171536497 (87.83 TB)
    host_read_commands			: 967548759
    host_write_commands			: 2052988968
    controller_busy_time			: 75703
    power_cycles				: 79989
    power_on_hours				: 15798
    unsafe_shutdowns			: 241
    media_errors				: 0
    num_err_log_entries			: 0
    Warning Temperature Time		: 0
    Critical Composite Temperature Time	: 0
    Thermal Management T1 Trans Count	: 0
    Thermal Management T2 Trans Count	: 0
    Thermal Management T1 Total Time	: 0
    Thermal Management T2 Total Time	: 0

    官网上查到这块固态硬盘的设计 TBW 是 240TB,目前写入了 87.83TB,按照这篇文章的估算方法,这块硬盘正值壮年,属于如果挂掉了会令人惋惜的状态。既然硬盘是健康的,那么就需要从软件的角度来排查问题了。

    复现问题

    根据我的日常使用经验,卡顿往往伴随高磁盘 IO,故可以使用硬盘跑分工具测试来复现问题:

    fio --filename=/path/to/no_cow_test.fio --size=8GB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=120 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1

    fio 运行时,可以通过 htop 的 IO Tab 看到有明显的磁盘读写,这时如果运行不太常用的命令,比如前端切图仔电脑上的 rustc --version,就可以观察到明显的延迟。通过这种方式比较稳定地复现问题场景后,就可以继续接下来的排查了。

    检查日志

    journalctl -b -p err --no-pagerdmsg -T 展示的错误日志通常对排查问题非常重要,但是在我的卡顿问题复现时却没有记录下任何错误信息。问题的排查一度陷入僵局,这时就得靠 Gemini 大师帮我排查一下有哪些设置会影响存储设备的性能了。

    脏页

    在 Linux 系统中,当应用程序向文件写入数据时,这些数据通常不会立即被写入到物理磁盘上。相反,它们首先被写入到内存中的一个缓冲区(称为「页缓存」或「page cache」)。这些已经修改但尚未写入磁盘的内存页就被称为「脏页」。

    脏页机制可以有效提升磁盘性能,但为了防止脏页无限增长,我们可以设定 vm.dirty_ratio 参数限制脏页数据占总内存的百分比,更多介绍请看 Wiki

    对于我的配置而言,如果 dirty_ratio 过大,比如 20%,意味着脏页数据量最高达到 6GB,不仅会挤占其他应用的可用内存空间,还可能由于操作系统需要一次性写入大量数据造成卡顿。

    但在我的测试下,将 vm.ditry_ratio 以及相关参数调小一些带来的效果并不明显,所以还得向其他的方向上挖掘。

    IO 调度器

    IO 调度器是 Linux 内核的一个组件,它的主要任务是优化对存储设备(如硬盘、SSD、NVMe)的读写请求顺序。

    对于 SSD 设备来说,IO 调度器可以帮助确保每个进程都能获得合理的 IO 访问机会,避免某些进程被「饿死」,另外不同的调度算法会在数据吞吐量与请求延迟之间有不同的取舍,以适应不同的应用场景。

    在默认情况下,Linux 不会为 NVME 设备设置 IO 调度器,它假设这类设备上的控制器有自己的优化机制,不需要额外的软件层面调度。我们可以通过下面的命令查看当前在使用的调度器(被方括号包围):

    cat /sys/block/nvme1n1/queue/scheduler
    [none] mq-deadline kyber bfq

    然而在调度器的选择上,Gemini 跟 Arch Wiki 出现了分歧,Gemini 认为 NVME 以及 SSD 就应该选择 none 作为 io scheduler,但 Arch Wiki 认为 it depends

    The best choice of scheduler depends on both the device and the exact nature of the workload. Also, the throughput in MB/s is not the only measure of performance: deadline or fairness deteriorate the overall throughput but may improve system responsiveness. Benchmarking may be useful to indicate each I/O scheduler performance.

    考虑到我的日常使用场景是桌面应用,NVME 上自带的控制器完全不可能知道我正在使用的窗口应用,也就没法保障我主要使用场景下的响应速度,于是我决定采用 Pop_OS 的推荐,使用 Kyber 调度器。

    重试问题场景后,卡顿的情况缓解了一些,但跟我的预期还有很大偏差,很多命令可能需要 10s 以上才能输出结果。于是又尝试了使用 BFQ scheduler,终于 rustc --version 可以在后台运行重 IO 程序的情况下在 1s 内输出结果了。使用下面的 udev rule 就可以持久化设置 IO 调度器。

    # /etc/udev/rules.d/60-ioschedulers.rules
    ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"

    通过设置 IO 调度器很好的解决了我的问题,那么代价是什么呢?

    I/O 调度器性能对比

    相较于 none 调度器,其他的软件调度器都加入了额外的一层抽象,这势必会引入更多的开销,为了搞清楚降低延迟的开销,我进行了下面的测试。

    fio --filename=/path/to/no_cow/test.fio --size=8GB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1
    iops-test-job: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=256
    指标none(基准)BFQkyber
    读取 IOPS7,2147,018 (-2.7%)7,141 (-1.0%)
    写入 IOPS7,2357,039 (-2.7%)7,161 (-1.0%)
    总 IOPS14,44914,057 (-2.7%)14,302 (-1.0%)
    读取带宽28.2 MiB/s27.4 MiB/s (-2.8%)27.9 MiB/s (-1.1%)
    写入带宽28.3 MiB/s27.5 MiB/s (-2.8%)28.0 MiB/s (-1.1%)
    吞吐量性能指标
    延迟指标none(基准)BFQkyber
    读取平均延迟70.5ms72.4ms (+2.7%)71.2ms (+1.0%)
    写入平均延迟70.9ms72.9ms (+2.8%)71.7ms (+1.1%)
    50% 延迟70.8ms71ms (+0.3%)71ms (+0.3%)
    95% 延迟78ms89ms (+14.1%)81ms (+3.8%)
    99% 延迟82ms114ms (+39.0%)91-92ms (+11%)
    99.9% 延迟88ms132-133ms (+50.0%)128ms (+45%)
    延迟性能对比

    可以看到在单个进程的读写测试下, BFQ 跟 kyber 在吞吐量跟延迟上的表现要略逊一筹。而这些开销给 Linux 桌面场景下带来的提升量化后又有多少呢?这需要设计一个更加复杂的跑分测试了,我们需要让一个延迟敏感应用跟一个高吞吐量应用同时运行,然后对比不同 IO 调度器如何平衡两者的硬盘操作:

    # 低延迟小请求 (模拟交互式应用)
    fio --name=latency_sensitive \
        --filename=$TEST_DIR/latency_sensitive.fio \
        --size=2GB --direct=1 --rw=randread \
        --bs=4k --ioengine=libaio --iodepth=1 \
        --runtime=$RUNTIME --time_based \
        --group_reporting --output-format=json \
        --output=/tmp/latency_sensitive.json &
    
    # 高吞吐量请求 (模拟批处理)
    fio --name=throughput_heavy \
        --filename=$TEST_DIR/throughput_heavy.fio \
        --size=4GB --direct=1 --rw=randread \
        --bs=4k --ioengine=libaio --iodepth=512 \
        --runtime=$RUNTIME --time_based \
        --group_reporting --output-format=json \
        --output=/tmp/throughput_heavy.json &

    不同的 IO 调度器在我电脑上的实际测试结果如下:

    调度器延迟敏感应用 IOPS延迟敏感应用平均延迟高吞吐应用 IOPSIOPS 比率
    BFQ5,4740.18 ms129,35023.63
    kyber4,6110.22 ms138,90430.12
    none3,1540.32 ms146,10446.32

    IOPS 比率:高吞吐应用获得的 IOPS 是延迟敏感应用的多少倍

    通过上面的测试可以看到:

    1. BFQ 在公平性方面表现最佳,真正保护了延迟敏感应用
    2. None 调度器确实能提供最高的原始吞吐量,但以牺牲公平性为代价
    3. Kyber 提供了较好的平衡,但在极端公平性方面不如 BFQ

    结论

    正如 Arch Wiki 所说,如何选择 IO 调度器取决于你的使用场景跟工作负载,在我的工作电脑上,BFQ 才是那个能够让我这块中年硬盘提供最佳桌面应用使用体验的调度器。

  • 提升机械革命无界 15XPro 暴风雪的充电速度

    This entry is part 2 of 3 in the series 机械革命无界 15XPro

    无界15XPro 的 99Wh 电池容量属实很大,但充电速度一言难尽,基本上要 4~5 小时左右才能从 10% 充到 100%。经过一番搜索后,总算找到了提升充电速度的方法。

    安装 Tuxedo Control Center 后,可以在 Settings 中找到 Battery Charging Options,只需要将 USB-C charging options 设置为 Priorize battery charing speed 就行。另外,如果长时间插电使用,还可以将 Charging profiles 设置成 Stationary use,这将会在硬件层面限制电池充电到 80% (但系统设置仍会显示充电到 100%)。

    如果你没安装 Tuxedo Control Center 也没关系,只要安装了驱动程序 (aur/mechrevo-drivers-dkms) ,就能通过下面两个 sysfs 接口实现同样的功能:

    cat /sys/bus/platform/drivers/tuxedo_keyboard/tuxedo_keyboard/charging_profile/charging_profile
    cat /sys/bus/platform/drivers/tuxedo_keyboard/tuxedo_keyboard/charging_priority/charging_prio
  • OBS 在 Linux 下启用 AMD GPU 加速

    OBS 在 Linux 平台下默认使用软件视频编码器,从而在录屏的时候造成 CPU 干活,GPU 摸鱼的场面。

    像我在使用的 AMD GPU,在正确安装驱动程序后,修改 OBS 设置中的 Output Mode 为 Advanced ,然后选择 FFmpeg VAAPI 作为视频编码器,这样就可以使用 GPU 编码视频了。

    可以看到, OBS 的 CPU 使用率大幅下降,并且 GPU 也在干活了。

  • claude code 使用心得

    一些常用的 /slash-commands

    /init

    让 claude code 到项目之前,最好先执行一下 /init,这样 claude code 就可以更加了解项目的功能以及编码习惯。不定期地在会话中执行 /init 也可以让 cc 及时了解项目的新规则,帮助它写出规范的代码。

    /compact

    用来压缩上下文,保留当前会话的记忆,但更省 token。

    /clear

    用来重置上下文,完全清楚当前会话的记忆,相当于重新开始会话。

    # new memory

    使用 # 开头就可以让 claude code 将你交代的事项记录在备忘录中,可以用来拓展 claude.md 中遗漏的项目约定或者你个人的习惯。

    向 claude code 布置任务的语言技巧

    我最常用的语言组织方式是这样的:

    描述现状

    要解决的问题

    关于解决这个问题的想法(如果有的话)

    任务大小最好控制在上面的描述可以在你能接受的范围内只用键盘完成输入,这样做的底层逻辑是人想要偷懒,会尽量少地用键盘打字,从而限制单个任务的大小,如果任务过于复杂,人出于打字上的懒惰,就不得不拆分任务。

    在我的实践下,这样交代任务对于 gemini-2.5-flash 跟 GLM-4.5 来说都会比较清晰且聚焦。

    手动压缩重置上下文

    由于 CC 完全不会有取舍地压缩上下文,所以,当我们准备开启一次新的任务时,最好手动压缩(/compact)或重置(/clear)上下文,这样做可以节省 Token 用量。

    何时压缩呢?当我们接下来的任务在代码文件上有切换,且跟前文有比较大的关联,但前文的要求没有被记录在 claude.md 或者 memory 中,压缩上下文就是比较好的选择。
    何时重置?当开始一个完全没有关联的新的任务时,我们可以选择重置上下文。

    模型能力对 Claude Code 的影响

    目前我中强度地测试了两种模型:GLM-4.5 跟 Gemini-2.5-Flash,前者价格只有 Claude Sonnet 4 的 1/10,后者更是只有 Claude Sonnet 4 的 1/50。

    从 Aider 的评测可以看到 claude sonnet 4 跟 gemini 2.5 flash 的性能差异并没有很大。

    而在实际的使用体验中,两者在修复构建脚本、CI 配置文件、升级 monorepo nx 的任务中,GLM-4.5 跟 Gemini-2.5-Flash 表现没有太多差异,都表现出了完整的 PDCA 行为,而且在细节执行层面也都表现出了一定的「倔强」性格。

    适合 Claude Code 的任务

    那些可以只在命令行完成验证任务最适合 claude code,这样 claude code 就可以通过执行命令的方式,验证任务是否完成,并且自动地在验证失败时调整解决方案。

  • 早知道 zswap 这么配置就好了

    swap 对于 Linux Server 来说可能是一剂毒药,但对于我这种经常要打开几十个 Tab 的 Linux Desktop 用户来说则可能是救命稻草。网上关于 swap 的调优众说纷纭,我决定给这个充满争议的话题再添一些乱。

    简单来说,我发现使用完全不写入硬盘的 zswap 搭配一个 swap 文件(或分区)要比单纯只用 swap + zswap 要更加适合日常办公场景。

    zswap 是一种 swap 跟 RAM 中间的一个压缩池。当一块内存将被送进 swap 的时候,zswap 会将其先压缩然后放进一个单独的内存池中,而不是直接放进 swap 设备。当 zswap 内存池快满或者这块内存不适合压缩(比如压缩后体积变大了)的时候,zswap 则会将其直接放进 swap 设备。

    通过安装 aur/zswap-disable-writeback ,可以几乎禁用掉 zswap 将内存解压写入 swap 的行为,这时 zswap 就会像 zram/swap 一样工作——仅压缩内存到内存池,不写入到更慢的 swap 设备,例如,硬盘分区或者 swap 文件。

    这样做的好处就是 swap 设备可以空出来用于系统休眠,而且 zswap 仍可以给操作系统提供更多的内存空间,更高效的使用内存。

    比如,在一个有 32GB RAM 的设备上,默认预留 20% 的空间来创建 zswap 的内存池,假设压缩比在 4.0 左右,那么这台设备在理论上可以给应用程序分配的内存将高达 51.2GB ,立省一条 16GB 内存

    在上面的配置下,还可以将 swappiness 设置到 100 以上,让操作系统更加激进地将内存交换出 RAM,给当前正在运行的活跃操作空出更多的空间,以应对突发性的内存需求(比如,打开新的浏览器 Tab)。

    相较于只使用硬盘作为 swap 设备,禁用 writeback 的 zswap 还有经济性上的优势,只要我们的内存需求在大多数情况下能够被 zswap 的内存池满足(在上面的例子中大约是 51GB),就不会发生由 swap 引起的硬盘 IO,有助于延长硬盘的寿命。

  • 在机械革命无界 15XPro 暴风雪上运行 Linux

    This entry is part 1 of 3 in the series 机械革命无界 15XPro

    最近把工作电脑换成了机械革命无界 15XPro 暴风雪,在收货后小小折腾了一两天后,终于让他大部分的功能工作正常了。

    键盘背光跟散热风扇的驱动

    可以参考这篇文章中的介绍安装来自德国一家公司维护的驱动。驱动安装好后,还可以安装类似鸡哥控制面板的 TUXEDO 控制面板,切换性能模式跟调整键盘背光 RGB:

    内置屏幕掉帧

    笔记本内置屏幕在 60Hz 时会频繁随机掉帧,这个现象跟 VRR 有关,需要强制启用 VRR。

    除此之外我还遇到了使用 Spectacle 截图时,外置显示器闪烁的问题,需要强制关闭外置显示器的 VRR。

    睡眠(suspend)后被立即唤醒

    当通过睡眠按键(Fn + F1)或者 systemctl suspend 进入睡眠状态时,系统会被立即唤醒,需要第二次尝试才能成功睡眠。

    反复阅读 https://wiki.archlinux.org/title/Power_management 系列文章后,我在 deepseek-r1 的帮助下成功地找出了这个问题的根因。

    TLDR

    创建一个 udev rule,禁用 PS/2 键盘的 Wakeup Trigger。

    # sudoedit /etc/udev/rules.d/99-disable-keyboard-wakeup.rules
    # Disable wakeup for PS/2 keyboard controller
    ACTION=="add", SUBSYSTEM=="serio", KERNEL=="serio0", ATTR{power/wakeup}="disabled"

    然后重载 udev rules:

    sudo udevadm control --reload-rules
    sudo udevadm trigger

    重启系统后验证是否生效:

    $ cat /sys/devices/platform/i8042/serio0/power/wakeup
    disabled

    现在尝试睡眠,就不会被立即唤醒了。

    排查过程

    首先安装 amd-debug-tools,运行 amd-s2idle test ,查看当前系统是否满足 s2idle 的要求:

    $ amd-s2idle test
    💻 AMD Ryzen AI 9 H 365 w/ Radeon 880M (family 1a model 24)
    💻 MECHREVO WUJIE Series (STX\KRK)
    🐧 Arch Linux
    🐧 Kernel 6.12.32-1-lts
    🔋 Battery BAT0 (OEM standard) is operating at 100.00% of design
    ✅ ASPM policy set to 'default'
    ✅ GPIO driver `pinctrl_amd` available
    ✅ PMC driver `amd_pmc` loaded (Program 11 Firmware 93.4.0)
    ✅ USB3 driver `xhci_hcd` bound to 0000:65:00.4, 0000:67:00.0, 0000:67:00.3, 0000:67:00.4
    ✅ USB4 driver `thunderbolt` bound to 0000:67:00.6
    ✅ System is configured for s2idle
    ✅ GPU driver `amdgpu` bound to 0000:65:00.0
    ✅ PC6 and CC6 enabled
    ✅ SMT enabled
    ✅ IOMMU properly configured
    ✅ ACPI FADT supports Low-power S0 idle
    🚦 Logs are provided via dmesg, timestamps may not be accurate over multiple cycles
    ✅ LPS0 _DSM enabled
    ✅ WLAN driver `mt7921e` bound to 0000:62:00.0
    ❌ Kernel is tainted: 12288
    💯 Your system does not meet s2idle prerequisites!
    🗣️ Explanations for your system
    🚦 Kernel is tainted
    A tainted kernel may exhibit unpredictable bugs that are difficult for this script to characterize. If this is intended behavior run the tool with --force. 
    For more information on this failure see:https://gitlab.freedesktop.org/drm/amd/-/issues/3089

    可以看到这里提示我的 kernel 被 tainted 了,这是安装 mechrevo-drivers-dkms 引起的,可以忽略。

    既然系统符合 s2idle 的要求,说明可能是某个设备在唤醒系统,deepseek 给出了接下来的排查思路,启用 PM 日志:

    # Enable verbose PM debugging
    echo 1 | sudo tee /sys/power/pm_print_times<br>echo 1 | sudo tee /sys/power/pm_debug_messages
    # Now try to suspend again
    systemctl suspend
    # Check dmesg after resume
    dmesg | grep -i "wake\|resume\|acpi"

    再次执行 systemctl suspend 复现问题后,可以在 dmesg 中看到下面的日志:

    [ 4636.873132] xhci_hcd 0000:67:00.4: PM: pci_pm_suspend_noirq returned 0 after 42252 usecs  
    [ 4636.873146] thunderbolt 0000:67:00.6: PM: pci_pm_suspend_noirq returned 0 after 42269 usecs  
    [ 4636.873169] pcieport 0000:00:08.3: PM: calling pci_pm_suspend_noirq @ 29723, parent: pci0000:00  
    [ 4636.878632] pcieport 0000:00:02.1: PM: pci_pm_suspend_noirq returned 0 after 10561 usecs  
    [ 4636.878653] pcieport 0000:00:03.2: PM: pci_pm_suspend_noirq returned 0 after 11025 usecs  
    [ 4636.885192] pcieport 0000:00:08.1: PM: pci_pm_suspend_noirq returned 0 after 12279 usecs  
    [ 4636.885300] pcieport 0000:00:08.3: PM: pci_pm_suspend_noirq returned 0 after 12119 usecs  
    [ 4636.885359] PM: noirq suspend of devices complete after 54.690 msecs  
    [ 4636.885376] ACPI: _SB_.PCI0.GPP5: LPI: Constraint not met; min power state:D1 current power state:D0  
    [ 4636.885381] ACPI: _SB_.PCI0.GPP6: LPI: Constraint not met; min power state:D1 current power state:D0  
    [ 4636.885388] ACPI: _SB_.PCI0.GPP4.SDCR: LPI: Constraint not met; min power state:D3hot current power state:D0  
    [ 4636.886012] PM: Triggering wakeup from IRQ 9  
    [ 4636.886504] ACPI: _SB_.PEP_: Successfully transitioned to state screen off  
    [ 4636.887420] ACPI: _SB_.PEP_: Successfully transitioned to state lps0 ms entry  
    [ 4636.887625] ACPI: _SB_.PEP_: Successfully transitioned to state lps0 entry  
    [ 4636.888555] PM: suspend-to-idle  
    [ 4636.888592] ACPI: EC: ACPI EC GPE status set  
    [ 4636.888623] ACPI: PM: Rearming ACPI SCI for wakeup  
    [ 4636.891279] PM: Triggering wakeup from IRQ 1  
    [ 4639.593124] amd_pmc: SMU idlemask s0i3: 0xffff1abd  
    [ 4639.593188] ACPI: PM: Wakeup unrelated to ACPI SCI  
    [ 4639.593189] PM: resume from suspend-to-idle  
    [ 4639.594699] amd_pmc AMDI000A:00: Last suspend didn't reach deepest state  
    [ 4639.595185] ACPI: _SB_.PEP_: Successfully transitioned to state lps0 exit  
    [ 4639.595760] PM: Triggering wakeup from IRQ 9  
    [ 4639.596746] ACPI: _SB_.PEP_: Successfully transitioned to state lps0 ms exit  
    [ 4639.597719] ACPI BIOS Error (bug): Could not resolve symbol [_SB.ACDC.RTAC], AE_NOT_FOUND (20240827/psargs-332)  
    [ 4639.597729] ACPI Error: Aborting method _SB.PEP._DSM due to previous error (AE_NOT_FOUND) (20240827/psparse-529)  
    [ 4639.597737] ACPI: _SB_.PEP_: Failed to transitioned to state screen on

    Deepseek 大胆推断是 IRQ 1 (typically the i8042 keyboard controller) 造成的问题,可以通过下面的方法来验证:

    echo "disabled" | sudo tee /sys/devices/platform/i8042/serio0/power/wakeup

    重试睡眠后,系统果然安然入睡了~

    进入 s2idle 睡眠后,一晚上大概会消耗 10% 左右的电量。

    Firefox 播放视频时会触发 GPU 图形崩溃

    当启用 Firefox 的硬件加速后,播放视频会让 GPU 崩溃,丢失全部的显存内容。还好这个问题已经被 AMD 修复,升级到最新的内核即可。

    色彩管理

    机械革命提供了官方的色彩文件,但必须要在 Windows 下安装机械革命控制台才能下载(官方客服并不受理此类咨询)。加载了官方的色彩配置文件后,可以比较明显地缓解低亮度下对比度过低的问题。为了方面读到这篇文章的你,点击下面的链接就可以下载到这份色彩配置文件~

    ipfs://QmaR5ZxFXNwcsjn9XZq6CpDfRFyoffDEr9fpi15Hmb31K7

    开机后有概率屏幕卡死

    开启自适应同步后可解决,感谢 LY 提供的解决方案。

  • 当一位拥有 root 权限的安卓用户升级到了 ColorOS 15

    大版本号的系统更新往往意味着 A Lot of BREAKING CHANGES!

    LSPosed

    需要安装一个第三方修改版的 LSPosed 以支持 Android 15。
    https://github.com/JingMatrix/LSPosed/releases/tag/v1.10.1

    或者申请加入 LSPosed 内测版本

    允许后台应用访问粘贴板

    https://github.com/Kr328/Riru-ClipboardWhitelist
    这个模块其实在 Android 14 时就已经无法正常工作了,升级到 Android 15 后完全可以卸载了。

    为了能够让 KDE Connect 可以正常访问剪贴板,需要用搭配一个 Magisk 模块跟一个 XPosed 模块使用。

    draumaz/kdeconnectbidirectionalclipboard 模块允许 KDE Connect 在开机后自动获取剪贴板相关的权限。

    entr0pia/xposed-clipboard-whitelist 则允许 KDE Connect 在后台读取剪贴板内容。

    让后台应用能够接收 FCM 通知

    允许 GMS 熄屏后继续运行

    参考酷安网友(丛雨不是粽子精)的帖子,需要在开机后以 root 权限运行这条命令:

    settings put secure google_restric_info 0

    或者你可以直接使用我制作的 Magisk 模块

    使用 fcmfix 启动未运行的应用

    kooritea/fcmfix: [xposed]让fcm唤醒已完全停止的应用 模块允许在国行系统上收到 fcm 推送后唤醒未启动的应用。

    推荐选择如下作用域:

    为了允许被唤醒的应用能够被启动,需要手动在 ColorOS 的 Settings/Apps/Auto launch 中授予自启动权限。否则当消息推送到手机上时,由于目标应用无法自启动,fcmfix 会代为生成一条仅包含应用包名的消息。

    fcmfix 支持有选择性的唤醒应用,我建议为了方便,可以勾选全部的包含 fcm 的应用,因为在 ColorOS 上,如果你不单独地为各个应用配置自启动权限,应用是无法在后台启动的。

    让 NoActive 支持 fcm

    如果你像我一样使用 NoActive 模块来严格地管理后台,你还需要参考 NoActive 的文档,启用全局 fcm 支持

    分享菜单清理

    每个应用都很想占据用户的分享菜单,但是 Android 的分享菜单管理功能又过于弱鸡,一个比较简单的方案是在分享菜单页面长按图标,将最常用的应用置顶。

    如果非常想要清理分享菜单而且不嫌麻烦的话,可以使用爱玩机工具箱提供的组件状态管理功能,禁用掉分享、批量发送之类的活动。

  • Obsidian 数据同步方案:从 Git 到 Syncthing 的平滑切换

    Obsidian 作为一款本地优先的笔记软件,数据安全始终是用户关注的重点。我之前选择 Git 来进行版本控制,但随着 Obsidian 插件的不断增加,有些插件会生成大量二进制文件,这些文件如果直接存储在 Git 仓库中,会快速消耗 Git LFS 的免费存储额度。

    我最初考虑使用 Remotely Save 插件的 WebDAV 功能将数据备份到 NAS,但在 QNAP 上频繁遇到 403 错误,最终决定采用更稳定的 Syncthing 方案。

    Syncthing 在 QNAP 上的部署要点

    在 QNAP 上安装 Syncthing 需要通过第三方软件源 MyQNAP.org,该源提供了两个 Syncthing 安装包:

    • Syncthing:以普通用户权限运行
    • Syncthing Run As Root:以 root 用户权限运行

    建议选择 Syncthing,原因如下:

    1. 权限管控更安全:避免 root 权限带来的安全隐患
    2. 多用户兼容性更好:非管理员用户也能正常访问 Syncthing 同步的文件

    :安装后系统会自动创建 syncthing 用户,默认属于 everyone 用户组

    配置优化建议

    1. 文件夹权限设置: 同步文件夹的权限配置需要特别注意,建议设置为 <user>:everyone 模式,确保 Syncthing 有完整的读写权限。
    2. Ignore Permissions 选项:在 Syncthing 中启用该选项,因为普通用户权限的 Syncthing 无法修改其他 NAS 用户的文件权限。
    3. Linux 桌面端推荐:建议使用 Syncthing GTK,它提供了更友好的图形界面,并支持后台运行。
    4. QNAP 共享文件夹的位置:在 QNAP 中,用户创建的共享文件夹都位于 /share/ 目录下。

    Web UI 访问优化

    如果通过 Nginx Proxy Manager 反向代理 Syncthing 的 Web UI,请务必执行以下设置:

    • 取消 Cache Assets 选项
    • 原因:Syncthing 依赖 /meta.js 文件验证登录状态,缓存 Assets 会导致登录功能异常

    这种同步方案既解决了 Git LFS 的存储限制,又避免了 Remotely Save 的 403 问题,是目前我认为比较理想的 Obsidian 数据同步方案。建议在切换前做好数据备份,确保万无一失。

  • 划词翻译插件的 Prompt

    沉浸式翻译固然好用,但是不利于学习单词,当遇到不认识的单词时,我更倾向于使用划词翻译插件。

    下面就是我用来执行翻译任务的 Prompt:

    你是一名优秀的翻译人员,熟练掌握各种语言,拥有母语般的掌握程度。
    
    在翻译任务中,你需要将「原文语言」翻译成「目标语言」,任务要求如下:
    
    1. **单词或词组的翻译**
       - 直接给出音标、词性跟含义。
       - 用「原文语言」给出简单易懂的解释,确保初学者能够理解。
       - 示例:
         - 翻译:
           - 音标:/ˈæp.əl/
           - 词性:名词
           - 含义:苹果
           - 原文语言解释:A round fruit with red, green, or yellow skin and white flesh.
    
    2. **句子或段落的翻译**:把握原文的精髓,用「目标语言」复述,而不是机械的翻译。
    
    3. **输出格式**:纯文本,不要使用 markdown 标记。
    
    现在,翻译的「目标语言」是 {{target}},以「原文语言」编写的待翻译文本如下:
    
    {{text}}

    上面的 prompt 使用了一些 prompt 技巧,使得 gpt-4o-mini 级别的模型也能够很好的完成翻译目标,这些技巧包括:

    • 结构化地组织语言,使得任务目标更加清晰,减少 LLM 的阅读障碍
    • 提供样例,就算是弱智一些的 LLM 也会严格按照样例输出。
    • 定义变量,由于翻译场景的限制,Prompt 阶段我们不可能得知待翻译文本的书写语言,通过定义「原文语言」跟「目标语言」并明确它们之间的关系,使得我们可以在 prompt 中通过这些「变量」来指代它们。