频道直达 - 专题 - 新闻 - 技巧 - 组网 - 开发 - 安全 - web编程 - 图像 - 操作系统 - 数据库 - 教育 - 旅游 - 健康 - 时尚 - 驱动 - 软件 - 游戏 - 多媒体 - ERP - 讨论组

Probevue - AIX6 新的程序员工具

来源:IBMDW 作者:Nigel Griffiths 出处:巧巧读书 2007-12-04 进入讨论组

AIX 从 1990 年就开始提供 Trace 功能

  • 在 AIX 内核中预先构建了挂钩(代码),并且这些挂钩大部分用于捕获内核函数的状态和参数
  • 专为生产使用而设计,但需要注意,其收集信息量过多,可能会降低性能

AIX 6 ProbeVue——包含在当前 AIX 6 Open Beta 版本中,但有功能限制

  • 需要时也可动态添加用户代码
  • 零代码修改
  • 一旦启用,将触发与 C 语言类似的 Vue
  • 专为生产使用而设计,而且几乎没有性能影响
  • 不会转储所有信息
  • 使用脚本确定真正需要的内容或查找错误条件
以上说明基于当前 Open Beta 版本之后的 AIX6 中的 probevue。如果使用以下示例 probevue 脚本出现较大问题,则可能有必要期待 AIX 6 完整版本的推出。

ProbeVue——五种启动方法

可以采用交互方式运行 probevue(对我而言,这工作似乎有点艰难,因为必须键入和重复键入细节!),也可以通过脚本运行 probevue。至少可以采用五种方法,可能开始会让人有些迷惑,那么接下来我们就对各个方法进行说明,以便您决定尝试哪种方法:

  • 1) 和 2) 使用脚本启动 probevue,并将脚本指定为输入参数,或将脚本重定向到命令中,如下所示(这是两种方法):
        probevue myscript.e
        probevue <myscript.e
        

  • 3) 自动启动脚本,并在第一行使用特殊的代码告知 shell 启动 probevue 来处理文件内容
        脚本(在本例中称为 myscript)包括第一行: #!/usr/bin/probevue
        将文件处理为可执行文件:chmod +x myscript
        然后运行脚本:./myscript.e
        

  • 4) 有些脚本需要参数(如 shell 脚本 $1、$2 等)。具体来说,很多需要进程 ID (PID)
        查找进程 ID:# ps -ef | grep find
        使用 PID 参数运行: probevue   myscript   43561
    

  • 5) 直接通过用户程序使用 probevue
        probevue -X progname -A prog-arguments myscript
    

Vue 脚本——基础知识

probevuew 脚本的结构如下(<-- 是注释,即不属于脚本的一部分)

<- optional declaring function prot-type so probevue understands your functionarguments
@@BEGIN
{
...                 <- optional start up code, good for initialisation of variables
}

@@<probe-spec>        <- Probe point specification Tuple (see below)
when <predicate>        <- Optional predicate
{
    statements here;<- Probe actions in C like code
...
}

@@END
{
...                              <- Optional ending code.  Can print out final 
                                 results. Gets runs if you hit Control+C
}

探点(Probe point )规范“Tuple”

首先请注意,Tuple 是有序列表的雅名——我在知道这一点后帮助非常大!
目前有三种类型的 Tuple:

  • 1) 针对用户编写的代码的入口或出口的用户函数跟踪探针(或 uft)
    • 语法: @@uft:PID:*:FunctionName:[entry/exit]
    • 示例:针对函数 foo()(主要可执行文件或库)的入口的探针,PID = 34568
      • @@uft:34568:*:foo:entry
      • 注意“*”是用于下一版本的占位符
  • 2) 系统调用入口/出口探针(或 syscall)
    • 语法: @@syscall:PID:SystemCallName:[entry/exit]
    • 示例:读取系统调用所有进程的出口的探针
      • @@syscall:*:read:exit
  • 3) 间隔探针(以指定的时间间隔触发)
    • 语法: @@interval:*:clock:milliseconds
    • 示例:每 500 毫秒(墙上时钟时间)触发一次的探针
      • @@interval:*:clock:500
