程序调试的利器GDB

无论是多么优秀的程序员,都难以保证自己在编写代码时不会出现任何错误,因此调试是软件开发过程中的一个必不可少的 组成部分。当程序完成编译之后,它很可能无法正常运行,或者会彻底崩溃,或者不能实现预期的功能。此时如何通过调试找到问题的症结所在,就变成了摆在开发 人员面前最严峻的问题。通常说来,软件项目的规模越大,调试起来就会越困难,越需要一个强大而高效的调试器作为后盾。对于Linux程序员来讲,目前可供 使用的调试器非常多,GDB(GNU DeBugger)就是其中较为优秀的。

    初识GDB

GDB 是自由软件基金会(Free Software  Foundation,FSF)的软件工具之一。它的作用是协助程序员找到代码中的错误。如果没有GDB的帮助,程序员要想跟踪代码的执行流程,唯一的办 法就是添加大量的语句来产生特定的输出。但这一手段本身就可能会引入新的错误,从而也就无法对那些导致程序崩溃的错误代码进行分析。GDB的出现减轻了开 发人员的负担,他们可以在程序运行的时候单步跟踪自己的代码,或者通过断点暂时中止程序的执行。此外,他们还能够随时察看变量和内存的当前状态,并监视关 键的数据结构是如何影响代码运行的。

调试方法

如果想对程序进行调试,必须先在用GCC编译源代码时加上-g选项,以便产生GDB所需要的调试符号信息。例如,debugme.c是一个存在错误程序,可以使用如下的命令对其进行编译,同时产生调试符号:
# gcc -g debugme.c -o debugme

如 果愿意的话,还可以在编译时使用“-ggdb”选项来生成更多的调试信息。由于这些调试信息中的相当一部分是GDB所特有的,所以生成的代码将无法在其它 调试器中正常调试。对于大多数情况来说,普通的-g选项就足够了。需要注意的是,GCC虽然允许同时使用-g(调试)和-o(优化)选项,但优化会影响最 终生成的代码,导致程序源代码和二进制代码之间的关系变得复杂起来。如果不想为调试制造障碍,建议不要将-g和-o选项一同使用,并且只在程序彻底调试完 后才开始进行代码优化。这样调试过程将变得相对轻松和愉快。

基本应用

现在可以启动GDB来调试已经生成的可执行程序debugme,命令如下:

    

        

            

        

    

                         

如果一切正常,GDB将被启动并在屏幕上输出版权信息,但如果使用了-q或–quiet选项则不会显示它们。启动GDB时另外一个有用的命令行选项是“-d dirname”,其中dirname是一个目录名。该目录名告诉GDB应该到哪里去寻找源代码。

一 旦出现GDB的命令提示符(gdb),就表明GDB已经准备好接收来自用户的各种调试命令了。如果想在调试环境下运行这个程序,可以使用GDB提供的 “run”命令,而程序在正常运行时所需的各种参数可以作为“run”命令的参数传入,或者使用单独的“set  args”命令进行设置。如果在执行“run”命令时没有给出任何参数,GDB将使用上一次“run”或“set  args”命令指定的参数。如果想取消上次设置的参数,可以执行不带任何参数的“set args”命令。下面尝试在调试器中运行这个程序:

    

        

            

        

    

                         

最后一行输出表明程序在调用动态链接库/lib/ld-linux.so.2中的_dl_fini() 函数时出现了错误,地址是0x4000c6ac。这些对调试是非常重要的线索。另外还有一种信息对调试也很重要,就是错误发生时的函数调用层级关系,可以 通过执行“backtrace”命令来获得。在使用GDB调试命令时,用户可以不必输入完整的命令名称,使用任何惟一的缩写都可以。例如 “backtrace”命令就可以缩写成“back”甚至“bt”。GDB还支持很多常用的Shell命令编辑特征,比如可以像在bash或tcsh中那 样按Tab键补齐命令。如果相关命令不惟一的话,则列出所有可能的匹配项。此外键盘上的方向键可用来翻动历史命令。

