Solaris 动态跟踪指南

结构

D 关键字 structstructure 的缩写,用于引入由一组其他类型组成的新类型。新的结构类型可用作 D 变量和数组的类型,从而使您可以采用单一名称定义相关变量组。D 结构与 C 和 C++ 中对应的构造相同。如果您采用 Java 编程语言编写程序,可将 D 结构视为只包含数据成员但不包含方法的类。

我们假定您希望在 D 中创建一个较为复杂的系统调用跟踪程序,用于记录与 shell 执行的每个 read(2)write(2) 系统调用有关的多种因素,如已用时间、调用数以及作为参数传递的最大字节计数。您可以编写一条 D 子句,在三个单独的关联数组中记录这些属性,如下例所示:

syscall::read:entry, syscall::write:entry
/pid == 12345/
{
	ts[probefunc] = timestamp;
	calls[probefunc]++;
	maxbytes[probefunc] = arg2 > maxbytes[probefunc] ?
	    arg2 : maxbytes[probefunc];
}

但是,该子句效率很低,因为 DTrace 必须创建三个单独的关联数组,并存储与每个数组的 probefunc 对应的同一元组值的各个副本。相反,可以使用结构来节省空间并使程序易于阅读和维护。首先,在程序源文件顶部声明一个新的结构类型:

struct callinfo {
	uint64_t ts;      /* timestamp of last syscall entry */
	uint64_t elapsed; /* total elapsed time in nanoseconds */
	uint64_t calls;   /* number of calls made */
	size_t maxbytes;  /* maximum byte count argument */
};

struct 关键字后跟一个可选标识符,用于引用现在称为 struct callinfo 的新类型。然后,将结构成员括在一组大括号 { } 中,并使用分号 (; ) 结束整个声明。定义每个结构成员使用的语法与 D 变量声明相同,即首先列出成员类型,然后是命名成员的标识符,以及另一个分号 (;)。

结构声明本身仅定义新类型,而不会创建任何变量或在 DTrace 中分配存储空间。完成声明之后,即可在整个 D 程序的其余部分将 struct callinfo 用作类型,并且每个类型为 struct callinfo 的变量都将存储结构模板描述的四个变量副本。这些成员将根据成员列表按顺序分配内存,并在成员间引入数据对象对齐所必需的填充空间。

您可以通过 "." 运算符编写以下格式的表达式,使用成员标识符名称来访问各成员值:

variable-name.member-name

以下示例为使用新结构类型的改进程序。请转到编辑器并键入以下 D 程序,然后将其保存在名为 rwinfo.d 的文件中:


示例 7–1 rwinfo.d:收集 read(2) 和 write(2) 统计信息

struct callinfo {
	uint64_t ts;      /* timestamp of last syscall entry */
	uint64_t elapsed; /* total elapsed time in nanoseconds */
	uint64_t calls;   /* number of calls made */
	size_t maxbytes;  /* maximum byte count argument */
};

struct callinfo i[string];	/* declare i as an associative array */

syscall::read:entry, syscall::write:entry
/pid == $1/
{
	i[probefunc].ts = timestamp;
	i[probefunc].calls++;
	i[probefunc].maxbytes = arg2 > i[probefunc].maxbytes ?
		arg2 : i[probefunc].maxbytes;
}

syscall::read:return, syscall::write:return
/i[probefunc].ts != 0 && pid == $1/
{
	i[probefunc].elapsed += timestamp - i[probefunc].ts;
}

END
{
	printf("        calls  max bytes  elapsed nsecs\n");
	printf("------  -----  ---------  -------------\n");
	printf("  read  %5d  %9d  %d\n",
	    i["read"].calls, i["read"].maxbytes, i["read"].elapsed);
	printf(" write  %5d  %9d  %d\n",
	    i["write"].calls, i["write"].maxbytes, i["write"].elapsed);
}

键入该程序后,请运行 dtrace -q -s rwinfo.d,指定其中一个 shell 进程。然后在 shell 中键入数条命令,并在完成 shell 命令输入后,在 dtrace 终端按 Ctrl-C 组合键,以触发 END 探测器并列显结果:


# dtrace -q -s rwinfo.d `pgrep -n ksh`
^C
        calls  max bytes  elapsed nsecs
------  -----  ---------  -------------
  read     36       1024  3588283144
 write     35         59  14945541
#