perf_event源码分析(一)——cmd_record

本文详细分析了perf_event工具中的cmd_record功能,主要关注如何生成perf.data文件。内容包括事件配置、内核及模块映射、mmap事件合成、线程和进程映射的记录,为后续的性能分析提供了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cmd_record是perf用户层的一个核心工具,为之后的report, annotate等工具提供profile,监测数据都记录在perf.data中,后面就是进行上层分析,这里对cmd_record()的分析主要是关注perf.data文件内容组成。

parse_events()会根据用户在命令行上的指定来配置监测事件,为每一个事件分配一个perf_evsel结构体,其中记录了事件名称与配置,最后将这个perf_evsel挂在静态全局变量evsel_list的entries链表上。对于每个事件,如果监测x个线程在y个core上运行的信息,就要做x*y个文件描述符,分别对应这个xy个监测信息,所以evsel->fd是xyarray这样类似二维数组结构,讲每个事件的名称、配置记录在perf_trace_event_type events[event_count]数组中,其中event->event_id = evesel->attr.config。

在完成用户指定事件相关操作之后,下面进入__cmd_record()。perf_session_new()函数是关键,它会被record和report分别以写、读方式进行调用,对于record在其中会调用perf_session__create_kernel_maps():(perf_session => machine)

1.        先做一个动态共享目标dso *kernel,kernel->short_name = "[kernel]", kernel->long_name = "[kernel.kallsyms]", kernel->kernel = DSO_TYPE_KERNEL, 读/sys/kernel/notes,将其中的id写入kernel->build_id[20]数组中。最后把这个dso挂到machine->kernel_dsos链表中。<=machine__create_kernel()

2.        从

