内置变量
bpftrace 的内置变量是其强大功能的基石,它们能让你在脚本中轻松获取事件触发时的上下文信息。
| 进程/线程信息 |
pid |
当前进程ID。用于过滤特定进程的事件。 |
|
tid |
当前线程ID。用于进行更精细的线程级分析。 |
|
comm |
当前进程名(最多16个字符)。常用于按进程名进行统计和过滤。 |
|
uid |
当前用户ID。用于分析特定用户的操作。 |
| 时间信息 |
nsecs |
自系统启动以来的纳秒级时间戳。常用于计算函数耗时、事件间隔等。 |
| CPU/系统信息 |
cpu |
当前事件发生时所在的CPU处理器ID。 |
|
curtask |
当前进程的内核task_struct结构体地址(以64位无符号整数表示),用于高级内核调试。 |
| 探针上下文信息 |
arg0, arg1, … argN |
Kprobe/Uprobe 的参数。用于获取被探测函数的参数值(注意:Tracepoint 不可用)。 |
|
args |
Tracepoint 的参数结构体。用于通过 args->field_name的方式访问 Tracepoint 的特定字段。 |
|
retval |
Kretprobe/Uretprobe 的返回值。用于获取被探测函数的返回值。 |
|
func |
当前触发的 Kprobe/Uprobe 所探测的函数名。 |
|
kstack/ ustack |
当前时刻的内核栈或用户栈描述。用于分析代码执行路径,定位性能瓶颈 |
例子
计算函数执行时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| # 测量 vfs_read 函数的执行时间(微秒) ~ » bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid]/ { $duration_us = (nsecs - @start[tid]) / 1000; @us = hist($duration_us); delete(@start[tid]); }' Attaching 2 probes... ^C
@start[551]: 84374532046638 @start[323672]: 84374600291711 @us: [0] 45 |@@@@@ | [1] 452 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| [2, 4) 264 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | [4, 8) 338 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | [8, 16) 43 |@@@@ | [16, 32) 25 |@@ | [32, 64) 4 | | [64, 128) 0 | | [128, 256) 0 | | [256, 512) 0 | | [512, 1K) 6 | | [1K, 2K) 0 | | [2K, 4K) 3 | | [4K, 8K) 1 | |
|
追踪特定进程的系统调用
1 2 3 4 5 6 7 8 9 10 11 12
| ~ » bpftrace -e 'tracepoint:syscalls:sys_enter_openat /comm == "top"/ { printf("PID %d is opening: %s\n", pid, str(args->filename)); }' Attaching 1 probe... PID 323556 is opening: /proc/uptime PID 323556 is opening: /proc PID 323556 is opening: /proc/uptime PID 323556 is opening: /proc/1/stat PID 323556 is opening: /proc/1/statm PID 323556 is opening: /proc/2/stat PID 323556 is opening: /proc/2/statm PID 323556 is opening: /proc/7/stat
|
分析内核调用路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| // 统计 ip_output 函数的调用栈,这里要注意,@[kstack]的key记录的是两条不同的调用链 ~ » bpftrace -e 'kprobe:ip_output { @[kstack] = count(); }' Attaching 1 probe... ^C
@[ ip_output+5 __ip_queue_xmit+400 ip_queue_xmit+25 __tcp_transmit_skb+2666 __tcp_send_ack.part.0+198 tcp_send_ack+32 __tcp_ack_snd_check+66 tcp_rcv_established+660 tcp_v4_do_rcv+362 tcp_v4_rcv+3671 ip_protocol_deliver_rcu+55 ip_local_deliver_finish+138 ip_local_deliver+115 ip_sublist_rcv_finish+137 ip_sublist_rcv+410 ip_list_rcv+314 __netif_receive_skb_list_core+639 netif_receive_skb_list_internal+463 napi_complete_done+126 netvsc_poll+1451 __napi_poll+49 net_rx_action+680 handle_softirqs+244 __irq_exit_rcu+120 irq_exit_rcu+18 sysvec_hyperv_callback+180 asm_sysvec_hyperv_callback+31 pv_native_safe_halt+15 arch_cpu_idle+13 default_idle_call+46 do_idle+517 cpu_startup_entry+49 rest_init+218 arch_call_rest_init+18 start_kernel+1241 x86_64_start_reservations+37 __pfx_reserve_bios_regions+0 secondary_startup_64_no_verify+381 ]: 3 @[ ip_output+5 __ip_queue_xmit+400 ip_queue_xmit+25 __tcp_transmit_skb+2666 __tcp_send_ack.part.0+198 tcp_send_ack+32 __tcp_ack_snd_check+66 tcp_rcv_established+660 tcp_v4_do_rcv+362 tcp_v4_rcv+3671 ip_protocol_deliver_rcu+55 ip_local_deliver_finish+138 ip_local_deliver+115 ip_sublist_rcv_finish+137 ip_sublist_rcv+410 ip_list_rcv+314 __netif_receive_skb_list_core+639 netif_receive_skb_list_internal+463 napi_complete_done+126 netvsc_poll+1451 __napi_poll+49 net_rx_action+680 handle_softirqs+244 __irq_exit_rcu+120 irq_exit_rcu+18 sysvec_hyperv_callback+180 asm_sysvec_hyperv_callback+31 pv_native_safe_halt+15 arch_cpu_idle+13 default_idle_call+46 do_idle+517 cpu_startup_entry+49 start_secondary+281 secondary_startup_64_no_verify+381 ]: 8
|

其他说明
- argX与 args的区别:arg0, arg1…用于 kprobe/uprobe,它们是简单的整数参数。而 args是一个结构体,专用于 tracepoint,需要通过 args->字段名来访问其成员。
- 查看 Tracepoint 参数:你可以使用 bpftrace -lv tracepoint:name命令来查看某个 tracepoint 有哪些参数可用。例如,要查看 write系统调用的参数,可以执行:
1 2 3 4 5 6
| ~ » bpftrace -lv tracepoint:syscalls:sys_enter_write tracepoint:syscalls:sys_enter_write int __syscall_nr unsigned int fd const char * buf size_t count
|