在将来的版本中将包含更多的 Tuple。

第一个示例 probevue 脚本

以下是一个非常简单的脚本,此脚本实际上工作并执行一些有意义的工作。

#!/usr/bin/probevue                <-- autorun
@@BEGIN
{
int count, total;                       <-- declare the variables (later probevue 
                                                   versions will not need this)
}

@@syscall:*:read:entry            <-- System call: any process ID, read() function, 
                                                    at start of the function
{
   count++;                             <-- increment the counters
   total++;
}

@@interval:*:clock:1000          <-- once per second (1000 ticks per second)
{
   printf("Number of reads = %d\n", count);
   count=0;
}

@@END                                   <-- After you type Control-C
{
    printf("\nTotal reads = %d\n",total);
}


以下是一些示例输出:
# ./count.e
Number of reads = 0
Number of reads = 1
Number of reads = 0
Number of reads = 0
Number of reads = 2
Number of reads = 0
Number of reads = 5
Number of reads = 269
Number of reads = 0
Number of reads = 0
^C
Total reads = 277

第二个示例包含从函数返回的代码

#!/usr/bin/probevue
@@BEGIN
{
int read(int fd, void *buf, int n);       <-- Declare function so ProbeVue understands it
int bad;
int good;
}
@@syscall:*:read:exit
when(__rv == -1)                         <-- __rv means the return value
{
   bad++;
}
@@syscall:*:read:exit
when(__rv != -1)
{
   good++;
}
@@interval:*:clock:1000                  <-- Once a second output counter
{
   printf("Reads good=%d bad=%d\n",good,bad);
   good=0;
}

以下是上面脚本的一些示例输出,我专门运行了一个程序来生成一些磁盘 I/O。注意:当程序尝试从无效的文件描述符(即未使用 open() 函数初始化文件描述符)进行读取时,将生成不良 I/O:

# ./goodandbad.e
Reads good=0 bad=0
Reads good=55 bad=0
Reads good=0 bad=0
Reads good=0 bad=0
Reads good=57 bad=1
Reads good=0 bad=1
Reads good=0 bad=1
Reads good=55 bad=1
Reads good=0 bad=1
Reads good=1 bad=1
Reads good=55 bad=1
Reads good=40 bad=1
Reads good=1 bad=2
Reads good=55 bad=3
Reads good=1 bad=3
Reads good=0 bad=3
Reads good=56 bad=4

第三个示例监视用户程序

我使用一个小程序生成了很多 CUP 工作。此程序调用了 ncpu,其中包含函数“engine()”,此函数耗尽了 CPU 上的 CPU 时钟周期。以下脚本用于研究此函数的使用情况。注意:此程序已经编译并在运行,并且它包括符号表,probevue 使用此符号表来查找函数入口和出口点(即未剥离)。probevue 脚本包括用于输出所能找到的程序和环境的详细信息的 probevue 函数:

#!/usr/bin/probevue

double engine(int p1, int p2);

@@uft:$1:*:engine:entry
{
     printf("PID=%d TID=%d PPID=%d PGID=%d UID=%d GID=%d InKernel=%d\n", __pid, 
     __tid, __ppid, __pgid, __uid, __euid, __kernelmode);
      printf("ProgName=%s errno=%d\n", __pname, __errno);
       printf("---\n");
      stktrace(GET_USER_TRACE,-1);
      printf("+++\n");
      stktrace(PRINT_SYMBOLS|GET_USER_TRACE,-1);
}

以下是用于运行此脚本的命令及其输出:
# ps -ef | grep ncpu
    root 299106 307250  27 14:02:00  pts/0 15:16 ./ncpu -p1 -z 90
    root 315596 307250   0 16:48:47  pts/0  0:00 grep ncpu
