• BCC源码内容概览(2)


    接前一篇文章:BCC源码内容概览(1)

    本文参考官网中的Contents部分的介绍。

    BCC源码根目录的文件,其中一些是同时包含C和Python的单个文件,另一些是.c和.py的成对文件,还有一些是目录。

    跟踪(Tracing)

    examples目录下的文件:

    • examples/tracing/nodejs_http_server.py

    使用USDT探测跟踪Node.js HTTP服务器请求。

    bcc/examples/tracing/nodejs_http_server_example.txt文件内容如下:

    1. # ./nodejs_http_server.py 24728
    2. TIME(s) COMM PID ARGS
    3. 24653324.561322998 node 24728 path:/index.html
    4. 24653335.343401998 node 24728 path:/images/welcome.png
    5. 24653340.510164998 node 24728 path:/images/favicon.png
    • examples/tracing/stacksnoop

    跟踪内核函数并打印所有内核堆栈跟踪。

    bcc/examples/tracing/stacksnoop_example.txt文件内容如下:

    1. Demonstrations of stacksnoop, the Linux eBPF/bcc version.
    2. This program traces the given kernel function and prints the kernel stack trace
    3. for every call. This tool is useful for studying low frequency kernel functions,
    4. to see how they were invoked. For example, tracing the submit_bio() call:
    5. # ./stacksnoop submit_bio
    6. TIME(s) SYSCALL
    7. 3592.838736000 submit_bio
    8. submit_bio
    9. submit_bh
    10. jbd2_journal_commit_transaction
    11. kjournald2
    12. kthread
    13. ret_from_fork
    14. This shows that submit_bio() was called by submit_bh(), which was called
    15. by jbd2_journal_commit_transaction(), and so on.
    16. For high frequency functions, see stackcount, which summarizes in-kernel for
    17. efficiency. If you don't know if your function is low or high frequency, try
    18. funccount.
    19. The -v option includes more fields, including the on-CPU process (COMM and PID):
    20. # ./stacksnoop -v submit_bio
    21. TIME(s) COMM PID CPU SYSCALL
    22. 3734.855027000 jbd2/dm-0-8 313 0 submit_bio
    23. submit_bio
    24. submit_bh
    25. jbd2_journal_commit_transaction
    26. kjournald2
    27. kthread
    28. ret_from_fork
    29. This identifies the application issuing the sync syscall: the jbd2 process
    30. (COMM column).
    31. Here's another example, showing the path to second_overflow() and on-CPU
    32. process:
    33. # ./stacksnoop -v second_overflow
    34. TIME(s) COMM PID CPU SYSCALL
    35. 3837.526433000 0 1 second_overflow
    36. second_overflow
    37. tick_do_update_jiffies64
    38. tick_irq_enter
    39. irq_enter
    40. smp_apic_timer_interrupt
    41. apic_timer_interrupt
    42. default_idle
    43. arch_cpu_idle
    44. default_idle_call
    45. cpu_startup_entry
    46. start_secondary
    47. 3838.526953000 0 1 second_overflow
    48. second_overflow
    49. tick_do_update_jiffies64
    50. tick_irq_enter
    51. irq_enter
    52. smp_apic_timer_interrupt
    53. apic_timer_interrupt
    54. default_idle
    55. arch_cpu_idle
    56. default_idle_call
    57. cpu_startup_entry
    58. start_secondary
    59. This fires every second (see TIME(s)), and is from tick_do_update_jiffies64().
    60. USAGE message:
    61. # ./stacksnoop -h
    62. usage: stacksnoop [-h] [-p PID] [-s] [-v] function
    63. Trace and print kernel stack traces for a kernel function
    64. positional arguments:
    65. function kernel function name
    66. optional arguments:
    67. -h, --help show this help message and exit
    68. -p PID, --pid PID trace this PID only
    69. -s, --offset show address offsets
    70. -v, --verbose print more fields
    71. examples:
    72. ./stacksnoop ext4_sync_fs # print kernel stack traces for ext4_sync_fs
    73. ./stacksnoop -s ext4_sync_fs # ... also show symbol offsets
    74. ./stacksnoop -v ext4_sync_fs # ... show extra columns
    75. ./stacksnoop -p 185 ext4_sync_fs # ... only when PID 185 is on-CPU
    • tools/statsnoop

    跟踪stat()系统调用。

    bcc/tools/statsnoop.py文件内容如下:

    1. #!/usr/bin/env python
    2. # @lint-avoid-python-3-compatibility-imports
    3. #
    4. # statsnoop Trace stat() syscalls.
    5. # For Linux, uses BCC, eBPF. Embedded C.
    6. #
    7. # USAGE: statsnoop [-h] [-t] [-x] [-p PID]
    8. #
    9. # Copyright 2016 Netflix, Inc.
    10. # Licensed under the Apache License, Version 2.0 (the "License")
    11. #
    12. # 08-Feb-2016 Brendan Gregg Created this.
    13. # 17-Feb-2016 Allan McAleavy updated for BPF_PERF_OUTPUT
    14. # 29-Nov-2022 Rocky Xing Added stat() variants.
    15. from __future__ import print_function
    16. from bcc import BPF
    17. import argparse
    18. # arguments
    19. examples = """examples:
    20. ./statsnoop # trace all stat() syscalls
    21. ./statsnoop -t # include timestamps
    22. ./statsnoop -x # only show failed stats
    23. ./statsnoop -p 181 # only trace PID 181
    24. """
    25. parser = argparse.ArgumentParser(
    26. description="Trace stat() syscalls",
    27. formatter_class=argparse.RawDescriptionHelpFormatter,
    28. epilog=examples)
    29. parser.add_argument("-t", "--timestamp", action="store_true",
    30. help="include timestamp on output")
    31. parser.add_argument("-x", "--failed", action="store_true",
    32. help="only show failed stats")
    33. parser.add_argument("-p", "--pid",
    34. help="trace this PID only")
    35. parser.add_argument("--ebpf", action="store_true",
    36. help=argparse.SUPPRESS)
    37. args = parser.parse_args()
    38. debug = 0
    39. # define BPF program
    40. bpf_text = """
    41. #include
    42. #include
    43. #include
    44. struct val_t {
    45. const char *fname;
    46. };
    47. struct data_t {
    48. u32 pid;
    49. u64 ts_ns;
    50. int ret;
    51. char comm[TASK_COMM_LEN];
    52. char fname[NAME_MAX];
    53. };
    54. BPF_HASH(infotmp, u32, struct val_t);
    55. BPF_PERF_OUTPUT(events);
    56. static int trace_entry(struct pt_regs *ctx, const char __user *filename)
    57. {
    58. struct val_t val = {};
    59. u64 pid_tgid = bpf_get_current_pid_tgid();
    60. u32 pid = pid_tgid >> 32;
    61. u32 tid = (u32)pid_tgid;
    62. FILTER
    63. val.fname = filename;
    64. infotmp.update(&tid, &val);
    65. return 0;
    66. };
    67. int syscall__stat_entry(struct pt_regs *ctx, const char __user *filename)
    68. {
    69. return trace_entry(ctx, filename);
    70. }
    71. int syscall__statx_entry(struct pt_regs *ctx, int dfd, const char __user *filename)
    72. {
    73. return trace_entry(ctx, filename);
    74. }
    75. int trace_return(struct pt_regs *ctx)
    76. {
    77. u64 pid_tgid = bpf_get_current_pid_tgid();
    78. u32 tid = (u32)pid_tgid;
    79. struct val_t *valp;
    80. valp = infotmp.lookup(&tid);
    81. if (valp == 0) {
    82. // missed entry
    83. return 0;
    84. }
    85. struct data_t data = {.pid = pid_tgid >> 32};
    86. bpf_probe_read_user(&data.fname, sizeof(data.fname), (void *)valp->fname);
    87. bpf_get_current_comm(&data.comm, sizeof(data.comm));
    88. data.ts_ns = bpf_ktime_get_ns();
    89. data.ret = PT_REGS_RC(ctx);
    90. events.perf_submit(ctx, &data, sizeof(data));
    91. infotmp.delete(&tid);
    92. return 0;
    93. }
    94. """
    95. if args.pid:
    96. bpf_text = bpf_text.replace('FILTER',
    97. 'if (pid != %s) { return 0; }' % args.pid)
    98. else:
    99. bpf_text = bpf_text.replace('FILTER', '')
    100. if debug or args.ebpf:
    101. print(bpf_text)
    102. if args.ebpf:
    103. exit()
    104. # initialize BPF
    105. b = BPF(text=bpf_text)
    106. # for POSIX compliance, all architectures implement these
    107. # system calls but the name of the actual entry point may
    108. # be different for which we must check if the entry points
    109. # actually exist before attaching the probes
    110. def try_attach_syscall_probes(syscall):
    111. syscall_fnname = b.get_syscall_fnname(syscall)
    112. if BPF.ksymname(syscall_fnname) != -1:
    113. if syscall in ["statx", "fstatat64", "newfstatat"]:
    114. b.attach_kprobe(event=syscall_fnname, fn_name="syscall__statx_entry")
    115. else:
    116. b.attach_kprobe(event=syscall_fnname, fn_name="syscall__stat_entry")
    117. b.attach_kretprobe(event=syscall_fnname, fn_name="trace_return")
    118. try_attach_syscall_probes("stat")
    119. try_attach_syscall_probes("statx")
    120. try_attach_syscall_probes("statfs")
    121. try_attach_syscall_probes("newstat")
    122. try_attach_syscall_probes("newlstat")
    123. try_attach_syscall_probes("fstatat64")
    124. try_attach_syscall_probes("newfstatat")
    125. start_ts = 0
    126. prev_ts = 0
    127. delta = 0
    128. # header
    129. if args.timestamp:
    130. print("%-14s" % ("TIME(s)"), end="")
    131. print("%-7s %-16s %4s %3s %s" % ("PID", "COMM", "FD", "ERR", "PATH"))
    132. # process event
    133. def print_event(cpu, data, size):
    134. event = b["events"].event(data)
    135. global start_ts
    136. global prev_ts
    137. global delta
    138. global cont
    139. # split return value into FD and errno columns
    140. if event.ret >= 0:
    141. if args.failed:
    142. return
    143. fd_s = event.ret
    144. err = 0
    145. else:
    146. fd_s = -1
    147. err = - event.ret
    148. if start_ts == 0:
    149. start_ts = event.ts_ns
    150. if args.timestamp:
    151. print("%-14.9f" % (float(event.ts_ns - start_ts) / 1000000000), end="")
    152. print("%-7d %-16s %4d %3d %s" % (event.pid,
    153. event.comm.decode('utf-8', 'replace'), fd_s, err,
    154. event.fname.decode('utf-8', 'replace')))
    155. # loop with callback to print_event
    156. b["events"].open_perf_buffer(print_event, page_cnt=64)
    157. while 1:
    158. try:
    159. b.perf_buffer_poll()
    160. except KeyboardInterrupt:
    161. exit()

  • 相关阅读:
    基於RISC-V QEMU 仿真運行Linux 系統環境搭建
    我从技术到产品经理的几点体会
    [python知识巩固]内建函数reversed()
    跨境电商收款账号一样会关联吗?谁能告诉?
    PHP 获取类对象的信息
    MySQL的安装与配置
    真正“搞”懂HTTPS协议17之TLS握手
    equals与==的区别
    【探索AI】Sora - 探索AI视频模型的无限可能
    【数据结构】堆的实现&堆排序&Top-K
  • 原文地址:https://blog.csdn.net/phmatthaus/article/details/133133187