check -leaks [-frames n ] [-match m]
check -memuse [-frames n] [-match m]
check -all [-frames n] [-match m]
check [funcs ] [files ] [loadobjects]
本节讨论了使用 CPU 性能计数器 (CPU Performance Counter, CPC) 时用到的开发者接口。Solaris 应用程序可以独立于底层计数器体系结构来使用 CPC。
本节介绍了 libcpc(3LIB) 库的最新添加内容。有关旧接口的信息,请参见 libcpc 手册页。
准备使用 CPC 工具的应用程序可通过调用 cpc_open() 函数来初始化库。此函数会返回一个供其他接口使用的 cpc_t * 参数。cpc_open() 函数的语法如下:
cpc_t*cpc_open(intver);ver 参数的值用于标识应用程序所使用的接口的版本。如果底层计数器无法访问或不可用,则 cpc_open() 函数将失败。
uint_t cpc_npic(cpc_t *cpc); uint_t cpc_caps(cpc_t *cpc); void cpc_walk_events_all(cpc_t *cpc, void *arg, void (*action)(void *arg, const char *event)); void cpc_walk_events_pic(cpc_t *cpc, uint_t picno, void *arg, void(*action)(void *arg, uint_t picno, const char *event)); void cpc_walk-attrs(cpc_t *cpc, void *arg, void (*action)(void *arg, const char *attr));
cpc_npic() 函数可返回底层处理器上的物理计数器数量。
cpc_caps() 函数可返回 uint_t 参数,此参数的值是基于底层处理器支持的功能执行按位或运算的结果。共有两项功能。CPC_CAP_OVERFLOW_INTERRUPT 功能,允许处理器在计数器溢出时产生中断;CPC_CAP_OVERFLOW_PRECISE 功能,允许处理器确定哪一个计数器产生溢出中断。
内核可维护底层处理器支持的事件的列表。单个芯片上的不同物理计数器不必使用相同的事件列表。cpc_walk_events_all() 函数可针对每个处理器支持的事件调用 action() 例程,而不用考虑物理计数器。cpc_walk_events_pic() 函数可针对特定物理计数器上每个处理器支持的事件调用 action() 例程。这两个函数都会将未解释的 arg 参数从调用者传递到每个 action() 函数调用。
平台可维护底层处理器支持的属性的列表。利用这些属性,可以访问特定于处理器的高级性能计数器功能。cpc_walk_attrs() 函数可针对每个属性名称调用操作例程。
cpc_set_t *cpc_set_create(cpc_t *cpc); int cpc_set_destroy(cpc_t *cpc, cpc_set_t *set); int cpc_set_add_request(cpc_t *cpc, cpc_set_t *set, const char *event, uint64_t preset, uint_t flags, uint_t nattrs, const cpc_attr_t *attrs); int cpc_set_request_preset(cpc_t *cpc, cpc_set_t *set, int index, uint64_t preset);
不透明数据类型 cpc_set_t 表示请求的集合。这些集合称为集。cpc_set_create() 函数可创建一个空集。cpc_set_destroy() 函数可销毁一个集,并释放由该集使用的所有内存。销毁一个集可释放由该集使用的硬件资源。
cpc_set_add_request() 函数可向一个集中添加请求。以下列表介绍了请求所使用的参数。
一个字符串,用于指定要进行计数的事件的名称。
一个 64 位无符号整数,用作计数器的初始值。
应用于一组请求标志的逻辑或运算的结果。
attrs 指向的数组中的属性个数。
指向 cpc_attr_t 结构数组的指针。
以下列表介绍了有效的请求标志。
利用此标志,当 CPU 在用户模式下执行时可对出现的事件进行计数。
通过此标志,可以对 CPU 在特权模式下执行时发生的事件进行计数。
此标志可请求在硬件计数器溢出时发出通知。
CPC 接口可将属性作为 cpc_attr_t 结构数组来进行传递。
cpc_set_add_request() 函数成功返回时,它将返回一个索引。此索引会引用通过调用 cpc_set_add_request() 函数时添加的请求所生成的数据。
cpc_set_request_preset() 函数可更改请求的预设值。通过更改可将新的预设值与溢出集重新绑定在一起。
cpc_walk_requests() 函数可针对 cpc_set_t 中的每个请求调用用户提供的 action() 例程。arg 参数的值会在未进行解释的情况下传递给用户例程。通过 cpc_walk_requests() 函数,应用程序可显示集中每个请求的配置。cpc_walk_requests() 函数的语法如下:
void cpc_walk_requests(cpc_t *cpc, cpc_set_t *set, void *arg, void (*action)(void *arg, int index, const char *event, uint64_t preset, uint_t flags, int nattrs, const cpc_attr_t *attrs));
本节中的接口可将集中的请求绑定到物理硬件,并将计数器设置到起始位置。
int cpc_bind_curlwp(cpc_t *cpc, cpc_set_t *set, uint_t flags); int cpc_bind_pctx(cpc_t *cpc, pctx_t *pctx, id_t id, cpc_set_t *set, uint_t flags); int cpc_bind_cpu(cpc_t *cpc, processorid_t id, cpc_set_t *set, uint_t flags); int cpc_unbind(cpc_t *cpc, cpc_set_t *set);
cpc_bind_curlwp() 函数可将集绑定到调用 LWP。该集的计数器将虚拟化为到此 LWP 上,并计算调用 LWP 运行时 CPU 上发生的事件的数量。cpc_bind_curlwp() 例程唯一的有效标志为 CPC_BIND_LWP_INHERIT。
cpc_bind_pctx() 函数可将集绑定到使用 libpctx(3LIB) 捕获的进程中的 LWP。此函数没有任何有效标志。
cpc_bind_cpu() 函数可将集绑定到在 id 参数中指定的处理器。将集绑定到 CPU 会使系统中的现有性能计数器上下文无效。此函数没有任何有效标志。
cpc_unbind() 函数可停止性能计数器,并释放与绑定集关联的硬件。如果将集绑定到 CPU,则 cpc_unbind() 函数将从该 CPU 解除绑定 LWP 并释放 CPC 伪设备。
利用本节中介绍的接口,可以将数据从计数器返回到应用程序。计数器数据驻留在名为 cpc_buf_t 的不透明数据结构中。此数据结构可用于捕获绑定集正在使用的计数器的状态快照,并且包括以下信息:
每个计数器的 64 位值
最新硬件快照的时间戳
累积 CPU 周期计数器,用于计算处理器针对绑定集使用的 CPU 周期的数量
cpc_buf_t *cpc_buf_create(cpc_t *cpc, cpc_set_t *set); int cpc_buf_destroy(cpc_t *cpc, cpc_buf_t *buf); int cpc_set_sample(cpc_t *cpc, cpc_set_t *set, cpc_buf_t *buf);
cpc_buf_create() 函数可创建一个缓冲区,用来存储 cpc_set_t 所指定的集中的数据。cpc_buf_destroy() 函数可释放与给定 cpc_buf_t 相关联的内存。cpc_buf_sample() 函数可获取正在代表指定集进行计数的计数器的快照。指定集必须已绑定,并且已创建了缓冲区,然后才能调用 cpc_buf_sample() 函数。
对缓冲区抽样不会更新与该集相关联的请求的预设值。如果使用 cpc_buf_sample() 函数对缓冲区进行抽样,然后解除绑定并重新绑定,则会从最初调用 cpc_set_add_request() 函数时该请求的预设值开始计数。
通过以下例程,可访问 cpc_buf_t 结构中的数据。
int cpc_buf_get(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val); int cpc_buf_set(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val); hrtime_t cpc_buf_hrtime(cpc_t *cpc, cpc_buf_t *buf); uint64_t cpc_buf_tick(cpc_t *cpc, cpc_buf_t *buf); int cpc_buf_sub(cpc_t *cpc, cpc_buf_t *result, cpc_buf_t *left cpc_buf_t *right); int cpc_buf_add(cpc_t *cpc, cpc_buf_t *result, cpc_buf_t *left, cpc_buf_t *right); int cpc_buf_copy(cpc_t *cpc, cpc_buf_t *dest, cpc_buf_t *src); void cpc_buf_zero(cpc_t *cpc, cpc_buf_t *buf);
cpc_buf_get() 函数可检索 index 参数所标识的计数器的值。index 参数是指在绑定集之前由 cpc_set_add_request() 函数返回的值。cpc_buf_get() 函数可将计数器的值存储在 val 参数所指示的位置。
cpc_buf_set() 函数可设置 index 参数所标识的计数器的值。index 参数是指在绑定集之前由 cpc_set_add_request() 函数返回的值。cpc_buf_set() 函数可将计数器的值设置为 val 参数所指示的位置处的值。cpc_buf_get() 函数和 cpc_buf_set() 函数均不会更改相应 CPC 请求的预设值。
cpc_buf_hrtime() 函数可返回高精度时间戳,用来指示对硬件抽样的时间。cpc_buf_tick() 函数可返回 LWP 运行时所经过的 CPU 时钟周期数。
cpc_buf_sub() 函数可计算在 left 和 right 参数中指定的计数器与周期值之间的差值。cpc_buf_sub() 函数可将结果存储在 result 中。给定的 cpc_buf_sub() 函数调用中的所有 cpc_buf_t 值都必须源自同一个 cpc_set_t 结构。result 索引包含缓冲区中每个请求索引的 left - right 计算的结果。结果索引还包含 tick 的差。cpc_buf_sub() 函数可用于将目标缓冲区的高精度时间戳设置为 left 或 right 缓冲区的最新时间。
cpc_buf_add() 函数可计算在 left 和 right 参数中指定的计数器和周期值的总和。cpc_buf_add() 函数可将结果存储在 result 中。给定的 cpc_buf_add() 函数调用中的所有 cpc_buf_t 值都必须源自同一个 cpc_set_t 结构。result 索引包含缓冲区中每个请求索引的 left + right 计算的结果。结果索引还包含 tick 的总和。cpc_buf_add() 函数可用于将目标缓冲区的高精度时间戳设置为 left 或 right 缓冲区的最新时间。
使用 cpc_buf_copy() 函数时 dest 与 src 相同。
cpc_buf_zero() 函数可将 buf 中的所有内容都设置为零。
本节介绍了 CPC 的激活接口。
int cpc_enable(cpc_t *cpc); int cpc_disable(cpc_t *cpc);
这两个接口分别用于启用和禁用与正在执行的 LWP 绑定的任何集的计数器。利用这些接口,应用程序可以指定所需的代码,同时使用 libpctx 将计数器配置延迟到某个控制进程。
本节介绍了 CPC 的错误处理接口。
typedef void (cpc_errhndlr_t)(const char *fn, int subcode, const char *fmt, va_list ap); void cpc_seterrhndlr(cpc_t *cpc, cpc_errhndlr_t *errhndlr);
通过这两个接口,可以传递 cpc_t 句柄。除了字符串之外,cpc_errhndlr_t 句柄还采用一个整型子代码。整型 subcode 用于描述 fn 参数所引用的函数遇到的特定错误。通过整型 subcode,应用程序可轻易识别各种错误情况。fmt 参数的字符串值包含对错误子代码的国际化说明,并且适用于显示。