本章介绍用于扩展记帐的 C 接口,包含以下主题:
项目和任务用于标记和分隔工作负荷。扩展记帐子系统用于监视系统中正在运行的工作负荷的资源占用情况。扩展记帐将生成工作负荷任务和进程的记帐记录。
有关扩展记帐和扩展记帐管理过程示例的概述,请参见《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 4 章 “扩展记帐(概述)”和《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 5 章 “管理扩展记帐(任务)”。
扩展记帐 API 包含用于执行以下操作的函数:
exacct 系统调用
对 exacct 文件执行的操作
对 exacct 对象执行的操作
杂项操作
|
|
|
下表列出了与扩展记帐子系统交互的系统调用。
表 3–1 扩展记帐系统调用
函数 |
说明 |
---|---|
使具有权限的进程能够使用特定于进程的其他数据来标记记帐记录 |
|
使具有权限的进程能够从当前执行任务和进程的内核中请求扩展记帐缓冲区 |
|
请求内核为指定的任务或进程写入资源使用情况的数据 |
以下函数提供对 exacct 文件的访问:
表 3–2 exacct 文件函数
函数 |
说明 |
---|---|
打开 exacct 文件。 |
|
关闭 exacct 文件。 |
|
首次对一组对象使用此函数会将数据读入 ea_object_t 结构。随后对该组使用此函数则会循环处理该组中的对象。 |
|
将指定的对象附加到打开的 exacct 文件中。 |
|
将基本字段(eo_catalog 和 eo_type)读入 ea_object_t 结构中,并反绕到记录头。 |
|
在 exacct 文件中往回跳一个对象,并将基本字段(eo_catalog 和 eo_type)读入 ea_object_t 中。 |
|
获取在其上创建 exacct 文件的主机名。 |
|
确定 exacct 文件的创建者。 |
以下函数用于访问 exacct 对象:
|
|
|
|
|
|
|
表 3–3 exacct 对象函数
函数 |
说明 |
---|---|
指定 exacct 对象并设置值。 |
|
设置一组 exacct 对象的值。 |
|
检查 exacct 对象的掩码,以了解该对象是否具有特定目录标记。 |
|
将 exacct 对象附加到指定的 exacct 对象中。 |
|
将 exacct 对象链作为指定组的成员项进行附加。 |
|
在指定的 exacct 对象中释放 value 字段。 |
|
释放指定的 exacct 对象以及任何附加的对象分层结构。 |
以下函数与杂项操作相关联:
本节提供访问 exacct 文件的代码示例。
... ea_object_t *scratch; int unpk_flag = EUP_ALLOC; /* use the same allocation flag */ /* for unpack and free */ /* Omit return value checking, to keep code samples short */ bsize = getacct(P_PID, pid, NULL, 0); buf = malloc(bsize); /* Retrieve exacct object and unpack */ getacct(P_PID, pid, buf, bsize); ea_unpack_object(&scratch, unpk_flag, buf, bsize); /* Display the exacct record */ disp_obj(scratch); if (scratch->eo_type == EO_GROUP) { disp_group(scratch); } ea_free_object(scratch, unpk_flag); ...
本示例评估了内核生成并显示了描述此 make 任务要生成的那部分源代码树的字符串。显示正在生成的且在按源目录的分析中有帮助的源代码部分。
本示例的要点包括以下内容:
要聚合 make(可以包括许多进程)的时间,可以将每个 make 作为任务来启动。make 子进程是作为不同的任务来创建的。要跨越 makefile 树进行聚合,必须确定父子任务关系。
将包含此信息的标记添加到任务的 exacct 文件中。添加描述此 make 任务要生成的那部分源代码树的当前工作目录字符串。
ea_set_item(&cwd, EXT_STRING | EXC_LOCAL | MY_CWD, cwdbuf, strlen(cwdbuf));
... /* Omit return value checking and error processing */ /* to keep code sample short */ ptid = gettaskid(); /* Save "parent" task-id */ tid = settaskid(getprojid(), TASK_NORMAL); /* Create new task */ /* Set data for item objects ptskid and cwd */ ea_set_item(&ptskid, EXT_UINT32 | EXC_LOCAL | MY_PTID, &ptid, 0); ea_set_item(&cwd, EXT_STRING | EXC_LOCAL | MY_CWD, cwdbuf, strlen(cwdbuf)); /* Set grp object and attach ptskid and cwd to grp */ ea_set_group(&grp, EXT_GROUP | EXC_LOCAL | EXD_GROUP_HEADER); ea_attach_to_group(&grp, &ptskid); ea_attach_to_group(&grp, &cwd); /* Pack the object and put it back into the accounting stream */ ea_buflen = ea_pack_object(&grp, ea_buf, sizeof(ea_buf)); putacct(P_TASKID, tid, ea_buf, ea_buflen, EP_EXACCT_OBJECT); /* Memory management: free memory allocate in ea_set_item */ ea_free_item(&cwd, EUP_ALLOC); ...
本示例显示如何读取并显示进程或任务的系统 exacct 文件。
本示例的要点包括以下内容:
调用 ea_get_object() 以获取该文件中的下一个对象。调用 ea_get_object(),循环遍历 exacct 文件,直到遇见 EOF。
catalog_name() 使用 catalog_item 结构将 Solaris 目录的类型 ID 转换为有意义的字符串,该字符串描述了该对象数据的内容。该类型 ID 是通过屏蔽最低的 24 位(即 3 个字节)获取的。
switch(o->eo_catalog & EXT_TYPE_MASK) { case EXT_UINT8: printf(" 8: %u", o->eo_item.ei_uint8); break; case EXT_UINT16: ... }
TYPE_MASK 的前 4 位用于查找列显该对象的实际数据的数据类型。
disp_group() 将使用指向组对象的指针及该组中的对象个数作为其参数。对于组中的每个对象,disp_group() 将调用 disp_obj() 并递归调用 disp_group()(如果该对象是组对象)。
/* Omit return value checking and error processing */ /* to keep code sample short */ main(int argc, char *argv) { ea_file_t ef; ea_object_t scratch; char *fname; fname = argv[1]; ea_open(&ef, fname, NULL, EO_NO_VALID_HDR, O_RDONLY, 0); bzero(&scratch, sizeof (ea_object_t)); while (ea_get_object(&ef, &scratch) != -1) { disp_obj(&scratch); if (scratch.eo_type == EO_GROUP) disp_group(&ef, scratch.eo_group.eg_nobjs); bzero(&scratch, sizeof (ea_object_t)); } ea_close(&ef); } struct catalog_item { /* convert Solaris catalog's type ID */ /* to a meaningful string */ int type; char *name; } catalog[] = { { EXD_VERSION, "version\t" }, ... { EXD_PROC_PID, " pid\t" }, ... }; static char * catalog_name(int type) { int i = 0; while (catalog[i].type != EXD_NONE) { if (catalog[i].type == type) return (catalog[i].name); else i++; } return ("unknown\t"); } static void disp_obj(ea_object_t *o) { printf("%s\t", catalog_name(o->eo_catalog & 0xffffff)); switch(o->eo_catalog & EXT_TYPE_MASK) { case EXT_UINT8: printf(" 8: %u", o->eo_item.ei_uint8); break; case EXT_UINT16: ... } static void disp_group(ea_file_t *ef, uint_t nobjs) { for (i = 0; i < nobjs; i++) { ea_get_object(ef, &scratch)); disp_obj(&scratch); if (scratch.eo_type == EO_GROUP) disp_group(ef, scratch.eo_group.eg_nobjs); } }