google-perftools 简介 google-perftools 是款针对 C/C++ 程序的性能分析工具,它是个遵守 BSD 协议的开源项目。使用该工具可以对 CPU 时间片、内存等系统资源的分配和使用进行分析,本文将重点介绍如何进行 CPU 时间片的剖析。 google-perftools 对个程序的 CPU 性能剖析包括以下几个步骤。 1. 编译目标程序,加入对 google-perftools 库的依赖。 2. 运行目标程序,并用某种方式启动 / 终止剖析函数并产生剖析结果。 3. 运行剖结果转换工具,将不可读的结果数据转化成某种格式的文档(例如 pdf,txt,gv 等)。 安装 您可以在 google-perftools 的网站 (http://code.google.com/p/google-perftools/downloads/list) 上下载最新版的安装包。为完成步骤 3 的工作,您还需要个将剖析结果转化为程序员可读文档的工具,例如 gv(http://www.gnu.org/software/gv/)。 编译与运行 您需要在原有的编译选项中加入对 libprofiler.so 的引用,这样在目标程序运行时会加载工具的动态库。例如本例中作者的系统中,libprofiler.so 安装在"/usr/lib"目录下,所以需要在 makefile 文件中的编译选项加入“-L/usr/lib -lprofiler”。 google-perftools 需要在目标代码的开始和结尾点分别调用剖析模块的启动和终止函数,这样在目标程序运行时就可以对这段时间内程序实际占用的 CPU 时间片进行统计和分析。工具的启动和终止可以采用以下两种方式。 a. 使用调试工具 gdb 在程序中手动运行性能工具的启动 / 终止函数。 gdb 是 Linux 上广泛使用的调试工具,它提供了强大的命令行功能,使我们可以在程序运行时插入断点并在断点处执行其他函数。具体的文档请参照 http://www.gnu.org/software/gdb/,本文中将只对用到的几个基本功能进行简单介绍。使用以下几个功能就可以满足我们性能调试的基本需求,具体使用请参见下文示例。 命令 功能 ctrl+c 暂停程序的运行 c 继续程序的运行 b 添加函数断点(参数可以是源代码中的行号或者个函数名) p 打印某个量的值或者执行个函数调用 b. 在目标代码中直接加入性能工具函数的调用,该方法就是在程序代码中直接加入调试函数的调用。 两种方式都需要对目标程序重新编译,加入对性能工具的库依赖。对于前者,他的好处是使用比较灵活,但工具的启动和终止依赖于程序员的手动操作,常常需要些暂停函数(比如休眠 sleep)的支持才能达到控制程序的目的,因此精度可能受到影响。对于后者,它需要对目标代码的进行修改,需要处理函数声明等问题,但得到的结果精度较高,缺点是每次重新设置启动点都需要重新编译,灵活度不高,读者可以根据自己的实际需求采用有效的方式。 示例详解 该程序是个简单的例子,文中有两处耗时的无用操作,并且二者间有定的调用关系。 清单 1. 示例程序 void consumeSomeCPUTime1(int input){ int i = 0; input++; while(i++ < 10000){ i--; i++; i--; i++; } }; void consumeSomeCPUTime2(int input){ input++; consumeSomeCPUTime1(input); int i = 0; while(i++ < 10000){ i--; i++; i--; i++; } }; int stupidComputing(int a, int b){ int i = 0; while( i++ < 10000){ consumeSomeCPUTime1(i); } int j = 0; while(j++ < 5000){ consumeSomeCPUTime2(j); } return a+b; }; int smartComputing(int a, int b){ return a+b; }; void main(){ int i = 0; printf("reached the start point of performance bottle neck\n"); sleep(5); //ProfilerStart("CPUProfile"); while( i++ MyProfile.pdf 转换后产生的结果文档如下图。图中的数字和框体的大小代表了的某个函数的运行时间占整个剖析时间的比例。由代码的逻辑可知,stupidComputing,stupidComputing2 都是费时操作并且它们和 consumeSomeCPUTime 存在着定的调用关系。 图 1. 剖析结果 结束语 本文介绍了个 Linux 平台上的性能剖析工具 google-perftools,并结合实例向读者展示了如何使用该工具配置、使用及分析性能瓶颈。
<think>好的,我现在需要处理用户的问题,关于`trace_tcp_probe(sk, skb);`这个函数的介绍。首先,我得回想下这个函数可能的上下文,因为在Linux内核的网络子系统中,特别是TCP协议的实现部分,有很多跟踪和调试相关的函数。 用户之前问的是关于C语言设置TCP时间戳的问题,现在转向了trace函数,可能是在调试或分析TCP数据包时遇到了问题。我需要确定`trace_tcp_probe`的作用和用途。根据经验,以`trace_`开头的函数通常与内核的跟踪点(tracepoints)有关,可能是用于在TCP事件发生时记录信息,比如发送或接收数据包时的状态变化。 接下来,我需要确认`trace_tcp_probe`是否属于内核的跟踪机制,比如ftrace或perf之类的工具使用的钩子。在Linux内核源码中,TCP相关的跟踪点可能包括`tcp_probe`模块,它用于监控TCP连接的状态和数据传输情况。例如,当数据包被发送或接收时,这个跟踪点会被触发,记录相关信息,如序列号、确认号、时间戳等。 用户可能想知道这个函数的具体功能,如何启用它,以及如何使用它来调试TCP问题。需要解释这个函数在内核中的位置,它属于哪个子系统,以及如何配置内核以启用相关的跟踪功能。此外,可能还需要提到如何通过用户空间的工具(如trace-cmdperf)来捕获和分析这些事件。 还要考虑用户可能的实际应用场景,比如性能调优、网络问题诊断,或者理解TCP协议的行为。需要解释使用`trace_tcp_probe`的好处,比如能够实时监控TCP连接的状态变化,帮助识别重传、窗口调整等问题。 另外,需要检查是否有相关的内核文档或源代码中的注释可以引用,以增强回答的准确性。例如,在Linux内核的`include/trace/events/tcp.h`文件中可能定义了这些跟踪点,以及它们触发的条件和记录的数据。 同时,要提醒用户注意权限问题,因为使用内核跟踪功能通常需要管理员权限,并且可能需要加载特定的内核模块,如`tcp_probe`。还需要说明如何解析输出的跟踪数据,可能需要特定的工具或脚本。 最后,总结这个函数的作用,它在调试中的重要性,以及使用时的注意事项,比如对系统性能的影响,如何减少日志量等。确保回答结构清晰,分点说明,便于用户理解。</think>以下是关于`trace_tcp_probe(sk, skb);`的详细解析: $$ 功能定位 $$ `trace_tcp_probe`是Linux内核中**TCP协议栈的调试跟踪函数**,属于内核的**事件追踪系统(ftrace)**的部分。它主要用于在TCP数据包发送/接收时触发事件,记录关键状态信息。 $$ 典型应用场景 $$ 1. 网络性能分析(如RTT测量) 2. TCP重传机制调试 3. 滑动窗口动态监控 4. 连接状态跟踪(SYN/FIN/RST等标志位变化) $$ 内核实现原理 $$ ```c // 内核源码示例(简化版): // include/trace/events/tcp.h TRACE_EVENT(tcp_probe, TP_PROTO(struct sock *sk, struct sk_buff *skb), TP_ARGS(sk, skb), TP_STRUCT__entry( __field(__u64, sock_cookie) // 套接字唯标识 __field(__u32, saddr) // 源IP __field(__u32, daddr) // 目的IP __field(__u16, sport) // 源端口 __field(__u16, dport) // 目的端口 __field(__u32, seq) // 序列号 __field(__u32, ack_seq) // 确认号 __field(__u8, tcp_flags) // TCP标志位(SYN/ACK等) ), TP_printk(...) // 格式化输出 ); ``` $$ 启用方法 $$ ```bash # 1. 加载tcp_probe模块 sudo modprobe tcp_probe port=80 full=1 # 2. 通过trace-cmd捕获事件 sudo trace-cmd record -e tcp_probe # 3. 查看实时日志(输出示例) sshd-23182 [000] ...1 16188.234567: tcp_probe: src=192.168.1.2:22 dst=10.0.0.3:54321 seq=12345 ack=67890 flags=ACK ``` $$ 关键数据结构 $$ - `struct sock *sk`:包含TCP连接的核心状态: ```c struct sock { u32 sk_saddr; // 源IP u32 sk_daddr; // 目的IP u16 sk_sport; // 源端口 u16 sk_dport; // 目的端口 u32 sk_rcv_nxt; // 期望接收的下个序列号 u32 sk_snd_nxt; // 下个发送序列号 struct tcp_sock *tp; // TCP专用参数 }; ``` - `struct sk_buff *skb`:数据包元信息: ```c struct sk_buff { __u32 seq; // TCP序列号 __u32 end_seq; // 结束序列号 __u8 tcp_flags; // TCP控制标志位 unsigned int len; // 数据长度 }; ``` $$ 数据分析技巧 $$ 1. **RTT计算** 通过连续两个事件的`seq`和`ack_seq`差值计算: $$ RTT = T_{ACK} - T_{DataSend} $$ 2. **重传检测** 当观察到同`seq`值多次出现且`tcp_flags`包含`RTO`标志时: ```bash [tcp_probe] seq=12345 flags=RTO # 重传超时 [tcp_probe] seq=12345 flags=ACK # 原始数据包 ``` 3. **窗口动态分析** 结合`tp->rcv_wnd`和`tp->snd_wnd`字段: ```c struct tcp_sock { u32 rcv_wnd; // 当前接收窗口 u32 snd_wnd; // 当前发送窗口 }; ``` $$ 性能优化建议 $$ 1. 限制跟踪范围避免性能损耗: ```bash # 只监控特定端口 echo port=443 > /sys/kernel/debug/tracing/events/tcp/tcp_probe/filter ``` 2. 使用采样模式减少数据量: ```bash # 每100个事件记录1次 echo 100 > /sys/kernel/debug/tracing/events/tcp/tcp_probe/sampling ``` **典型应用案例**:某云服务商通过分析`tcp_probe`日志,发现客户端频繁触发TCP零窗口(Zero Window),最终定位到接收端应用程序的缓冲区分配策略缺陷,优化后网络吞吐量提升40%。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值