GDB是一个源代码级的调试器,使用“list”命令可以查看当前调试对象的源代码。该命令的通用格式为“list [m,n]”,表示显示从m行开始到n行结束的代码段,而不带任何参数的“list”命令将显示最近10行源代码。

设置断点
在 调试有问题的代码时,在某一点停止运行往往很管用。这样程序运行到此外时会暂时挂起,等待用户的进一步输入。GDB允许在几种不同的代码结构上设置断点, 包括行号和函数名等,并且还允许设置条件断点,让程序只有在满足一定的条件时才停止执行。要根据行号设置断点,可以使用“ break  linenum”命令。要根据函数名设置断点,则应该使用“break funcname”命令。

在以上两种情况中,GDB将 在执行指定的行号或进入指定的函数之前停止执行程序。此时可以使用“print”显示变量的值,或者使用“list”查看将要执行的代码。对于由多个源文 件组成的项目,如果想在执行到非当前源文件的某行或某个函数时停止执行,可以使用如下形式的命令:

    

        

            

        

    

                         

条件断点允许当一定条件满足时暂时停止程序的执行。它对于调试来讲非常有用。设置条件断点的正确语法如下:

    

        

            

        

    

                         

其中expr是一个逻辑表达式。当该表达式的值为真时,程序将在该断点处暂时挂起。例如,下面的命令将在debugme程序的第38行设置一个条件断点。当程序运行到该行时,如果count的值等于3,就将暂时停止执行:
(gdb) break 38 if count==3

设置断点是调试程序时最常用到的一种手段。它可以中断程序的运行,给程序员一个单步跟踪的机会。使用命令“ break main”在main函数上设置断点可以在程序启动时就开始进行跟踪。

接 下去使用“continue”命令继续执行程序,直到遇到下一个断点。如果在调试时设置了很多断点,可以随时使用“info  breakpoints”命令来查看设置的断点。此外,开发人员还可以使用“delete”命令删除断点,或者使用“disable”命令来使设置的断点 暂时无效。被设置为无效的断点在需要的时候可以用“enable”命令使其重新生效。

观察变量
GDB 最有用的特性之一是能够显示被调试程序中几乎任何表达式、变量或数组的类型和值,并且能够用编写程序所用的语言打印出任何合法表达式的值。查看数据最简单 的办法是使用“print”命令,只需在“print”命令后面加上变量表达式,就可以打印出此变量表达式的当前值,示例如下:

    

        

            

        

    

                         

从输出信息中可以看出,输入字符串被正确地存储在了字符指针str所指向的内存缓冲区中。除了给出变量 表达式的值外,“print”命令的输出信息中还包含变量标号($1)和对应的内存地址(0x40015360)。变量标号保存着被检查数值的历史记录, 如果此后还想访问这些值,就可以直接使用别名而不用重新输入变量表达式。

如果想知道变量的类型,可以使用“whatis”命令,示例如下:

    

        

            

        

    

                         

对于第一次调试别人的代码,或者面对的是一个异常复杂的系统时,“whatis”命令的作用不容忽视。

单步执行
为了单步跟踪代码,可以使用单步跟踪命令“step”,它每次执行源代码中的一行。

在GDB中可以使用许多方法来简化操作,除了可以将“step”命令简化为“s”之外,还可以直接输入回车键来重复执行前面一条命令。

除了可以用“step”命令来单步运行程序之外,GDB还提供了另外一条单步调试命令“next”。两者功能非常相似,差别在于如果将要被执行的代码行中包含函数调用,使用step命令将跟踪进入函数体内,而使用next命令则不进入函数体内。

在进入下一部分之前,使用下面的命令退出GDB:
(gdb) quit

分析核心(core)文件

在 程序发生崩溃时,有时可能无法直接运行GDB来进行调试。比如程序可能是在另外一台机器上运行的,或者因为程序对时间比较敏感,所以手动跟踪调试会产生无 法接受的延迟等。遇到这些情况,就只能等到程序运行结束后才能判断崩溃的原因了。这时需要用到Linux提供的core  dump机制。当程序中出现内存操作错误时,会发生崩溃并产生核心文件。使用GDB可以对产生的核心文件进行分析,找出程序是在什么时候崩溃的和在崩溃之 前程序都做了些什么。当然,如果要用GDB来分析核心文件,也必须在编译时加上-g选项来产生调试符号表。

