Linux内核动态跟踪—SYstemTap
2009-12-04 16:49
197 查看
导读 :Sloaris中的Dtrace技术曾获《华尔街杂志》2 006技术创新大奖中的金奖。在2005年底,Sun在清华大学举办了Sloaris技术讲座,其中的Dtrace技术,让人耳目一新,它让技术人员摆脱了苦苦阅读静态源代码的日子。那时就期盼,这一技术什么时候出现在Linux内核中。 M. Tim Jones又给我们带来了新的文章,他介绍了Linux内核中类似于Dtrace的技术-SystemTap。在对系统性能追逐的当下,了解并掌握此项技术,不论是对于深入Linux内核内部,还是调试内核和性能调优,无疑都是有帮助的。------------------------------------------------------------------------------------------------------------------------------------------------------------
|
M. Tim Jones, 自由作家 2009 年 12 月 03 日 现代的操作系统内核提供自检 功能,即动态地检查内核以理解其行为的能力。这些行为可以反映内核问题和性能瓶颈。拥有这些信息时候,您就可以调优或修改内核以避免出现故障。本文探索一个名为 SystemTap 的开放源码基础设施,它为 Linux® 内核提供这种动态的自检。 SystemTap 是监控和跟踪运行中的 Linux 内核的操作的动态方法。这句话的关键词是动态,因为 SystemTap 没有使用工具构建一个特殊的内核,而是允许您在运行时动态地安装该工具。它通过一个名为Kprobes 的应用编程接口(API)来实现该目的,本文将探索这个 API。我们首先了解以前的一些内核跟踪方法,然后在深入探讨 SystemTap 的架构及其使用。 内核跟踪 SystemTap 与一种名为 DTrace 的老技术相似,该技术源于 Sun Solaris 操作系统。在 DTrace 中,开发人员可以用 D 编程语言( C语言的子集,但修改为支持跟踪行为)编写脚本。DTrace 脚本包含许多探针和相关联的操作,这些操作在探针 “触发” 时发生。例如,探针可以表示简单的系统调用,也可以表示更加复杂的交互,比如执行特定的代码行。清单 1 显示了 DTrace 脚本的一个简单例子,它计算每个进程发出的系统调用的数量(注意,使用字典将计数和进程关联起来)。该脚本的格式包含探针(在发出系统调用时触发)和操作(对应的操作脚本)。 清单 1. 计算每个进程的系统调用的简单 DTrace 脚本
Distribution License (CDDL) 之下发行的,并且被移植到 FreeBSD 操作系统中。 另一个非常有用的内核跟踪工具是 ProbeVue,它是 IBM 为 IBM® AIX® 操作系统 6.1 开发的。您可以使用 ProbeVue 探查系统的行为和性能,以及提供特定进程的详细信息。这个工具使用一个标准的内核以动态的方式进行跟踪。清单 2 显示了 ProbeVue 脚本的一个例子,它指出发出 sync系统调用的特定进程。 清单 2. 指出哪个进程调用 sync 的简单 ProbeVue 脚本
操作系统策划一个实现该功能的开源项目是势不可挡的。SystemTap 从 2005 年开始开发,它提供与 DTrace 和 ProbeVue 类似的功能。许多社区还进一步完善了它,包括 Red Hat、Intel、Hitachi 和 IBM 等。 这些解决方案在功能上都是类似的,在触发探针时使用探针和相关联的操作脚本。现在,我们看一下 SystemTap 的安装,然后探索它的架构和使用。 您可能仅需一个 SystemTap 安装就可以支持 SystemTap,具体情况取决于您的分发版和内核。对于其他情况,需要使用一个调试内核映像。这个小节介绍在 Ubuntu version 8.10 (Intrepid Ibex) 上安装 SystemTap 的步骤,但这并不是一个具有代表性的 SystemTap 安装。在 参考资料 部分中,您可以找到在其他分发版和版本上安装 SystemTap 的更多信息。 对大部分用户而言,安装 SystemTap 都非常简单。对于 Ubuntu,使用 apt-get:
8.10,需要使用一个调试内核映像。应该使用 apt-get获取包 linux-image-debug-generic就可以获得它的。但这里不能直接使用 apt-get,因此您可以下载该包并使用 dpkg 安装它。您可以下载通用的调用映像包并按照以下的方式安装它:
源代码轻松解决。查看 参考资料 获得如何更新运行时 time.c 文件的信息。 如果您使用定制的内核,则需要确保启用内核选项 CONFIG_RELAY、 CONFIG_DEBUG_FS、 CONFIG_DEBUG_INFO 和 CONFIG_KPROBES。 让我们深入探索 SystemTap 的某些细节,理解它如何在运行的内核中提供动态探针。您还将看到 SystemTap 是如何工作的,从构建进程脚本到在运行的内核中激活脚本。 动态地检查内核 SystemTap 用于检查运行的内核的两种方法是 Kprobes 和 返回探针。但是理解任何内核的最关键要素是内核的映射,它提供符号信息(比如函数、变量以及它们的地址)。有了内核映射之后,就可以解决任何符号的地址,以及更改探针的行为。 Kprobes 从 2.6.9 版本开始就添加到主流的 Linux 内核中,并且为探测内核提供一般性服务。它提供一些不同的服务,但最重要的两种服务是 Kprobe 和 Kretprobe。Kprobe 特定于架构,它在需要检查的指令的第一个字节中插入一个断点指令。当调用该指令时,将执行针对探针的特定处理函数。执行完成之后,接着执行原始的指令(从断点开始)。 Kretprobes 有所不同,它操作调用函数的返回结果。注意,因为一个函数可能有多个返回点,所以听起来事情有些复杂。不过,它实际使用一种称为 trampoline 的简单技术。您将向函数条目添加一小段代码,而不是检查函数中的每个返回点。这段代码使用 trampoline 地址替换堆栈上的返回地址 —— Kretprobe 地址。当该函数存在时,它没有返回到调用方,而是调用 Kretprobe(执行它的功能),然后从 Kretprobe 返回到实际的调用方。 SystemTap 的流程 图 1 展示了 SystemTap 的基本流程,涉及到 3 个交互实用程序和 5 个阶段。该流程首先从 SystemTap 脚本开始。您使用 stap实用程序将 stap 脚本转换成提供探针行为的内核模块。stap 流程从将脚本转换成解析树开始 (pass 1)。然后使用细化(elaboration)步骤 (pass 2) 中关于当前运行的内核的符号信息解析符号。接下来,转换流程将解析树转换成 C源代码 (pass 3) 并使用解析后的信息和 tapset 脚本(SystemTap 定义的库,包含有用的功能)。stap 的最后步骤是构造使用本地内核模块构建进程的内核模块 (pass 4)。 图 1. SystemTap 流程 有了可用的内核模块之后, stap完成了自己的任务,并将控制权交给其他两个实用程序 SystemTap: staprun和 stapio。这两个实用程序协调工作,负责将模块安装到内核中并将输出发送到 stdout (pass 5)。如果在 shell 中按组合键 Ctrl-C 或脚本退出,将执行清除进程,这将导致卸载模块并退出所有相关的实用程序。 SystemTap 的一个有趣特性是缓存脚本转换的能力。如果安装后的脚本没有更改,您可以使用现有的模块,而不是重新构建模块。图 2 显示了 user-space 和 kernel-space 元素以及基于 stap 的转换流程。 图 2. 从 kernel/user-space 角度了解 SystemTap 流程 在 SystemTap 中编写脚本非常简单,但也很灵活,有许多您需要使用的选项。参考资料 提供一个详述语言和可行性的手册的链接,但这个小节仅讨论一些例子,让您初步了解 SystemTap 脚本。 探针 SystemTap 脚本由探针和在触发探针时需要执行的代码块组成。探针有许多预定义模式,表 1 列出了其中的一部分。这个表列举了几种探针类型,包括调用内核函数和从内核函数返回。 表 1. 探针模式例子
sys_sync时触发。当该探针触发时,您希望计算调用的次数,并发送这个计数以及表示调用进程 ID(PID)的信息。首先,声明一个任何探针都可以使用的全局值(全局名称空间对所有探针都是通用的),然后将它初始化为 0。其次,定义您的探针,它是一个探测内核函数 sys_sync的条目。与探针相关联的脚本将递增 count 变量,然后发出一条消息,该消息定义调用的次数和当前调用的 PID。注意,这个例子与 C 语言中的探针非常相似(探针定义语法除外),如果具有 C语言背景将非常有帮助。 清单 3. 一个简单的探针和脚本
变量和类型 SystemTap 允许定义多种类型的变量,但类型是从上下文推断得出的,因此不需要使用类型声明。在 SystemTap 中,您可以找到数字(64 位签名的整数)、整数(64 位)、字符串和字面量(字符串或整数)。您还可以使用关联数组和统计数据(我们稍后讨论)。 表达式 SystemTap 提供 C 语言中常用的所有必要操作符,并且用法也是一样的。您还可以找到算术操作符、二进制操作符、赋值操作符和指针废弃。您还看到从 C 语言带来的简化,其中包括字符串连接、关联数组元素和合并操作符。 语言元素 在探针内部,SystemTap 提供一组类似于 C一样易于使用的语句。注意,尽管该语言允许您开发复杂的脚本,但每个探针只能执行 1000 条语句(这个数量是可配置的)。表 2 列出了一小部分语句作为例子。注意,在这里的许多元素和 C 中的一样,尽管有一些附加的东西是特定于 SystemTap 的。 表 2. SystemTap 的语言元素
C语言中不存在的。 最后,SystemTap 提供许多内部函数,这些函数提供关于当前上下文的额外信息。例如,您可以使用 caller() 识别当前的调用函数,使用 cpu()识别当前的处理器号码,以及使用 pid()返回 PID。SystemTap 还提供许多其他函数,提供对调用堆栈和当前注册表的访问。 在简单介绍了 SystemTap 的要点之后,我们接下来通过一些简单的例子来了解 SystemTap 的工作原理。本文还展示了该脚本语言的一些有趣方面,比如聚合。 系统调用监控 前一个小节探索了一个监控 sync 系统调用的简单脚本。现在,我们查看一个更加具有代表性的脚本,它可以监控所有系统调用并收集与它们相关的额外信息。 清单 4 显示的简单脚本包含一个全局变量定义和 3 个独立的探针。在首次加载脚本时调用第一个探针( begin 探针)。在这个探针中,您可以发出一条表示脚本在内核中运行的文本消息。接下来是一个 syscall探针。注意这里使用的通配符 ( *),它告诉 SystemTap 监控所有匹配的系统调用。当该探针触发时,将为特定的 PID 和进程名增加一个关联数组元素。最后一个探针是 timer 探针。这个探针在 10,000 毫秒(10 秒)之后触发。与这个探针相关联的脚本将发送收集到的数据(遍历每个关联数组成员)。当遍历了所有成员之后,将调用 exit 调用,这导致卸载模块和退出所有相关的 SystemTap 进程。 清单 4. 监控所有系统调用 (profile.stp)
清单 5. profile.stp 脚本的输出
在这个例子中,您稍微修改了上一个脚本,让它收集一个进程的系统调用数据。此外,除了仅捕捉计数之外,还捕捉针对目标进程的特定系统调用。清单 6 显示了该脚本。 这个例子根据特定的进程进行了测试(在本例中为 syslog 守护进程),然后更改关联数组以将系统调用名映射到计数数据。 清单 6. 新系统调用监控脚本 (syslog_profile.stp)
清单 7. 新脚本的 SystemTap 输出 (syslog_profile.stp)
聚合实例时捕捉数字值的统计数据的出色方法。当您捕捉大量数据时,这个方法非常高效有用。在这个例子中,您收集关于网络包接收和发送的数据。清单 8 定义两个新的探针来捕捉网络 I/O。每个探针捕捉特定网络设备名、PID 和进程名的包长度。在用户按 Ctrl-C 调用的 end 探针提供发送捕获的数据的方式。在本例中,您将遍历 recv聚合的内容、为每个元组(设备名、PID 和进程名)相加包的长度,然后发出该数据。注意,这里使用提取器来相加元组: @count提取器获取捕获到的长度(包计数)。您还可以使用 @sum提取器来执行相加操作,分别使用 @min或 @max 来收集最短或最长的程度,以及使用 @avg来计算平均值。 清单 8. 收集网络包长度数据 (net.stp)
清单 9. net.stp 的输出
最后一个例子展示 SystemTap 用其他形式呈现数据有多么简单 —— 在本例中以柱状图的形式显示数据。返回到是一个例子中,将数据捕获到一个名为 histogram 的聚合中(见清单 10)。然后,使用 netdev 接收和发送探针以捕捉包长度数据。当探针结束时,您将使用 @hist_log提取器以柱状图的形式呈现数据。 清单 10. 步骤和呈现柱状图数据 (nethist.stp)
ping 来生成网络流量。 @hist_log提取器是一个以 2 为底数的对数柱状图(如下所示)。还可以步骤其他柱状图,从而使您能够定义 bucket 的大小。 清单 11. nethist.stp 的柱状图输出
本文仅探索了 SystemTap 的最简单的功能。在 参考资料 部分中,您可以找到许多教程、例子和语言参考的链接,这些资源提供了解 SystemTap 所需的所有详细信息。SystemTap 使用几个现有的方法并借鉴了以前的内核跟踪实现。尽管该工具还在紧张开发当中,但它现在已经可以使用。请期待未来出现的新特性。 参考资料 学习 查看 SystemTap 项目的 Web 站点 了解最新的信息,包括当前的版本、文档和链接,以及如何参与 SystemTap 项目。SystemTap 使用 Kprobes 作为将探针安装到运行的内核中的底层方法。在 Sourceware Web 站点上更多地了解 Kprobes。 IBM Redpaper “SystemTap: Instrumenting the Linux Kernel for Analyzing Performance and Functional Problems” 提供关于如何使用 SystemTap 的更多信息。 针对 IBM 系统上的 Linux 的 IBM Blueprint 显示了如何在 Red Hat Enterprise Linux and SUSE Linux Enterprise Server 上 安装和使用 SystemTap。另一个 Blueprint 讨论如何使用 SystemTap GUI,这是一个基于 Eclipse 的工具,它简化了 SystemTap 脚本的编写和内核事件的可视化。 了解如何 为 Ubuntu 8.10 修改 SystemTap,以改正运行时的 time.c 文件中的 bug。 论文 “Dynamic Instrumentation of Production Systems” 来自 2004 USENIX,它介绍了 DTrace 工具,由来自 Sun Microsystems 的作者发表。 architecture paper from 2005 介绍了 SystemTap 架构和设计格式。从本文中可以了解 SystemTap 背后的动机和需求。除了提供大量关于 SystemTap 的技术细节之外,本文还是设计文档的出色模型。 这份在 2006 Ottawa Linux 研讨会总结得出的 Kprobes 教程 简明扼要地介绍了使用 Kprobes 探测内核。您还可以阅读有趣的文章 “使用 Kprobes 调试内核”(developerWorks,2004 年 8 月)。 在这个题为 “Dynamic Tracing and Performance Analysis Using SystemTap” 的演示中,来自 Intel 的 Josh Stone 提供一份关于 SystemTap 的出色教程。这个演示相当全面地介绍了 SystemTap 及其语言和使用。 SystemTap Language Reference 是了解 SystemTap 及其所有功能的优秀资源。 Wikipedia 提供大量关于 SystemTap、DTrace 和 ProbeVue 的有用资源。您还可以找到关于这些技术的演示和教程的外部链接。 在 developerWorks Linux 专区 寻找为 Linux 开发人员(包括 Linux 新手入门)准备的更多参考资料,查阅我们 最受欢迎的文章和教程。 在 developerWorks 上查阅所有 Linux 技巧 和 Linux 教程。 随时关注 developerWorks 技术活动和网络广播。 获得产品和技术 使用可直接从 developerWorks 下载的 IBM 产品评估试用版软件 构建您的下一个开发项目。 讨论 在 SystemTap Blueprints Community Forum 上讨论 SystemTap 和 SystemTap GUI。 加入 developerWorks 社区;您可以通过个人信息和定制主页获得自己感兴趣的 developerWorks 文章,并与其他 developerWorks 用户进行交流。 关于作者
|
相关文章推荐
- Linux内核跟踪之ring buffer的实现
- 【移动安全】Android App Smail代码动态跟踪调试方法
- 基于opencV的动态背景下运动目标检测及跟踪(修改版)
- Linux内核跟踪之ring buffer的实现
- Linux内核跟踪之trace框架分析
- 动态视频目标检测和跟踪技术
- TLD动态跟踪系统中的学习策略—P-N Learning
- 浅谈Linux内核动态模块的编译
- Linux内核分析之三——使用gdb跟踪调试内核从start_kernel到init进程启动
- opencv动态目标跟踪学习总结
- Linux内核支持动态获取IP地址
- Solaris上使用DTrace进行动态跟踪
- Linux内核分析:实验五--使用GDB跟踪系统调用执行过程
- 笔记 动态图像目标跟踪算法研究
- 运动检测与跟踪之动态背景的更新
- 如何用调试器动态跟踪PostgreSQL?
- Linux内核访问外设I/O资源的方式-动态映射(ioremap)与静态映射(map_desc)方式
- TLD动态跟踪系统中的学习策略—P-N Learning
- Java动态跟踪工具(不需要重启服务)——Btrace
- Linux内核分析 - 网络[十七]:NetFilter之连接跟踪