Windyland 内核崩坏

内核崩坏

在现在, 研究内核会是一件很有趣的事情.

最近几年周围环境发生了一些戏剧性的变化。 越来越少的开发者被聘用作为职业的内核开发, 这意味着内核开发者也会越来越少。 于此相比, 更多的开发资源被投入到相对更容易得到回报的项目, 比如云计算、手机应用、企业应用、游戏行业等等。 但是研究内核依旧可以使开发者在这些领域得到更深刻和更全面的理解。

首当其冲,云计算领域已经已经如火如荼的今日, Solaris 已经淡出 DataCenter 舞台, 留下的 Linux 和 Windows 已经是万众瞩目的焦点 – 几乎所有公有云平台都支持 Linux, 而且纷纷成为了 Linux 基金会的一分子:Amazon Web Services、Azure、Google Cloud – 无论其作为宿主系统还是虚拟系统,对内核行为的研究都会使云业务的展开备受帮助。 而且在容器全面推行下的今日,容器下的其内核行为更是对同一系统的所有实例都会有相同的影响。 就Linux 容器而言,与其相关的领域不限制于驱动、网络子系统、存储子系统、文件系统、CPU和内存资源、vGPU、FPGA、授权等等。

其次, Windows Phone 已经淡出市场竞争的今日,手机应用的开发非常大程度上依赖于两大操作系统:谷歌推出的Android 和 苹果公司推出的 iOS。前者基于修改版本的Linux,实现原有Linux系统上无法实现的电源管理用户进程间的资源隔离。后者更是对Mac OS X 系统的部分性质的重写,使其在有限的CPU和内存资源的情况下,界面渲染和事件响应速度远超对手, 另外其严格的资源保护和安全限制更是让无数开发者不得不重新审视自己的开发模型。

最后其他应用也是不同程度上依赖内核行为。 比如最近的Spectre 事件导致内核补丁,作为游戏应用,一度使其效能大打折扣。 企业应用更是容易依赖于特定版本的内核, 以保护其实际的行为和预期的行为的一致, 这一点在Redhat和其他企业级Linux供应商的内核的长期支持策略得到了体现。

上游是愚昧和无知的组合

你说你在等上游merge, 那只是一群**

有人说, 到上游的沟通永远是不畅的. 做过大规模项目的人容易体会到, 沟通不畅是一个很好的借口.

有人说, 是patch 不够格. 那最初制定的人的代码水平就够格了?

有人说, 是patch 满足不了维护者的需求. 正解, 维护者都是想方设法维护自己的权威不被挑战, 维护自己”respect”.

我只想说, 别指望其他人维护了几年代码就有所长进, 他们自我提高. 其他人始终只是其他人, 你无法要求他们提高,想要改进代码最后还是要靠自己.

rt. upstream is nothing but protectors of selfish.

写软件难难于上青天 - 续篇

BBH的博客,写软件是很难的, 一语戳中很多程序员的软肋.对此深有体会.

写软件难, 难于上青天, 下面特地补充一些不方便用英语描述的问题.

不明确的问题

写软件是件体力活. 写软件自然少不了和计算机打交道, 学过计算机科学CS 的人都知道这是一门以实践著称的学科, 说白了就是没有严格系统科学体系的学科.

既然理论是不系统, 自然对知识面的广度有更高的要求. 比如修复某个分布式系统追到具体kernel的网络行为, 或者深度学习的算法bug 调到了编译器上 – 领域一大 再牛的人总会遇到自己不知道的东西.

不明朗的需求

按理说一个产品都会有自己的需求决定. 比如定制一个红绿灯, 总会有某个城市成千上万的人去检验它是否合格.

但是很遗憾, 软件产品本身决定了自己不可能和传统一样有固定的需求.

软件产品容易修改. 不同于传统产品的生长设计周期, 软件产品比硬件产品可能容纳更多的动态的需求, 其工程理论也从瀑布式发展到敏捷开放, 即便如今敏捷开放不再是主流, 后面的趋势也是如此. 与此同时使用者也收到其影响, 对软件产品的需求日益趋于不稳定.

软件产品的重用机制收益非常高, 简单地修改就可以满足不同人群的需求. 比如Windows, 其部分核心代码还是三十年前msdos遗留的. 相比硬件产品每次迭代都需要推倒重做, 中间节约的人力和物理成本相当之大.