在分析核心文件之前必须确认系统是否允许生成核心文件,很多Linux发行版在默认时禁止生成核心文件。为了生成核心文件,首先必须执行下面的命令:
# ulimit -c unlimited

然后就可以生成核心文件了。这里仍以前面的debugme程序为例,再次执行下面命令将产生核心文件:

    

        

            

        

    

                         

生成的核心文件名根据系统配置的不同会有所差异。要在GDB中分析核心文件,除了要给出核心文件的文件名外,还必须给出生成该核心文件的可执行程序的名称,示例如下:

    

        

            

        

    

                         

从GDB的输出信息中可以看出,产生这个核心文件的原因是因为程序收到了序号为11的信号。如果想知道程序在崩溃之前运行到了哪里,可以使用“backtrace”或“info stack”命令查看一下堆栈的历史记录。示例如下:

    

        

            

        

    

                         

由上可知,程序崩溃时正处于_dl_fini()函数之中。但很多时候程序员感兴趣的可能并不是这个, 而是exit()或_libc_start_main()函数,因为它们才可能是问题真正的症结所在。GDB提供的“frame”命令可以用来在不同的调 用上下文中切换。例如下面的命令可以查看exit()函数在执行时的状况:

    

        

            

        

    

                         

此外还可以用“up”或“down”命令在不同的函数调用上下文中切换。开发人员使用这三条命令可以很轻松地实现调用栈的遍历。在分析核心文件时,通过将遍历栈的命令和检查变量值的“print”命令结合起来,就能够复原程序运行时的全部景象。

调试其它进程

有 时会遇到一种很特殊的调试需求,对当前正在运行的其它进程进行调试。这种情况有可能发生在那些无法直接在调试器中运行的进程身上,例如有的进程只能在系统 启动时运行。另外如果需要对进程产生的子进程进行调试的话,也只能采用这种方式。GDB可以对正在执行的程序进行调度,它允许开发人员中断程序并查看其状 态,之后还能让这个程序正常地继续执行。

GDB提供了两种方式来调试正在运行的进程:一种是在GDB命令行上指定进程的PID,另一种是在GDB中使用“attach”命令。例如,开发人员可以先启动debugme程序,让其开始等待用户的输入。示例如下:

    

        

            

        

    

                         

接下去在另一个虚拟控制台中用下面的命令查出该进程对应的进程号:

    

        

            

        

    

                         

得到进程的PID后,就可以使用GDB对其进行调试了:

    

        

            

        

    

                         

在上面的输出信息中,以Attaching to program开始的行表明GDB已经成功地附加在PID为555的进程上了。另外一种连接到其它进程的方法是先用file命令加载调试时所需的符号表,然后再通过“attaché”命令进行连接:

    

        

            

        

    

                         

如果想知道程序现在运行到了哪里,同样可以使用“backtrace”命令。当然也可以使用“step”命令对程序进行单步调试。

在完成调试之后,不要忘记用detach命令断开连接,让被调试的进程可以继续正常运行:

GDB是Linux下一个最基本的调试器,其功能非常丰富。完整地介绍GDB的功能可能需要几百页,本文只涵盖了GDB的一些最常见的用法。作为一个合格的Linux程序员,花在GDB上的功夫和时间越多,从调试中获得的益处就越多。

关于sizeof和内存对齐

感觉这篇文章分析的还算比较到位,故转之。
转自: http://www.52rd.com/Blog/Archive_Thread.asp?SID=10488

本来,一般是不自己计算sizeof的,知道内存对齐会对sizeof有影响,所以从来不手算,而是代码里写上sizeof。今天又看到http://blog.vckbase.com/smileonce/archive/2005/08/08/10658.html,翻来了http://blog.vckbase.com/billdavid/archive/2004/06/23/509.html ,自己想想还是也记录一下,万一以后自己真的也要计算sizeof,忘了,还能有个提示,也给不是很明白的朋友一个参考。
struct sample1
{
    char a;        /// sizeof(char) = 1
    double b;    /// sizeof(double) = 8
};
///default(  缺省#pragam pack(8) ——VC6和VC71,其它编译器,个人未知 )
    ///1+8 = 9 —> 16(  8 < 9 < 16  )