#  ./engine    299106
PID=299106 TID=630919 PPID=307250 PGID=299106 UID=0 GID=0 InKernel=0 
ProgName=ncpu errno=0
---
0x100001dc
0x10000964
0x100010e8
0xd02fd66c
0x20000c80
0x10001160
+++
.__start+0x8c
.main+0x60c
.work+0x1b4
.random+0x2c

第四个示例检查用户程序函数的参数

接下来让我们研究一下名为 engine() 的函数。该函数接受两个参数,第一个是随机生成的 1 到 1,000,000 之间的数字——但我们不确定具体是不是在此范围内。我们将随机数放入四个“桶”中。我们要确定各个桶中的随机数的数量是否大体相等——不是完全相等,但至少相近:

#!/usr/bin/probevue

double engine(int p1, int p2);
int b1, b2, b3, b4;

@@uft:$1:*:engine:entry
{
        tmp = __arg1;
        if( tmp < 250000 ) b1++;
        if( 250000 <= tmp && tmp < 500000 ) b2++;
        if( 500000 <= tmp && tmp < 750000 ) b3++;
        if( tmp  >750000 ) b4++;
}

@@END
{
printf("\nFour bucket results are: %d %d %d %d\n",b1,b2,b3,b4);
}

以下是上述脚本的对应命令和输出:
ps -ef | grep ncpu
    root 299106 307250  27 14:02:00  pts/0 15:16 ./ncpu -p1 -z 90
    root 315596 307250   0 16:48:47  pts/0  0:00 grep ncpu
#  # ./random 299106
[[[Wait 30 seconds here]]]
^C
Four bucket results are: 101524 101262 101454 120657

噢,最后一个桶里中的数量更多一些,但这不是 probevue 的问题!这是我代码中的一个错误。我后来通过一个更为详细的 probevue 脚本发现,有些值大于 1,000,000!Probevue 将实际值添加到“生产”工作负载,而没有中断应用程序,也不对程序进行重新编码/重新编译/重新启动。我想不出其他能够做到这一点的方法。

关于 probevue 的这个早期测试版的最后一点看法

我并没有讨论更为高级的功能,如:

  • 试验性捕获——缓存结果,并稍后在找到要研究的点后提交/丢弃数字
  • 从用户程序读取数据
  • 线程处理
  • 用于更改缺省行为的 probevctrl 命令
对于 AIX 6.1,这是初始版本,我还得知可能会提供扩展用户指南——将是当前手册页的改进。
第一个 AIX6 版本有以下方面值得我们注意:
  • 内核变量仅限于内存中驻留的变量
  • 用户 C 代码函数入口需要符号表
  • 没有 C 预处理器支持
  • WPAR 限制——使用 probevue 时,您的 WPAR 不具有移动性(不能重新加载)。停止 probevue 后,WPAR 就可再次移动了。另外, syscall tuple 必须具有 PID,可从 WPAR 查看 PID(不允许使用“*”)
  • 不支持线程局部字符串
计划在 2008 版中推出更多功能。

URl收藏 http://www.qqread.com/unix/c383942.html进入讨论组讨论。
收藏此文】【 】【打印】【关闭
较早的文章:AIX6 的安全新特性

较新的文章:IBM大型主机拥抱OpenSolaris
相关图文阅读
频道图文推荐
健 康 咨 询
时 尚 咨 询
巧巧读书宗旨
相关专题
讨论组问题推荐
站内各频道最新更新文档
站内最新制作专题
热门关键字导读
Photoshop教 程照片处理 照片制作 PS快捷键 抠图
计 算 机 故 障XP系统修复
艺 术 与 设 计设计 流媒体 设计欣赏 边框
计 算 机 安 全ARP
站内频道文章精选
巧巧电脑频道编辑信箱  告诉我们您想看的专题或文章