永恒的问题

在某个调查中显示, 70%以上的成功IT企业的CEO都认为人工智能最后会取代人类.

其实这是不可能的. AI 或者 计算机 其主要的发展逻辑是通过人类书写的程序代替了人类的人工作业. 其本质还是一部分人类(通常被认为是机智的)代替另一些人类的工作.

从逻辑学角度, AI的独立性是无法被自我证明, 就如同定理本身.

从历史学角度, AI的发展取决与人类的发展, 有可能就如同IT取代机械文明一样, 后面还会有新的领域出现取代IT.

从伦理学角度, AI只是多数人的意志以少数人的决定的体现, 人类的社会总究还是在相互影响, 只不过换了一个途径.

从哲学角度, AI只是人类当前时代形而上的意识, 人类的意识对外界的依赖, 如果AI总有一天取代人类, 这一天不能影响人类,也即不能被观测, 对人类本身也是毫无意义的.

从科学角度, AI的存在仍然是有序的电子或者量子效应的叠加, 比自然界中的量子效应的影响力想去甚多, 也许会在某一时刻占上风, 不过不值一提.

从数学角度, AI的理论是不可自证的, 其行为的发生和持续依赖外界因素的干扰.

RDMA 编程速记

RDMA 有 QP (Queue Pair)

RDMA 有 PD (protective domain)

RDMA 有 CQ (Completion Queue)

RDMA 有 msg_mr (Message Manager)

为啥以太网网就没?

别问我,自己看api

man 7 rdma_cm

rdma 的man文档里面有不少关于rdma api 的介绍

客户端

同步api:

异步api:

合并api:

服务端

Message Operation

RDMA 数据结构

下面是在 rdma/rdma_cma.h 中定义的数据结构

  • struct rdma_cm_id
  • struct rdma_conn_param
  • enum rdma_cm_event_type
  • enum rdma_port_space
  • struct rdma_addrinfo
  • struct rdma_route
  • struct rdma_ib_addr

IB Verbs

RDMA Verbs下面就是IB的实现

IB 一共有3种连接方式:

  • Unreliable Datagram (UD)
  • Unreliable Connected (UC)
  • Reliable Connected (RC)

可以在 rdma_create_id 时候指定

IB 一共支持常见的OP Code, 有Send、Recv、RDMA READ、 RDMA Write 还有其它。

OPCODE IBV_QPT_UD IBV_QPT_UC IBV_QPT_RC
IBV_WR_SEND X X X
IBV_WR_SEND_WITH_IMM X X X
IBV_WR_RDMA_WRITE   X X
IBV_WR_RDMA_WRITE_WITH_IMM   X X
IBV_WR_RDMA_READ     X
IBV_WR_ATOMIC_CMP_AND_SWP     X
IBV_WR_ATOMIC_FETCH_AND_ADD     X

IB Device API

IB Polling API

IB 数据结构

下面是在 infiniband/verbs.h 中定义的数据结构

  • struct ibv_device IB Device
  • struct ibv_context: IB Context
  • struct ibv_pd: IB Protection Domain
  • struct ibv_mr: IB MR
  • struct ibv_comp_channel: IB Completion Channel
  • struct ibv_cq: IB Completion Queue
  • struct ibv_srq: IB Shared Completion Queu
  • struct ibv_qp: IB Queue Pair
  • struct ibv_qp_init_attr create qp 需要用到
  • struct ibv_send_wr post send 需要用到
  • struct ibv_recv_wr post recv 需要用到

例子

其它讨论

Dtrace on Mac OS X

引子

最近在看 CppCon 2015 中的 Chandler Carruth 的 Tuning C++ - Benchmarks, and CPUs, and Compiler 的视频。 Chandler Carruth 是 Google 编译器团队的工程师,也是LLVM 项目的核心贡献者之一, 其对X86 平台的经验和分析能力也是很强的。 他提到的新的 Google benchmark库,他在视频中所用的工具 perf 是linux 平台独占的。 这和我日常使用的 OS X 有很大不同。

OS X 上的相关工具

不过 OS X 也有很强的性能分析工具 dtrace。 移植自solaris的 dtrace 无论是性能开销和扩展性上都要强出perf 一截。Xcode 附带的 Instrument 也是基于 dtrace 写成的。那既然如此,为什么不用dtrace 协助自己的日常开发呢?

  • GUI 的 Instruments
  • Command Line 的 dtruss 和 dtrace