#pragma pack( 4 )
    ///1+8 = 9 —> 12(  8 < 9 < 12  )

#pragma pack( 2 )
    ///1+8 = 9 —> 10(  8 < 9 < 10  )

#pragma pack( 1 )
    ///1+8 = 9 —> 9

#pragma pack( 16 )
    ///1+8 = 9 —> 16(  16—>8 —- 8 < 9 < 16  )

struct sample2
{
    char a;     ///1
    int b;        ///4
};
#pragma pack( 8 )
    /// 1 + 4  = 5 —> 8(  8 —> 4  )

#pragma pack( 16 )
    /// 1 + 4 = 5 —> 8( 16 —> 4  )

    说明:#pragma pack告诉编译器进行内存边界对齐,一般都是采用编译器的设置对整个项目采用同一对齐方案,而且通常为缺省8字节对齐。

/////////////////////////////////以下内容于 2005-12-10 添加/////////////////////////////////

    今天又看到以前测试的一段代码,突然不明白了起来,又稍写了几个测试。
struct sample3
{
    char a;  ///1
    int b;    ///4
    char c;  ///1
};
///default                  ///12
#pragma pack( 4 )   ///12
#pragma pack( 2 )   ///08
#pragma pack( 1 )   ///06
#pragma pack( 16 ) ///12

    原来,其实编译器,根据对齐指示的对齐字节和最大成员的字节,对每个成员进行了对齐:编译器会取对齐指示和最大成员字节中较小的一个用于补齐其它成员。那么,上面的sample1/2/3也就都在情理之中了。为了证实这点,我们还再看一个例子:
struct sample4
{
    char a;      ///1
    int b;         ///4
    double c;  ///8
    char d;      ///1
};
///default:                ///8+8+8+8 = 32
#pragma pack( 4 )   ///4+4+8+4 = 20
#pragma pack( 2 )   ///2+4+8+2 = 16
#pragma pack( 1 )   ///1+4+8+1 = 14
#pragma pack( 16 ) ///8+8+8+8 = 32
而实际上,编译器给出的值是:24、20、16、14、24
那么说明我错了。注意一下,我发现char a,int b加起来也才5<8,难到编译器进行了联合对齐?
struct sample5
{
    char a;      ///1
    double c;  ///8
    int b;         ///4
    char d;      ///1
};
编译器给出结果:24、20、16、14、24

    这用联合对齐的解释正好符合,我又试验了不同的数据,发现这个结论并不太准确确。于是,我输出了每一个对象成员地址进行分析。由于试验数据量很大,这里就不列出了。

最后得到了以下结论:
    1. 成员的对齐是按声明顺序进行的;
    2. 对齐值由编译指示和最大成员两者较小的值决定;
    3. 未对齐到对齐值的成员一起形成块对齐(联合对齐);
    4. 上一个(下一个)对齐采用自己较大则不变,自己较小则填充自己对齐到上一个(下一个)大小;
    5. 每成员对齐:如果前面已对齐到对齐值,下一个对齐自己。如果前面未对齐到对齐值,如果加上下一个成员不大于对齐值,下一个对齐自己,否则填充自己块对齐到对齐值。
    6. 最后还未对齐到对齐值的,填充空间块对齐到对齐值。

从这些结论,可以得到:
    1. 以上的对齐原则其实是尽量整齐排列、尽量节省内存。
    2. 声明成员应该尽量避免不同类型错杂开来,最好采用从小到大或者从大到小的顺序(错开后,会因为上对齐和下对齐而增加填充开销)。
    3. 编译器缺省采用8字节对齐主要是因为最大基本类型为8自己(以前自己不明白,在论坛提过问,后来,以为是SSE指令的原因)。
    4. 手算sizeof是没有必要的,负责的(可以先对齐出对齐块,用块数乘对齐值)。

 
