pmset -g log 在我这台 Mac 上,一次输出23.9 MB。

MenuCue v0.5.0 的发布说明里,Power 页写着睡眠和唤醒的诊断,有唤醒历史。差不多两个小时后的一个提交说明里写着,这个列表在这台 Mac 上其实一直是空的。读取有个16 MB 的上限,23.9 比16大,命令被掐掉,界面上留下的是一句英文报错,大意是返回的数据太多。

空列表

那23.9 MB 里,98.6%是一个叫 Assertions 的段落,这次调用根本不读它。要的那一点东西,混在十万多行里。

改法是边读边筛:管道里的数据一路读过去,只留符合条件的行。最后23.9 MB 里留下了260 KB,后面要处理的只有这260 KB。

先量一下

筛是筛了,一开始很慢。提交说明里的端到端数字,是从36.5秒到12.0秒,其中5.4秒是 pmset 自己在吐数据。

慢的地方有两处,都在应用这一边。一处是拆行:每拆一行就从缓冲区前面删掉一段,24 MB 拆下来成了平方级。另一处是过滤函数收的是 String,为了丢掉98.6%的行,先给105,000行每一行造一个 String,后来改成了按字节过滤。

最后是12.0秒。我觉得这组数字最有用的地方,是告诉我哪一块还能动,哪一块碰不了,那5.4秒就碰不了。

同一个提交里还修了一处更难看的。匹配唤醒的正则没锚住,pmset 的列是补了空格对齐的,「Wake」把「Wake Requests」那一段也吃了进来。那一段是睡下去的时候写的,记的是将来打算醒的时间。结果列表里大约30%是还没发生的唤醒,被当成发生过的,还算进了每天的次数。

18 比 60

不到十分钟,下一个提交又去碰了那一段。

之前的唤醒列表只能显示硬件中断的名字,一串 smc.sysState.Wake 开头的东西。真正安排这次唤醒的进程,其实一直在同一份输出里,就在刚被剔掉的 Wake Requests 里,解析器把它丢了。同一段日志,先从「发生过的唤醒」里剔出去,不到十分钟又拿来当线索。

规矩定得很保守。请求里只有标了星号的那条算候选,因为只有它会最先触发。唤醒时间和请求时间差在90秒以内才算对上,对不上,就写系统记录里的中断名,不去猜离得最近的是哪个进程。最近60次唤醒里,能说出名字的有18次,剩下的42次就老老实实显示原因。

又过了二十个小时左右,电池卡片上加了预估续航,也是这个思路。取系统自己给的数,和按电量百分比除以掉电速度算出来的数,两个里小的那个,再打九折。充电时不显示,超过24小时也不显示,因为那种数是空闲时的噪声外推出来的,不叫续航。代码注释给的理由是这两个数都偏乐观。

一条河

差不多同时,电池卡片上还加了一张分流图,照着 AlDente 里那种画法。插着电的时候,电从插头那头出来分成两股,一股进电池,一股进系统,像一条河分了叉。电池来帮忙的时候反过来,两股汇成一股。

第一版里,插头、电池、系统那几个方块的高度,和飘带的粗细都跟瓦数挂钩,各设了个下限,免得小的那个放不下图标。一个小时之后的提交,标题的意思是让飘带按瓦数成比例,让微光看得见。也就是说第一版不成比例。

改完的样子是:一条飘带从头到尾一个粗细,粗细就是读数。方块不再跟着瓦数变,大小固定,各自居中在自己那股水流上,飘带比方块粗也没关系。微光的周期从6秒改成了3秒。

最细的那一股还是有个下限,11个点(point,不是像素),再细标签就放不下了。所以整张图也不是完全按比例的,最细的那一股是例外。