ps 打印的调度优先级是错误的?

通常我们在 Linux 平台会用 ps(1) 查看当前运行的所有进程信息(快照),它会输出 UID, PPID, PID, TIME, CMD 等信息,如下:

[root@VM-0-11-tlinux ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Aug30 ? 00:03:46 /usr/lib/systemd/systemd --system --deserialize 17
root 2 0 0 Aug30 ? 00:00:00 [kthreadd]
root 4 2 0 Aug30 ? 00:00:00 [kworker/0:0H]
root 6 2 0 Aug30 ? 00:00:00 [mm_percpu_wq]
root 7 2 0 Aug30 ? 00:00:44 [ksoftirqd/0]
root 8 2 0 Aug30 ? 00:01:14 [rcu_sched]
root 9 2 0 Aug30 ? 00:00:00 [rcu_bh]
root 10 2 0 Aug30 ? 00:00:00 [migration/0]
...

以上信息有时候不足以排查问题,比如进程的 nice 值,调度优先级都没有显示。怎么办?根据 ps(1) 所述可以用 -l 参数显示包含了 nice 值,PRI 等信息,如下:

[root@VM-0-11-tlinux ~]# ps -el
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 0 80 0 - 13547 ep_pol ? 00:03:46 systemd
1 S 0 2 0 0 80 0 - 0 kthrea ? 00:00:00 kthreadd
1 I 0 4 2 0 60 -20 - 0 worker ? 00:00:00 kworker/0:0H
1 I 0 6 2 0 60 -20 - 0 rescue ? 00:00:00 mm_percpu_wq
1 S 0 7 2 0 80 0 - 0 smpboo ? 00:00:44 ksoftirqd/0
1 I 0 8 2 0 80 0 - 0 rcu_gp ? 00:01:14 rcu_sched
1 I 0 9 2 0 80 0 - 0 rcu_gp ? 00:00:00 rcu_bh
1 S 0 10 2 0 -40 - - 0 smpboo ? 00:00:00 migration/0
...

看起来调度优先级(PRI)和 nice 信息都有了,但是有些奇怪,它们的值对应关系为: PRI=NI+80。OK,看了手册页,它说 -c 参数可以打印关于调度器的相关信息,我们看看:

[root@VM-0-11-tlinux ~]# ps -elc
F S UID PID PPID CLS PRI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 TS 19 - 13547 ep_pol ? 00:03:46 systemd
1 S 0 2 0 TS 19 - 0 kthrea ? 00:00:00 kthreadd
1 I 0 4 2 TS 39 - 0 worker ? 00:00:00 kworker/0:0H
1 I 0 6 2 TS 39 - 0 rescue ? 00:00:00 mm_percpu_wq
1 S 0 7 2 TS 19 - 0 smpboo ? 00:00:44 ksoftirqd/0
1 I 0 8 2 TS 19 - 0 rcu_gp ? 00:01:14 rcu_sched
1 I 0 9 2 TS 19 - 0 rcu_gp ? 00:00:00 rcu_bh
1 S 0 10 2 FF 139 - 0 smpboo ? 00:00:00 migration/0

打印出了进程所使用的调度策略(CLS),然而,PRI 居然又变了!这次 pid 1(systemd) 的优先级显示的不是 80,而是变成了 19。这是为何?

如果现在就觉得有点混乱的话,我们再看看 top(1) 输出的:

[root@VM-0-11-tlinux ~]# top -b -o -PID
top - 17:20:13 up 20 days, 3:39, 3 users, load average: 0.00, 0.00, 0.00
Tasks: 87 total, 1 running, 46 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 6.2 sy, 0.0 ni, 93.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 876288 total, 69040 free, 96548 used, 710700 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 606368 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 54188 5212 3700 S 0.0 0.6 3:46.98 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.14 kthreadd
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
7 root 20 0 0 0 0 S 0.0 0.0 0:44.81 ksoftirqd/0
8 root 20 0 0 0 0 I 0.0 0.0 1:14.80 rcu_sched
9 root 20 0 0 0 0 I 0.0 0.0 0:00.00 rcu_bh
10 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0

top(1) 输出同样的进程 systemd,它的优先级又变成了 20. 这又是为什么?

top(1) 的手册页会告诉你,它显示的确实是调度优先级:

   16. PR  --  Priority
       The scheduling priority of the task.  If you see `rt' in this field, it means the task is running under real time scheduling priority.

事实上,大多数 Linux 发行版提供的 ps(1), top(1) 命令都属于 procps-ng(https://gitlab.com/procps-ng/procps) 这个软件包,但是为什么它们显示进程调度优先级的时候如此不同,以至于连 ps(1) 自己不同的参数下显示的也不一样?

我们直接看看 ps(1) 的代码,里面有如下注释:

// "PRI" is created by "opri", or by "pri" when -c is used.
//
// Unix98 only specifies that a high "PRI" is low priority.
// Sun and SCO add the -c behavior. Sun defines "pri" and "opri".
// Linux may use "priority" for historical purposes.
//
// According to the kernel's fs/proc/array.c and kernel/sched.c source,
// the kernel reports it in /proc via this:
//        p->prio - MAX_RT_PRIO
// such that "RT tasks are offset by -200. Normal tasks are centered
// around 0, value goes from -16 to +15" but who knows if that is
// before or after the conversion...
//
// <linux/sched.h> says:
// MAX_RT_PRIO is currently 100.       (so we see 0 in /proc)
// RT tasks have a p->prio of 0 to 99. (so we see -100 to -1)
// non-RT tasks are from 100 to 139.   (so we see 0 to 39)
// Lower values have higher priority, as in the UNIX standard.
//
// In any case, pp->priority+100 should get us back to what the kernel
// has for p->prio.
//
// Test results with the "yes" program on a 2.6.x kernel:
//
// # ps -C19,_20 -o pri,opri,intpri,priority,ni,pcpu,pid,comm
// PRI PRI PRI PRI  NI %CPU  PID COMMAND
//   0  99  99  39  19 10.6 8686 19
//  34  65  65   5 -20 94.7 8687 _20
//
// Grrr. So the UNIX standard "PRI" must NOT be from "pri".
// Either of the others will do. We use "opri" for this.
// (and use "pri" when the "-c" option is used)
// Probably we should have Linux-specific "pri_for_l" and "pri_for_lc"
//
// sched_get_priority_min.2 says the Linux static priority is
// 1..99 for RT and 0 for other... maybe 100 is kernel-only?
//
// A nice range would be -99..0 for RT and 1..40 for normal,
// which is pp->priority+1. (3-digit max, positive is normal,
// negative or 0 is RT, and meets the standard for PRI)
//


https://gitlab.com/procps-ng/procps/-/blob/master/ps/output.c#L590

ps(1) 为了兼容各种 UNIX 标准及其实现,包含了多个调度优先级的取值方法(pri, opri, intpri, priority)。PRI 默认取自 opri 变量,如果加了 -c 参数,则取自 pri 变量。总的来说,在 Linux 平台,其实取 priority 变量,即 /proc/[pid]/stat 中的第 18 列 priority 原始值应该是更好的,符合 Linux 调度优先级本意,也与 top(1) 一致,即:

[root@VM-0-11-tlinux ~]# ps -e -o 'priority,nice,cmd'
PRI NI CMD
20 0 /usr/lib/systemd/systemd --system --deserialize 17
20 0 [kthreadd]
0 -20 [kworker/0:0H]
0 -20 [mm_percpu_wq]
20 0 [ksoftirqd/0]
20 0 [rcu_sched]
20 0 [rcu_bh]
-100 - [migration/0]

重命名本地 git 仓库,master -> main

pull 某个许久未同步的 git 仓库时,fetch 成功,但是最终报了如下错误:

$ git pull
Your configuration specifies to merge with the ref ‘refs/heads/master’
from the remote, but no such ref was fetched.

查了一会儿发现是上游把 master 分支给重命名成 main 了。于是本地仓库也需要更新:

$ git checkout master
$ git branch -m master main
$ git fetch
$ git branch –unset-upstream
$ git branch -u origin/main
$ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main

Google Cloud Platform 的一点点体验

因为自己想搭个 wireguard 服务器在 HK,去 GCP 启动了一个 VM 实例,结果今天发现似乎不得不把它删掉,总结 GCP 使用感想如下:

  1. 居然连实例重装系统都不支持,只能删掉另起一个
  2. 我使用了一个 CentOS 8 的实例,执行一次 yum update 结果 SSH 都挂了,看了下日志,应该是升级 google 相关软件包导致的
  3. SSH 挂掉后,我想通过串口登陆进系统,串口登陆居然是灰的,默认不让从串口登陆。
  4. 于是我以为是 VM 里面可能没起串口,给 reset 了,结果就起不来
  5. 我只能求助伟大的 Google 搜索,发现,GCP 的串口登陆需要设置 metadata。(这是什么奇葩东西?)
  6. 于是我设置了 metadata,终于可以打开串口了,发现实例没起来是因为 SELinux 不知道为什么被开启了。但我有九成的把握,就是升级 google 相关软件包导致
  7. 我想进 GRUB,改内核启动参数,然而发现,GCP 默认把 GRUB 菜单显示也给关了,美其名曰“快速启动”。就不能给一秒钟时间吗?

想了想,没什么办法可以救得回这台实例了。

虽然上面没有我什么重要的东西,但我总结起来,GCP 的这个使用经验,简直就是在一直打我耳光,也许我属于不配使用它的那一类人吧。可能这是 Google 那群人根据自己在公司内部的使用方式提供出来的最佳实践,估计都已经把 OS 这层给越来越“虚”化,不需要 Google 员工在意 OS 层面的东西。但外界是否也达到了这种地步?恐怕 GCP 是还活在自己的梦里。

PlayStation 4 Pro

最近买了个美版 PS4 pro 。其实本来打算是买回给老家的一台新买的 4K + HDR 电视机配的,要不然按照国内的内容源缺乏程度, 4K + HDR 就是个摆设而已。

当然先是寄到了自己广州这边,然而玩了几天 The Last Of Us 之后,我有点喜欢这个游戏机了(挖鼻孔)。于是这几天不跑步,不运动,晚上和周末花了一点时间把它通关了。然而看着已经买了的好多个其它正在下载的游戏,更加觉得自己可以重新开始宅了。。。

以前不太理解有些人为什么会话这么多钱买游戏玩,(PC 游戏盗版一大堆在那里呢),然而有了个游戏机后才发现,它的优点——省心(不用为系统配置操心)确实是最大的卖点。作为一个玩具,它能让人纯粹的从中找到乐趣,不用再关心其它事情,这就是最好的了。

如何正确的引导用户设置好的密码

  1. 可以强迫用户输入密码的长度最小为 N 位。
  2. 不要强迫用户必须输入数字、字母、特殊符号的组合。因为过于复杂的密码用户自己都记不住几个,只能重复的使用常用的几个密码组合,或者是写下来在某个地方,结果是被别人偷看、盗走。
  3. 支付密码,只用数字就可以了,不要强迫用户必须输入其它字母或者符号。用户也许不会天天都用你的 app 进行支付,同样,再说一遍,过于复杂的密码很容易忘记。因为这个密码本身已经有登陆密码的保护了,可以做的一个限制是输错 N 次之后,暂时冻结支付或者要求进入恢复支付密码的步骤。
  4. 让你的登录表单对密码管理器友好。有些登录表格会蓄意不让浏览器记住密码,然而实际上,让浏览器自动保存和填写密码是更好的办法,这样用户可以随机生成密码填进去就完事了。而当密码管理器无法记住密码的时候,用户同样也只能从自己脑海里面的常用密码选一个出来使用,最终的结果是导致用户在不同网站用了相同的密码。
  5. 如果用户选择了记住登录状态,就不要动不动隔了一两天没登陆就把用户登录状态取消了。这点在很多 app 上面非常常见,然而,在使用了随机密码的情况下,输入密码其实是个痛苦的过程。同时,这也是个高风险的过程,因为容易被偷看和监听,尤其是国内这么多网站都还没有部署 HTTPS 的情况下。

Windows 的退化

Windows 本来是优秀应用软件的集中地,尤其是以微软自己的应用程序为代表,这些软件基本很少崩溃,响应迅速,性能非常好。

然而到了 modern apps/UWP 时代之后,这一切都在退化。

已经说不清是多少次被 Windows 10 上面的 UWP 应用的闪退、崩溃给弄到吐血了(其中很多都是微软自己的应用)。并且, UWP 的问题不仅仅是闪退,它的性能也远远不如传统的 Windows 应用,比如:它的启动实在太慢。

我完全不知道 UWP 是否是个好的应用平台,不知道是否是开发者的低能导致的问题。然而这些都不重要。Windows 需要的成功,靠这么烂的软件(平台)质量是只能走向死路的。

Chrome vs. Backspace

Hacker News 上面出现了一个讨论(https://news.ycombinator.com/item?id=11729287),是关于 Google Chrome 去除了将 Backspace 键作为回退到上一个页面的快捷键功能。
我很惊讶很多人在回帖里面对 Chrome 开发者的这一决定表示支持,因为:

  1. 我自己是个 backspace 键的重度用户。我尽量都是在用键盘快捷键在导航,除了 backspace,还有 Ctrl+w,f5,f6 。。。没兴趣从以前的 backspace 切换为两只手才能操作的 Ctrl+左方向键。
  2. backspace 并不是很多人说的那么小众的导航键。相反,把它作为回退上页的功能来用的例子非常多,比如在 Windows 平台,File Explorer 里面也是可以用它回退到上一页面的。
  3. Google Chrome 得了 Apple 的病。一直以来我都觉得 Chrome 其实更像是个 Apple 弄出来的浏览器,标榜着自己比用户更懂一切。而我不想被当作傻瓜。

我觉得我还是继续用 Firefox 吧

HEVC/H.265

仔细想了想,最近一年的时间里,对我的生活改善最为明显的技术是——HEVC/H.265 编码的视频。

现阶段唯一的缺陷是硬件解码的支持并不广泛,Intel 也只有从 Skylake 才开始支持 HEVC/H.265 的硬件编码、解码,不过也只是 8-bit 色深的,10-bit 的基本没有效果,仍然只能靠软解码,吃 CPU。就拿手头的 Intel NUC6I5SYH 来说,它的 CPU —— Core i5-6260U 碰到 HEVC 10-bit 的 4K 视频文件,是无法流畅播放的。(这是当然的,其实笔记本的 i7-4700HQ 都没法流畅播放的,基本没试过其它什么场景能把 CPU 负载跑到这么高的。)

不是说一定要看 10-bit 而不是 8-bit 的视频文件,只不过多数能找到的片源都是 10-bit 的了。

Fxxk HHVM

hhvm 大概是我见过的稳定性最差的开源软件之一了,也不知道这项目到底有没有QA的,反正我是碰到过很多次一更新,这破东西就挂了,起不来