载自 :http://blog.vckbase.com/zhangjw_cn/archive/2005/08/09/10701.html
 
 
—————————————————————————————————-
 
文章二:

#pragma pack和数据对齐问题

结构数据存放时默认按4对齐,考虑以下程序,输出结果为:sizeof(A)=12

typedef struct _A
{
    
int x;
    
char z[7];
}
A;

void main()
{
    
int len = sizeof(A);
    printf(
"sizeof(A)=%d\n", len);    // len = 12
}

使用 #pragma pack,设置数据按1对齐,此时输出结果为:sizeof(A)=11

#pragma pack(push)
#pragma pack(
1)
typedef 
struct _A
{
    
int x;
    
char z[7];
}
A;
#pragma pack(pop)

void main()
{
    
int len = sizeof(A);
    printf(
"sizeof(A)=%d\n", len);    // len = 11
}
 
—————————————————————————————————-

文章三:

解惑:sizeof(联合)这个值是怎么计算的

[不要只做技术]在论坛上问如下代码结果为什么是24?

这个问题很好回答,并且我把这个问题归结于基本概念题(就是入门书必须介绍的)。我想一般来说,做过内存管理的,对这个语言特性肯定不会陌生。

摘几句The C Programming Language里面讲述这个问题的原话,以说明读书还是必要的:
①联合就是一个结构,②它的所有成员相对于基地址的偏移量都为0,③此结构空间要大到足够容纳最“宽”的成员,④并且,其对齐方式要适合于联合中所有类型的成员。

怕有的兄弟还不明白,特附图一个帮助理解:

   

    

        

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

        

        

            

            

            

            

            

            

            

            

        

        

            

            

            

            

            

        

    

char a; => x                                              
int i[5]; =>             

 x

            

            

 x

            

            

 x

            

            

 x

            

            

 x

            

            

x

            

double b; =>             

 x

            

            

 

            

            

 

            

该结构要放得下int  i[5]必须要至少占4×5=20个字节。如果没有double的话20个字节够用了,此时按4字节对齐。但是加入了double就必须考虑double 的对齐方式,double是按照8字节对齐的,所以必须添加4个字节使其满足8×3=24,也就是必须也是8的倍数,这样一来就出来了24这个数字。综上 所述,最终联合体的最小的size也要是所包含的所有类型的基本长度的最小公倍数才行。(这里的字节数均指winnt下的值,平台、编译器不同值也有可能 不同。)

联合在存储分配的时候用的机会最多,因为很少有像存储分配这样需要给多种不同类型的变量分配空间而又打算尽可能的节约内存的,这很适合联合的特性。上述对齐的方式有个很有趣的用法也就常在存储分配里面使用。(下面依旧用The C Programming Language中的例子作答)

这里的Align有什么用?作用只有一个,就是强迫分配的结构体按long的长度对齐。

========== test add by lijunjie =========
struct nn {
    float f;  // 4
    char c1;  // 1 -> 4
    long l;   // 4
    int i;    //4
    char c2;  // 1 -> 4
};

不管是 #pragma pack(4) 还是 #pragma pack(8) ; 因为成员的最大宽度为4,所以最大按照4字节对齐,;因为 c1 的前后成员都能自己对齐,所以c1只好自己完成对齐, 故sizeof 的结果为20;

或许该结构体写成如下方式更合理一些:
struct nn {
    float f;  // 4
    long l;   // 4
    int i;    //4
    char c1;  // c1 和 c2 联合后对齐, 故 1 + 1 = 2 -> 4
    char c2; 
};
故sizeof的结果为 16

=========== 相关文章 ===========
http://westsoftware.blog.163.com/blog/static/26094109201021301421829/

浏览器带来的烦恼

在firefox4中(不知道其它版本是否如此); 如果设置了“自动打开上次未关闭的标签页”, 则该标签页所在的进程cookie也会保留,但是已关闭的那些标签页的进程cookie是不保留的。

