09月08, 2022

bpftrace 入门(4)变量

内置变量

无论 Dynamic tracing 或者 Static tracing,它们的目的都是监听特定函数调用事件,这些函数即可以在内核中,也可以在用户态的应用或者 lib 中。获知这些函数调用时的参数、返回值就已经实现了开发者大半目标。除此之外,bpfstrace 还内置了一些变量,用户访获得探测对象自身信息。这些变量在 bpftrace 中直接访问即可。

  • pid / tid

    Bpftrace 或者说 eBPF 工作在内核,因此这些变量都与内核中进程表示有关。

    先说 tid,内核中线程与进程没做作明确区分,它们都是相同的调度对象 task_sructtid 是 thread id 的缩写,由于历史原因,在 task 中的成员是 task_sruct.pid。所以对于 Linux 内核,线程 = 轻量级进程。

    pid 实际上指的是内核中进程组,由 task 中的 task_sruct.tgid 成员表示。

    也就是说,进程 = 线程组。

  • uid / gid

    执行函数的用户ID、组ID。

  • nsecs

    时间戳,纳秒。

  • elapsed

    ebpfs 启动后的纳秒数。

  • numaid

    NUMA = Non-Uniform Memory Access,与多核 CPU 的内存访问相关。

  • cpu

    当前 cpu 编号,从 0 开始。

  • comm

    进程名称,通常为进程可执行文件名。

  • kstack

    内核栈。

  • ustack

    用户栈。

  • arg0, arg1, ..., argN

    函数参数。

  • sarg0, sarg1, ..., sargN.

    函数参数(栈中)。

  • retval

    返回值。

  • func

    函数名,可以在可执行文件的符号表中这个函数名。

  • probe

    探针的完整名称,也就是 bpftrace 中 形如 'kprobe:do_nanosleep'

  • curtask

    当前 task struct。

  • rand

    一个无符号 32 位随机数。

  • cgroup

    当前进程的 Cgroup,内核资源组,类似 namespace,docker 等虚拟化技术即基于内核提供的这一基础设施。

  • cpid

    子进程 pid,bpftrace 允许通过 -c 指定一个 cmd 运行,然后在该进程上安装 probe。

  • $1, $2, ..., $N, $#.

    bpftrace 程序自身的位置参数

这些内置变量可以在 bpftrace 脚本中直接使用。

变量

bpftrace 不仅能将监测到的函数调用信息 print 出来,更进一步,它提供了存储空间,允许在处理 probe 时保存、累计数据。bpftrace 脚本最终被编译为 Bytecode,由 eBPF VM 执行。

image-20220908233049214.png

不同于传统的 trace 技术仅提供有限的 ring buffer,eBPF 为 VM 提供了无上限的存储 Maps(图中底部中间)。bpftrace 也可以读写 Maps,在多个 probe actions 和 多次事件中保存数据,直到 bpftrace 程序退出或者主动清除。

全局变量 @name

所谓全局有几个方面的意思:

  • 对所有 probe actions 可见;
  • bpftrace 生命周期内可见;

bpftrace 支持两种变量形式:

  • 简单变量,@name = value
  • Map,@name[key] = value

简单变量就是单纯的变量名和值,很容易理解,你可以在脚本中创建任意数量的简单变量。

Map 非常接近 Python 中的 Dict,或者 C 中的数组,但数组索引可以是数字、字符串等。例如借助内置变量 tid 可以为每个线程记录独立的数值。

# example.bt
kprobe:do_nanosleep {
  /*以线程 tid 作为 key,不同线程的 value 不同*/
  @start[tid] = nsecs; 
} 

kretprobe:do_nanosleep /@start[tid] != 0/ {
  printf("slept for %d ms\n", (nsecs - @start[tid]) / 1000000); 
  delete(@start[tid]); 
}

# bpftrace example.bt
Attaching 2 probes...
slept for 1000 ms
slept for 1000 ms
slept for 1000 ms
slept for 1009 ms
slept for 2002 ms

临时变量

$name, 只在当前 action 中有效,超出 action 的 {}不具备记忆能力。

本文链接:http://www.thinkinpython.com/post/bpftrace_tutorial_4.html

-- EOF --