Windyland 内核崩坏

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