这样就给SSO带来了麻烦,在 a.com登录时,同时登录了b.com; 如果把a.com的标签页都关闭,保留b.com的标签页,重启浏览器,b.com自动打开,这时,b.com的进程cookie是保留的,但是a.com的进程cookie是不保留的,于是,a.com和b.com的状态就不统一了。

继续想办法。

PHP 中 echo 与 print的区别

1. echo 可以使用逗号分隔连续输出多个字符串,如:
   echo ‘aaa’, ‘bbb’, ‘ccc’;
   // print ‘aaa’, ‘bbb’, ‘ccc’; 是错误的

2. echo 没有返回值,print有返回值,如:
   echo echo ‘aaa’;  // 语法错误
   echo print ‘aaa’; // 打印出 1

3. print可以以函数的形式使用,echo不可以,如:
   print(‘aaa’); // 可以, 注意:不能多个参数
   echo (‘aaa’); // 不可以,语法错误

4. echo 不是函数,是语法结构; print虽然能用函数形式使用,也有返回值,但是print也不是函数, 如:
   echo function_exists(‘echo’); // 返回false
   echo function_exists(‘print’); // 返回false

PEAR和PECL

PEAR (PHP Extension and Application  Repository)PHP扩展与应用程序库。

PEAR是“一个可重用PHP组件的框架和发布系统”。PEAR可以下载、安装、升级及删除PHP脚本。 使用PEAR包的时候,不必为了脚本的位置或者怎么找到它们而担心,扩展命令行接口(CLI)也很容易使用。
PEAR是一个由社区推动的PHP项目,官方发布的PHP中就包含了PEAR。

PECL (PHP 扩展库)的全称是 The PHP Extension Community Library ,是一个开放的并通过PEAR打包格式来打包安装的PHP 扩展库仓库。通过PEAR 的Package Manager可以对 PECL 模块进行下载和安装。

PEAR和PECL的区别:

Pear:是PHP的扩展代码包,所有的扩展均以PHP代码的形式出现,功能强大,安装简单,甚至可以改改就用。使用的时候,要在代码中进行Include才能够使用。

Pecl:是PHP的标准扩展,可以补充实际开发中所需的功能,所有的扩展都需要安装,在Windows下面以Dll的形式出现,在linux下面,需要单独进行编译,它的表现形式为根据PHP官方的标准用C语言写成,尽管源码开放但是一般人无法随意更改源码。

最直接的表述:Pear是PHP的上层扩展,Pecl是PHP的底层扩展。

在linux上,pear下载的包是直接放在目录 /usr/local/lib/php 下的; 而 pecl下载的包需要编译然后放到目录 /usr/local/lib/php/extensions/no-debug-non-zts-yyyymmdd/ 目录下。 pear下载的包需要 include后使用, pecl安装的包需要修改php.ini,添加extension=xxx.so才能使用。

上面提到pecl是使用pear的打包格式来打包的,其实pecl和pear是两个shell脚本,执行的基本是同一个PHP文件,pecl走的是pear的发布模式。

pear的频道信息保存在目录 /usr/local/lib/php/.channels/中;下载后的模块或包的信息保存在/usr/local/lib/php/.registry/目录中, 数据信息都是已PHP数组的序列化的方式来存储的,这样保存和查询都很方便

linux-利用sar进行性能监控

转自: http://www.51testing.com/?uid-130600-action-viewspace-itemid-220288

为了监控服务器性能
写了个shell脚本,监控服务器的:CPU、MEM、磁盘IO、负载四个指标
记录下来,以备不时之需

sar安装方法:
yum install sysstat

脚本内容如下:

