问:假定我使用 "processA",它在某一时刻创建了 "processB",然后 processB 调用 hotfunc()。我感兴趣的是如何跟踪 processB 中 hotfunc() 发出的所有 libc 函数调用。 我在下面说明了我是如何尝试完成上述操作的,但问题是有没有什么更简便的方法(后面的问题以粗体显示): 答:我们最近添加了一些新的 dtrace(1M) 选项以简化上述任务。我在下面介绍了这些选项。将来,基于 s10_63 或更高版本的 SX 内部版本中将包含这些选项。 我必须一直等到产生了 processB,直到那时才能使用 PID 提供程序启动 D 脚本以跟踪 hotfunc() 发出的 libc 调用。我认为可以简化此操作的方法是:创建一个包含 "proc:::exec-success" 探测器的 monitorchild.d 脚本,它可以监视 processA 何时产生 processB。此时,它将带有 stop() 破坏性操作的 SIGSTOP 发送到 processA。此后,我手动运行第二个脚本:tracehotfunc.d `pgrep processA`。因此,我现在获得了正确的 PID。 DTrace 显示错误消息:"dtrace: failed to compile script tracehotfunc.d: line 8: libc.so is not a valid library name"(dtrace:无法编译脚本 tracehotfunc.d:第 8 行:libc.so 不是有效的库名称)。 我运行了 mdb -p `pgrep processB`,然后 " ::objects" 显示以下输出:
BASE LIMIT SIZE NAME
10000 10e000 fe000 a.out
ff3c0000 ff3ea000 2a000 ld.so.1
因此,我估计“过早地”运行了脚本:PID 已存在,但 ld.so 没有足够的时间来加载对象,因此第二个 D 脚本无法正常运行。我随后运行了 "truss -t \!all -U a.out:main -p `pgrep processB`"。由于此时加载了库,因此,我可以运行 tracehotfunc.d 和 "prun pidB"。我可以跟踪 hotfunc(),但是它为什么第一次无法正常运行的原因并非显而易见。另外,仅当我明确地将 libc 放在探测器名称中时,才会出现错误(libc 不是有效的库名称)。 您说的没错,它在进程生命周期中确实“太早了”,因而无法分析 libc。在使用 DTrace pid 提供程序时,我们抓取了您所分析的进程,并检查其符号表以确定放置相应分析的位置。在上面的 mdb -p 输出中,您可以看到在进程的用户端生命周期中很早就停止了进程,此时进程仍具有动态链接程序处理依赖关系。因此,甚至还没有将 libc 映射到地址空间中。正如您所发现的一样,您需要一直等到调用 main() 之前,以确保映射了所有库。我们已添加了一些新选项以简化此操作。 我首先尝试编写一个通用的 "pid$1:::entry" 以便跟踪 hotfunc() 发出的所有调用。该脚本可以正常运行,但没有报告 hotfunc() 发出的所有调用。我感到十分困惑,直到后来才了解它没有报告任何内容的原因。 有什么更简便的方法来执行此操作吗?简而言之,类似于 "truss -f" 的命令,但使用 PID 提供程序来跟踪用户级别的函数。 在最新版本的 DTrace(它将是下一个 Solaris Express 版本和 S10 最终版本的一部分)中,我们已添加了 dtrace(1M) 选项 -c 和 -p,它们用于创建和运行命令以及抓取特定进程。它们也为进一步改进用户端跟踪奠定了基础。特别是 -c 选项,它允许将命令一直运行到动态链接程序完成其操作时为止,然后停止该命令,接下来按照与手动操作完全相同的方式激活分析。我们还添加了新的 $target 宏变量,它可以扩展为所创建的进程或使用 -p 抓取的进程的进程 ID 以简化所执行的操作。因此,您可以使用 date(1) 命令跟踪 libc 中的每个函数调用,如下所示:
CPU ID FUNCTION:NAME 0 36039 libc_init:entry 930373 0 34168 atexit:entry 930373 0 35697 lmalloc:entry 930373 0 35696 getbucketnum:entry 930373 0 35695 initial_allocation:entry 930373 0 36220 mmap:entry 930373 0 36302 __getcontext:entry 930373 0 35697 lmalloc:entry 930373 0 35696 getbucketnum:entry 930373 0 36206 getrlimit:entry 930373 0 36203 getpid:entry 930373 0 35697 lmalloc:entry 930373 0 35696 getbucketnum:entry 930373 ... 0 33969 exit:entry 930373 ... 0 36364 _fini:entry 930373 0 36040 libc_fini:entry 930373 ... 0 35953 mutex_unlock:entry 930373 # 请密切关注 Solaris Express 以获取该版本。 问:DTrace 不能在 Solaris 8 环境中正常运行吗? 答:DTrace 只能在 Solaris 10 中运行,现在可通过 Solaris Express 下载程序获取该工具。但是,可通过在 Solaris 10 中运行应用程序并使用 DTrace 来查找应用程序中的问题,对应用程序进行改进,然后将应用程序放回到 Solaris 8 生产环境中,以利用改进后的应用程序中的相应功能。 问: 有没有涵盖更多读者(如仍在学习 Solaris 的系统管理员和开发者)的计划? 答:有。目前,我们正在编写 SunEd 教程,在 Solaris 10 面向公众发行的时候即会推出该教程。我们还打算最终提供一个针对不同领域的高级教程;但是,得等到我们从最初的 DTrace 教程中积累了一些经验后,才会着手编写这些教程。 感谢您开发出了 DTrace! 我们很高兴它能对您有所帮助! 问:使用特定于应用程序的样例脚本的效果会比较好。比如说,Apache Web 服务器。因此,如果 apache 实例运行速度缓慢,我就会从这些样例脚本入手。 答:是的,的确如此。现在,确实可以使用 DTrace 了解特定于应用程序的问题,但是,最有用的脚本几乎总是要求对一些实现知识进行编码。 我们正在通过添加 DTrace 扩展来解决这一问题,这些扩展允许应用程序导出具有语义稳定性的探测器。因此,就像我们目前使用的比较稳定的 "io"、"proc" 和 "sched" 提供程序一样,我们希望有一天能够开发出某种稳定的 "apache" 提供程序,以便提供与管理 Apache 的那些探测器具有语义相关性的探测器。(最终是由 Apache 开发者来决定如何定义和维护这些探测器,因此,我们不应将注意力放在提供程序本身上,而应放在用于开发提供程序的技术上。)并且,这些提供程序的文档中不再提供其样例脚本... 问:在观察用户堆栈帧时,如何将 C++ 名称解码? 答:到目前为止,我们还没有内置的解码功能;我们正在着手添加这项功能。可通过使用随 Sun C++ 编译器提供的 "dem" 实用程序或随 GCC 提供的 "gc++filt" 实用程序,手动对内容进行解码。 问:有没有关于如何将 DTrace 用于 Java 应用程序的示例或帮助? 能否使用 DTrace 调试 Java 应用程序并在 JVM 内部进行查看? 答:到目前为止,可观察的主要 Java 内容是 DTrace jstack() 操作(如果是 Java 进程,则为 ustack() 的别名);如果进程是 "Tiger" JVM(最新版本),该操作将捕获 Java 源代码级别的堆栈跟踪。也可以使用常规的 DTrace 探测器,将 Java 活动与底层系统活动相关联,如 i/o 和调度等。 问:要在非全局区域中运行 Dtrace,需要进行什么特殊设置吗?现在,如果我在非全局区域中以超级用户身份运行 dtrace -l,将会显示以下消息:"dtrace: failed to initialize dtrace: DTrace not available in local zone"(dtrace:无法初始化 dtrace:DTrace 在本地区域中不可用)。而在全局区域中运行 dtrace -l 时,则会返回一个非常冗长的列表。我是在 s10__63 上运行此命令的。 答:目前,无法从本地(非全局)区域中使用 DTrace。我们正在着手实现这一功能,但在 Solaris 10 操作系统的第一个发行版中不会提供此功能(以后,我们可能会在更新发行版中添加这一功能)。 但是,您可以在全局区域中使用 DTrace 来跟踪其他区域中的活动。还可以使用 DTrace 的 'zonename' 变量在引起活动的区域上执行谓词、聚合或任何其他操作。 问:编写应用程序时,是否必须使用某种特殊资源以使应用程序能够生成其自身的探测器,或者仅使用已安装到内核或驱动程序中的探测器? 答:要使用 DTrace 的 pid 提供程序跟踪应用程序或库,您不必对它们进行任何修改,甚至不必重新编译二进制文件。您可能需要进行的唯一调整是,确保不要将符号表分离。pid 提供程序可用于跟踪每个函数的进入和返回,以及位于任何函数偏移位置的任何指令,但前提是存在函数的符号表条目。 如果要在代码中的某些位置包含显式探测器,或者要在代码中的多个不同位置激活单个稳定的探测器,则可以使用用户端静态定义的 (User Land Statically Defined, USDT) 跟踪来嵌入探测器。当前 Solaris Express 发行版中未提供该功能,但计划在 Solaris 10 操作系统的最终发行版中提供这一功能。 在内核模块方面,您可以跟踪所有内核模块中大多数函数的进入和返回(对某些内核函数进行分析可能是不安全的)。在此我重申一遍,您不必重新编译二进制文件。 |
BigAdmin SubscriptionsBigAdmin Areas
BigAdmin Sun Center
BigAdmin Topics | |||||