DTracing PHP

admin 2022年5月17日11:27:06评论16 views字数 3501阅读11分40秒阅读模式

Dtrace是一个非常灵活和强大的工具来跟踪和调试应用程序。 这里是一个如何進行Dtracing PHP的教程。

先决条件

您需要一个支持 Dtrace 的操作系统,如Solaris 10,OpenSolaris,Mac OS X 10.5或FreeBSD 7。我在OpenSolaris 2008.11上使用 Dtrace 。您还需要至少dtrace权限或需要是root才能跟踪程序。

介绍DTrace

Dtrace真的很强大,试图介紹它的所有功能是不可能的。因此,我将只关注基础知识,这是我们工作所需要的东西。 Dtrace背后的基本思想是内核和用户程序在内核或用户程序中的特定位置上触发探测器。因为探测器刚刚被触发,如果DTrace正在运行并尝试捕获这些标记,探测器本身不会耗费CPU功率(实际上它们是NOP的)。但是,如果我们跟踪它们,我们能够看到这些探测器,并且他们能够传递一些数据。为了从这些探针中获得更复杂的信息,DTrace有一个内置的脚本语言来捕获这些探针并处理它们。

Dtrace程序结构

DTrace中的每个探测器都由4元组描述。

第一个是提供者(provider)
第二个是模块(module)
第三个是函数名(function)
第四个是名称(name)

元组由分号分隔,因此每个探测器由以下定义:

<probeprovider>:<providermodule>:<probefunc>:<probename>

在我们的示例中,提供程序通常是pid提供程序,它为我们提供给定PID(我们要跟踪的PHP控制器)的探测。该probemodule将是php和probefunc将是底层C函数的函数名称。名称实际上可以是一切,但最好的做法是在函数的入口处有一个探针,在函数返回之前调用entry和return。

DTrace程序具有与探针匹配的探针标识符。每个标识符都有一个主体,它可以包含变量的初始化或使用表的数据的累积。此外,每个标识符可以具有在主体运行之前被评估的条件。

所以我们有以下结构:

<probeprovider>:<providermodule>:<probefunc>:<probename>
/ <condition> /
{
    <body>
}

例如,我们跟踪gc_collect_cylce函数:

pid$target:php:gc_collect_cycle_function:entry
{
    trace(probename);
}

请注意,DTrace具有大量预定义变量,例如probename。请参阅Sun的Dtrace指南以获取预定义变量的列表。

PHP探针

由于PHP不提供自己的探针,我们必须使用底层的C函数。 PHP本身不提供自己的探测器。有由Wez Furlong编写的ext / dtrace,它为PHP提供了一些探测器,但是当我们想要更深入一些时,我们必须使用底层的C函数。用户空间程序通常由所谓的pid-provider跟踪。它用于通过具有给定PID的程序获得所有探测器。与用户态程序不同,内核没有pid,因此内核探测器没有PID,并且可以很容易地被标识为唯一的名称。

由于我们有时不知道我们要跟踪的php进程的PID,有一个称为\$target的变量。如果你使用它,\$ target将自动填充在dtrace启动程序时创建的PID。如果我使用

dtrace -s test.d -c 'php test.php'

启动一个程序,程序php test.php将被执行,并且创建的PID将被分配给变量\$target。 DTrace还有一个选项,只显示可用的探针:尝试

dtrace -ln 'pid$target:php::entry' -c 'php test.php'

以获得所有由PHP调用的函数入口。你可能不时得到一个消息,没有足够的内存可用跟踪。在这些情况下,你只是试图捕获太多的探头。因此,我使用特定的:::条目符号来获取函数条目,这在我的机器上工作得很好。让我们来看看一些有趣的探头。如果我们试图使用

dtrace -ln 'pid$target:php::entry' -c 'php test.php'

来显示所有与PHP相关的探测器。

输出可能开始与类似:

ID PROVIDER MODULE FUNCTION NAME
69608 pid2696 php _start entry
69609 pid2696 php __fsr entry
69610 pid2696 php _free_ereg_cache entry
69611 pid2696 php zm_startup_ereg entry
69612 pid2696 php zm_shutdown_ereg entry
69613 pid2696 php zm_info_ereg entry
69614 pid2696 php zif_ereg entry
69615 pid2696 php zif_eregi entry
69616 pid2696 php php_ereg_replace entry
69617 pid2696 php zif_ereg_replace entry
69618 pid2696 php zif_eregi_replace entry
69619 pid2696 php zif_split entry
69620 pid2696 php zif_spliti entry
69621 pid2696 php zif_sql_regcase entry
69622 pid2696 php php_regcomp entry
69623 pid2696 php p_ere entry
69624 pid2696 php p_ere_exp entry
69625 pid2696 php p_str entry
69626 pid2696 php p_bre entry
69627 pid2696 php p_simp_re entry

第一个例子

所以我们的第一个例子是我们要跟踪编译时间。编译函数在PHP中称为compile_file。因此,我们的探测器标识符将是pid\$target:php:compile_file。 PID提供程序将只获取特定探针的探针,而php probemodule将集中在所有PHP相关函数。然后选择compile_file函数。由内核提供,有两个子名,calle条目和。当函数被输入并且返回时,函数返回时调用入口。因此,我们需要跟踪

pid $ target:php:compile_time:entry
和
pid $ target:php:compile_time:return

我们知道只需要得到信息编译需要多长时间。为此,DTrace定义了一个名为timestamp的变量,该变量可以在DTrace标识符的主体内访问,该标识符保存从程序开始的毫秒。所以知道我们抓住我们的入口探测器并将时间设置为本地值:

pid$target:php:compile_file:entry
{
    self->compile_start = timestamp;
}

请注意,self>符号用于获取每个线程的变量。因此每个线程都有自己的价值。这不是特别需要我们的基于PHP的示例,但最好的做法是尽可能使用线程局部变量。

我们只需要我们的返回探针计算实际偏移:

pid$target:php:compile_file:return
{
    printf("Compile time: %dn", timestamp – self->compile_start);
}

这将输出我们的实际编译时间。只需将标识符及其主体放入“compiletime.d”中,并使用dtrace -q -s compiletime.d -c’php test.php’启动dtrace,它将显示test.php的编译时间。请注意,self> compile_start和timestamp都是整数。 Dtrace实际上没有浮动基元的概念,所以你不能使用printf输出浮点。

输出可能类似于:

$ dtrace -q -s compiletime.d -c 'php test.php'
Compile Time: 99604

高级示例

现在让我们更深入一点引擎。我们现在想要跟踪垃圾收集器何时进入并想要查看释放的引用的数量。垃圾回收器使用函数gc_collect_cycles。

pid$target:php:gc_collect_cycles:return
{
    printf("%d refs freed", arg1);
}

请注意特殊的arg1变量。这总是保持“返回”子集中的返回值。在”entry”中,arg0 … argN将保存函数参数。

有关更详细的示例,请参阅我的下一个博客条目,其中将包含更复杂的DTrace脚本。

FROM : virzz.com | Author:Virink

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月17日11:27:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DTracing PHPhttp://cn-sec.com/archives/1013017.html

发表评论

匿名网友 填写信息