#!/bin/bash
if (( $# != 2))
then
    echo "usage:num1-Please enter the number of script. execution"
    echo "usage:num2-Please enter a value for rest time"
    exit 1
fi

sar -d 0 | head -3 | tail -1 > dev8-0.log
sar -u 0 | head -3 | tail -1 > cpu.log
sar -r 0 | head -3 | tail -1 > mem.log
echo "" > loadAverage.log
for ((i=1;i<=$1;i++))
do
    sar -d 1 | grep dev8-0 | grep -v Average >> dev8-0.log
    sar -u 1 | head -4 | tail -1 >> cpu.log
    sar -r 1 | head -4 | tail -1 >> mem.log
    monitorDate=date +'%F %T'
    load=w | grep 'load average' | awk -F ',' {'print $4,$5,$6'}
    echo $monitorDate $load >> loadAverage.log
    sleep $2
done

脚本使用方法:
chmod +x monitor.sh(脚本名)
./monitor.sh 5 1
每1秒记录监控数据一次,共记录5次
注:每次运行脚本时,会把上一次的日志清空;

脚本内容解释:
sar -d 1:打印磁盘IO信息,采样间隔1秒
sar -u 1:打印CPU信息,采样间隔1秒
sar -r 1:打印MEM信息,采样间隔1秒
然后再利用一些grep/head/tail/awk等命令取得想要的部份信息;
(使用过程中发现,采样间隔使用0秒时,会出现打印出来的CPU和磁盘IO信息全一样,MEM会有所不同。。。)

脚本运行结果:
./monitor.sh 5 1
运行后,当前目录下会生成下面几个日志文件:

# cat cpu.log
02:21:24 PM       CPU     %user     %nice   %system   %iowait    %steal     %idle
02:21:24 PM       all      0.89      0.05      1.29      0.23      0.00     97.54
02:21:25 PM       all      0.89      0.05      1.29      0.23      0.00     97.54
02:21:26 PM       all      0.89      0.05      1.29      0.23      0.00     97.54
02:21:27 PM       all      0.89      0.05      1.29      0.23      0.00     97.54
02:21:28 PM       all      0.89      0.05      1.29      0.23      0.00     97.54
%user 在用户模式中运行进程所花的时间
%nice 运行正常进程所花的时间
%system 在内核模式(系统)中运行进程所花的时间
%iowait 没有进程在该CPU上执行时,处理器等待I/O完成的时间
%idle 没有进程在该CPU上执行的时间

#cat mem.log
02:21:24 PM kbmemfree kbmemused  %memused kbbuffers  kbcached kbswpfree kbswpused  %swpused  kbswpcad
02:21:24 PM   2884304   1267572     30.53    335216    795552   2048248         0      0.00         0
02:21:25 PM   2884428   1267448     30.53    335216    795552   2048248         0      0.00         0
02:21:26 PM   2884428   1267448     30.53    335216    795552   2048248         0      0.00         0
02:21:27 PM   2884428   1267448     30.53    335216    795552   2048248         0      0.00         0
02:21:28 PM   2884552   1267324     30.52    335216    795552   2048248         0      0.00         0
kbmemfree 空闲内存大小
kbmemused 内存使用量大小
%memused 内存使用量百分比
kbbuffers 内存buffers大小
kbcached 内存cached大小
kbswpfree 空闲swap大小
kbswpused swap使用量大小
%swpused swap使用量百分比

# cat dev8-0.log
02:21:24 PM       DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
02:21:24 PM    dev8-0      0.92      0.22     27.83     30.47      0.02     19.40      6.18      0.57
02:21:25 PM    dev8-0      0.92      0.22     27.83     30.47      0.02     19.40      6.18      0.57
02:21:26 PM    dev8-0      0.92      0.22     27.83     30.47      0.02     19.40      6.18      0.57
02:21:27 PM    dev8-0      0.92      0.22     27.83     30.47      0.02     19.40      6.18      0.57
02:21:28 PM    dev8-0      0.92      0.22     27.83     30.47      0.02     19.40      6.18      0.57
DEV  sar命令正在监视的块设备的名字。
tps  每秒传输数(或者每秒IO数)
rd_sec/s 每秒512字节读取数
wr_sec/s 每秒512字节写入数
%util  设备饱和度时,会发生此值接近100%。

# cat loadAverage.log

2010-09-16 14:21:24 load average: 0.14 0.14 0.15
2010-09-16 14:21:25 load average: 0.61 0.23 0.18
2010-09-16 14:21:26 load average: 0.61 0.23 0.18
2010-09-16 14:21:27 load average: 0.61 0.23 0.18
2010-09-16 14:21:28 load average: 0.61 0.23 0.18