Instruments

打开 Xcode 可以在子菜单中选择 Instruments(或者也可以在Spotlight 搜索), 下面有众多的预建的功能,从内存分配到GPU profiling。 Xcode 7.1 中自带有以下功能:

性能相关:

  • Time Profiler (CPU 性能)
  • Counters (CPU 性能)
  • Core Animation (GPU 性能)
  • OpenGL ES Analysis (GPU 性能)
  • GPU Driver (GPU 性能)
  • Activity Monitor(网络和磁盘使用)
  • Network(网络使用)
  • File Activity(磁盘使用)

内存相关:

  • Activity Monitor(内存使用)
  • Allocations (废弃的内存)
  • Leaks (泄漏的内存)
  • Zombies (二次释放的内存)

Energy Usage:

  • Energy Diagnostics
  • Activity Monitor
  • File Activity
  • Time Profiler

其他:

  • Automation
  • Cocoa Layout
  • Core Data
  • Metal System Trace
  • System Traces
  • System Usage

Instrument 是一个非常综合的工具,除了dtrace(io、syscall)以外还有malloc的跟踪、gpu 的分析等。具体的用处也可以通过添加dtrace 脚本来得到扩展。 下面介绍下dtrace 中的常见的命令行工具。

dtruss

日常中用得最多的是dtruss,它可以显示进程的系统调用(下面简称syscall)信息。

用法: dtruss -h

USAGE: dtruss [-acdefholLs] [-t syscall] { -p PID | -n name | command }

          -p PID          # 只检查此PID的进程
          -n name         # 只检查此名称的进程
          -t syscall      # 只检查此syscall
          -a              # 打印所有细节
          -c              # 打印syscall 被调用的次数
          -d              # 打印相对时间(us)
          -e              # 打印逝去时间 (us)
          -f              # 同时跟踪其子进程
          -l              # 每行打印pid/lwpid
          -o              # 打印cpu 时间
          -s              # 打印stack 调用栈
          -L              # 不打印pid/lwpid
          -b bufsize      # 调整缓存大小,默认是4M

注意执行dtruss 需要在dtruss 前面加上sudo, 因为dtrace相关的应用都是要root权限的。

其实这是一个等价于struss的封装脚本,不过基于dtrace 其性能要比struss 高出不少。

类似的工具有:

  • iosnoop 监视进程的IO
  • execsnoop 监视进程的创建(通常是fork)
  • opensnoop 监视文件打开操作
  • errinfo 监视系统调用失败(errno)
  • iotop 监视进程的IO, 类似于iosnoop
  • 还有一些第三方的工具来自 Dtrace book, 比如hfsslower.d, soconnect_mac.d, bitesize.d,maclife.d 也很有用

以上工具和dtruss一样是要求root 权限的。

dtrace

drace 是一个性能开销比较的性能分析工具,目前除了最早的Solaris 系统内置以外,Mac OS X和FreeBSD 以及Oracle Linux 已经有部分的支持。其用法是用D 脚本语言写代码,然后交由内核解释执行,由于其特殊的执行机制,可以保证即使遭遇错误,内核也不会崩溃,而且由其引起的额外开销也异常的小,非常适合用于测试性能。

下面是一行D语言的dtrace 命令。

  • 监视新进程: dtrace -n 'proc:::exec-success { trace(curpsinfo->pr_psargs); }'

  • 监视进程打开的文件: dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'

  • 按执行文件名统计syscall 的次数: dtrace -n 'syscall:::entry { @num[execname] = count(); }'-

  • 按syscall名统计syscall 的次数: dtrace -n 'syscall:::entry { @num[probefunc] = count(); }'

  • 按进程统计syscall 的次数: dtrace -n 'syscall:::entry { @num[pid,execname] = count(); }'

  • 按进程统计读取的字节数: dtrace -n 'sysinfo:::readch { @bytes[execname] = sum(arg0); }'

  • 按进程统计写入的字节数: dtrace -n 'sysinfo:::writech { @bytes[execname] = sum(arg0); }'

  • 按88Hz 统计pid 189的进程的栈: dtrace -n 'profile-99 /pid == 189 && arg1/ { @[ustack()] = count(); }'

Futher Reading