from : http://blog.csdn.net/hlchou/article/details/6441272

[

ftrace 简介 http://www.ibm.com/developerworks/cn/linux/l-cn-ftrace/index.html#author1

android性能测试工具之dumpstate http://blog.csdn.net/melody_lu123/article/details/6859879

]

在软体开发时, 通常都会面临到系统效能调教的需求, 我们希望知道哪些区块的程式码或函式被执行的次数频繁, 或是占据较高的处理器时间, 以便借此优化程式码撰写的行为, 或是改善耗CPU 时间的算法, 以Linux 平台来说,OProfile(http://oprofile.sourceforge.net ) 会是一个大家常推荐的工具,OProfile 支持Time-based 透过系统Timer 中断搜集当下执行环境资讯, 并加以统计, 或基于Event-based, 以ARM 来说就是PerformanceMonitor Unit(CP15) 硬体支援的Performance 控制单元( 更多资讯可以参考:http://infocenter.arm.com/help/ topic/com.arm.doc.dai0195b/index.html),ARMPMU 提供例如Instruction/DataCache 使用状况(miss,write-back,write-buffer..etc) ,Memory/MMU 存取的状况,IRQ/FIQ Latency ,Branch预测统计,I/D-TCMStatus..etc, 基于这机制的Profiling 可以在影响系统效能最少的情况下, 进行System-wide 的性能统计资讯. 另一种选择, 则是透过ARM 接上JTAG 介面, 藉由ICE 软体的Profiling 功能进行分析.

然而, 如果我们希望更明确的知道每个Function 被执行的次数(OProfileTime-based 的统计时间够长就可得出对应的比例,做为决定的依据), 执行的流程, 与个别时间成本, 或是系统在排程(Scheduling andWake-up), 中断,Block/Net, 或Kernel 记忆体配置.. 等, 与LinuxKernel 核心物件有关资讯的话, 其实Ftrace 会是另一个可以辅助的资讯来源, 不同于OProfile ,Ftrace 会透过gcc-pg 把每个函式前面都插入呼叫mcount 函式的动作, 在Branch 统计部分, 也会把if 或是透过likely/unlikely 巨集, 进行植入是的统计, 因此,Ftrace 相比OProfile 虽然可以提供比较完整的Kernel 层级统计资讯, 但因为OProfile 主要是透过ARM 或其他处理器平台的PerformanceMonitor 单元, 因此,OProfile 可以在影响系统效能较低的情况下进行统计( ㄟ ... Time-basedFunctionprofiling 也是会影响到被测端的效能的.), 但总体而言, 都比mcount 植入每个函式中, 对系统效能的影响更算是轻量. 如何决定应用哪个模块进行效能分析, 还是要依据当下开发时的目的与所遇到的问题来做决定.

Ftrace 最应该参考的文件就是LinuxKernel 原始码中位于Documentation/ftrace.txt 的文件, 参考该文件资讯与Google 一下​​,Ftrace 作者为在RedHat 服务的Steven Rostedt, 主要目的是为LinuxKernel 提供一个系统效能分析的工具, 以便用以除错或是改善/ 优化系统效能,Ftrace 为一个以FunctionTrace 为基础的工具, 并包含了包括行程Context-Switch,Wake-Up/Ready到执行的时间成本, 中断关闭的时间, 以及是哪些函式呼叫所触发的, 这都有助于在复杂的系统执行下, 提供必要资讯以便定位问题.

接下来, 我们将介绍GCC 对于FtraceProfiling 上, 在编译器层级的支援, 以及有关的builtin 函式, 让各位清楚这些机制底层运作的原理, 最后, 并以Ftrace 为主, 说明个机制的内容, 但本文并不会深入探究到各Ftrace 模组机制的实作部分, 主要只以笔者自己认为值得说明的区块, 来加以说明, 对各项细节有兴趣的开发者, 建议可以自行探究.

GCC“-pg” Profiling 机制与builtin 函式对FtraceBranch Profiling 的支援

Ftrace 支援在有加入“ likely/unlikely” 条件判断式位置的BrnchProfiling 与对整个核心if 条件判断式的BrnchProfiling ( 当然,选择后者对效能影响也比较明显... 要做记录的地方变多了.) . 使用者可以透过Kernelhacking --->Tracers --->Branch Profiling ---> 来选择“ Nobranch profiling”,”Trace likely/unlikely profiler” 或“ Profile all ifconditionalss”. 对系统进行BranchProfiling 的动作.( Ftrace 在config 中有这四个设定跟BranchProfiling 有关CONFIG_TRACE_BRANCH_PROFILING,CONFIG_BRANCH_PROFILE_NONE,CONFIG_PROFILE_ANNOTATED_BRANCHES与CONFIG_PROFILE_ALL_BRANCHES)

参考include/linux/compiler.h 中的实作, 如果选择“ Profileall if conditionalss”, 就会把全部的if 条件判断字元, 透过gccprecompile 定义为巨集__trace_if, 如下所示

#defineif(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )

#define__trace_if(cond) /

if(__builtin_constant_p((cond)) ? !!(cond) : /

({ /

int______r; /

staticstruct ftrace_branch_data /

__attribute__((__aligned__(4))) /

__attribute__((section("_ftrace_branch"))) /

______f= { /

.func= __func__, /

.file= __FILE__, /

.line= __LINE__, /

}; /

______r= !!(cond); /

______f.miss_hit[______r]++; /

______r; /

}))

如果if 条件式为常数( 也就是说编译器可以在编译阶段就决定好if/else 路径了), 就不纳入统计, 反之, 就会根据条件式的结果(______r=0 or 1) 统计命中的次数, 作为if/else 条件设计的参考.( 其实, 透过likely/unlikely 优化编译阶段的BranchPredition 是很有帮助的).

如果是设定为” Tracelikely/unlikely profiler”, 就会把likely 与unlikely 巨集定义如下所示

/*

*Using __builtin_constant_p(x) to ignore cases where the return

*value is always the same. This idea is taken from a similar patch

*written by Daniel Walker.

*/

#ifndef likely

# define likely(x) (__builtin_constant_p(x) ? !!(x) :__branch_check__(x, 1))

#endif

#ifndef unlikely

# define unlikely(x) (__builtin_constant_p(x) ? !!(x) :__branch_check__(x, 0))

#endif

其中__branch_check__ 定义如下

#definelikely_notrace(x) __builtin_expect(!!(x), 1)

#defineunlikely_notrace(x) __builtin_expect(!!(x), 0)

#define__branch_check__(x, expect) ({ /

int______r; /

staticstruct ftrace_branch_data /

__attribute__((__aligned__(4))) /

__attribute__((section("_ftrace_annotated_branch")))/

______f= { /

.func= __func__, /

.file= __FILE__, /

.line= __LINE__, /

}; /

______r= likely_notrace(x); /

ftrace_likely_update(&______f,______r, expect); /

______r; /

})

函式ftrace_likely_update( 位置在kernel/trace/trace_branch.c) 实作如下所示,

voidftrace_likely_update(struct ftrace_branch_data *f, int val, intexpect)

{

/*

*I would love to have a trace point here instead, but the

*trace point code is so inundated with unlikely and likely

*conditions that the recursive nightmare that exists is too

*much to try to get working. At least for now.

*/

trace_likely_condition(f,val, expect);

/*FIXME: Make this atomic! */

if(val == expect)

f->correct++;

else

f->incorrect++;

}

有关函式trace_likely_condition 的行为在此就不追踪, 只谈函式ftrace_likely_update, 这函式会统计开发者使用likely/unlikely 定义好的if/else 区块顺序, 跟实际执行时,if/else 执行的结果, 透过correct/incorrect 累加, 我们可以根据Run-Time 实际统计的结果, 看是否原本likely/unlikely 有需要修正的空间( 往统计正确的方向去, 就可避免处理器PipelineFlush 的机会), 以便得到更好的执行效能.

若没有启动任何BranchProfiling 的动作, 则likely 与unlikely 就只会透过Builtin 函式_builtin_expect( 在GCC2.96 版本之后支援) 进行编译阶段的BranchPredition 优化动作, 如下宣告

#define likely(x) __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)

编译器支援的Builtin 函式__builtin_constant_p, 主要的功能为判断所给予的值是否为常数(__builtin_constant_p 会返回1,若不是常数__builtin_constant_p 会返回0), 若是则可在编译时期安排好对应的执行动作, 就不需要把全部的行为, 都放到编译后的程式码, 透过执行时期才决定.

以如下程式码来验证行为,

#defineY 6

voidFunc(int Z)

{

intvResult;

vResult=__builtin_constant_p(Z)?(Z*100):-1;

printf("5:Result:%ld/n",vResult);

vResult=(Z*100);

printf("6:Result:%ld/n",vResult);

}

intmain()

{

intX=5;

intvResult;

vResult=__builtin_constant_p(X)?(X*100):-1;

printf("1:Result:%ld/n",vResult);

vResult=(X*100);

printf("2:Result:%ld/n",vResult);

vResult=__builtin_constant_p(Y)?(Y*100):-1;

printf("3:Result:%ld/n",vResult);

vResult=(Y*100);

printf("4:Result:%ld/n",vResult);

Func(7);

return;

}

以gcc 版本4.1.2 来验证, 若以-O0 编译,X 为一个区域变数,__builtin_constant_p(X) 会返回0, 反之,Y 为一个定义的常数,__builtin_constant_p(Y) 会返回1, 而如果把一个常数透过函式参数Z 传递, 因为这个值会被放到堆叠( 根据每个处理器的CallingConvention, 在ARM 上会先放到暂存器R0-R3), 导致__builtin_constant_p(Z) 返回0, 若是以-O1 或-O2 编译, 则编译器可以判断区域变数X 的值,__builtin_constant_p(X) 会返回1, 若是函式函式传递的参数Z,_builtin_constant_p(Z) 还是会传回0. 优化的区块还是以Function 本身为单位, 并且有打开优化选项, 可以让Builtin 函式发挥更好的效能.

参考GCC 文件,__builtin_constant_p 也可以作为Constant 变数初始值的指定( 文件建议要在GCC3.0.1 版本之后), 如下所示, 若EXPRESSION 为常数, 则table 初始值为该常数, 反之则初始值为0.

staticconst int table[] = {

__builtin_constant_p(EXPRESSION) ? (EXPRESSION) : -1,

};

另一个需要介绍的Builtin 函式为__builtin_expect, 这函式的功能主要在提供编译器BranchPrediction 的能力, 如以下的程式码

voidFuncA(int X)

{

if(__builtin_expect(X,1))

{

printf("FuncA1:%ld/n",X*0x100);

}

else

{

printf("FuncA2:%ld/n",X);

}

}

voidFuncB(int X)

{

if(__builtin_expect(X,0))

{

printf("FuncB1:%ld/n",X*0x100);

}

else

{

printf("FuncB2:%ld/n",X);

}

}

intmain()

{

FuncA(7);

FuncB(8);

return;

}

执行结果为

FuncA1:700h

FuncB1:800h

以gcc4.1.2 搭配-O2 进行编译( 在这验证环境下, 使用-O0, 函式__builtin_expect 会没有效果), 执行结果一致, 透过反组译程式码结果如下

FuncA/B (-O0)

FuncA (-O2) -if(__builtin_expect(X,1))

FuncB(-O2)-if(__builtin_expect(X,0))

push %ebp

mov %esp,%ebp

sub $0x8,%esp

mov 0x8(%ebp),%eax

test %eax,%eax

je 80483a9 <FuncA+0x25>

mov 0x8(%ebp),%eax

shl $0x8,%eax

mov %eax,0x4(%esp)

movl $0x8048500,(%esp)

call 8048298 <printf@plt>

jmp 80483bc <FuncA+0x38>

80483a9:

mov 0x8(%ebp),%eax

mov %eax,0x4(%esp)

movl $0x804850d,(%esp)

call 8048298 <printf@plt>

leave

ret

push %ebp

mov %esp,%ebp

sub $0x8,%esp

mov 0x8(%ebp),%eax

test %eax,%eax

je 80483f2 <FuncA+0x22>

shl $0x8,%eax

mov %eax,0x4(%esp)

movl $0x804853a,(%esp)

call 8048298 <printf@plt>

leave

ret

80483f2:

movl $0x0,0x4(%esp)

movl $0x8048547,(%esp)

call 8048298 <printf@plt>

leave

ret

push %ebp

mov %esp,%ebp

sub $0x8,%esp

mov 0x8(%ebp),%eax

test %eax,%eax

jne 80483b3 <FuncB+0x23>

movl $0x0,0x4(%esp)

movl $0x804852d,(%esp)

call 8048298 <printf@plt>

leave

ret

80483b3:

shl $0x8,%eax

mov %eax,0x4(%esp)

movl $0x8048520,(%esp)

call 8048298 <printf@plt>

leave

ret

我们可以看到__builtin_expect(X,1) 会优先把if 的执行区块放到连续的程式码中, 而__builtin_expect(X,0) 则是会把else 的执行区块, 放到前面连续的程式码中, 至于执行时期会执行到if 或else 的区块, 就根据X 条件是否为0 来决定. 参考GCC文件, 我们也可以搭配条件判断的写法

可以参考LinuxKernel 中include/linux/compiler.h 中的实作, 如下所示

#define likely(x) __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)

如果开发者判断,if 的区块是较常被执行到的, 那就应该用likely, 例如

if(likely(success))

{….}

else //else 区块可能为error 处理逻辑多数的情况应该希望走的是if 的逻辑

{….}

如果开发者判断else 区块, 是希望较常被执行到的, 就可以使用unlikely, 例如

if(unlikely(error))

{….}

else //success

{….}

处理器本身也有BranchPredition 的能力, 如果不在有被处理器记忆到的BPEntry 中, 处理器通常会循序 Fetch 指令进来,一旦发现分支预测错误 , 就会 FlushPipeline, 透过函式__builtin_expect, 我们可以在编译时期, 依据传入值的结果, 决定if/else 编译为机械码时程式码排列的顺序, 减少处理器Pipeline 被Flush 的机率, 这对执行效能也是有很大的帮助.

GCCsupport for the GNU profiler gprof

有关GNUgprof 的介绍, 可以参考网页http://www.cs.utah.edu/dept/old/texinfo/as/gprof.html . 基于GCC 对Profiling 的支援, 开发端可以透过-pg 的编译参数, 让gcc 把profiling 的功能加入到程式码中,

以如下程式码为例,

intFuncA()

{

inti;

intvRet=0;

for(i=0;i<20000;i++)

{

vRet+=i;

}

returnvRet;

}

intFuncB(int I)

{

inti;

intvRet=0;

for(i=0;i<9999;i++)

{

vRet+=I+FuncA();

}

returnvRet;

}

intmain()

{

intvResult;

vResult=FuncA();

vResult=FuncB(vResult);

printf("Result:%ld/n",vResult);

return0;

}

透过gcc 编译后, 有加上-pg 与没加上的差异如下

函式名称

无-pg

有加上-pg

main

lea 0x4(%esp),%ecx

and $0xfffffff0,%esp

pushl 0xfffffffc(%ecx)

push %ebp

mov %esp,%ebp

push %ecx

sub $0x24,%esp

call 8048384 <FuncA>

mov %eax,0xfffffff8(%ebp)

mov 0xfffffff8(%ebp),%eax

mov %eax,(%esp)

call 80483b2 <FuncB>

mov %eax,0xfffffff8(%ebp)

mov 0xfffffff8(%ebp),%eax

mov %eax,0x4(%esp)

movl $0x8048500,(%esp)

call 8048298 <printf@plt>

mov $0x0,%eax

add $0x24,%esp

pop %ecx

pop %ebp

lea 0xfffffffc(%ecx),%esp

ret

lea 0x4(%esp),%ecx

and $0xfffffff0,%esp

pushl 0xfffffffc(%ecx)

push %ebp

mov %esp,%ebp

push %ecx

sub $0x24,%esp

call 804837c <mcount@plt> =>Glibc 提供的mcount 函式

call 80484b4 <FuncA>

mov %eax,0xfffffff8(%ebp)

mov 0xfffffff8(%ebp),%eax

mov %eax,(%esp)

call 80484e7 <FuncB>

mov %eax,0xfffffff8(%ebp)

mov 0xfffffff8(%ebp),%eax

mov %eax,0x4(%esp)

movl $0x8048680,(%esp)

call 804835c <printf@plt>

mov $0x0,%eax

add $0x24,%esp

pop %ecx

pop %ebp

lea 0xfffffffc(%ecx),%esp

ret

FuncA

push %ebp

mov %esp,%ebp

sub $0x10,%esp

movl $0x0,0xfffffffc(%ebp)

movl $0x0,0xfffffff8(%ebp)

jmp 80483a4 <FuncA+0x20>

mov 0xfffffff8(%ebp),%eax

add %eax,0xfffffffc(%ebp)

addl $0x1,0xfffffff8(%ebp)

cmpl $0x4e1f,0xfffffff8(%ebp)

jle 804839a <FuncA+0x16>

mov 0xfffffffc(%ebp),%eax

leave

ret

push %ebp

mov %esp,%ebp

sub $0x10,%esp

call 804837c <mcount@plt> =>Glibc 提供的mcount 函式

movl $0x0,0xfffffffc(%ebp)

movl $0x0,0xfffffff8(%ebp)

jmp 80484d9 <FuncA+0x25>

mov 0xfffffff8(%ebp),%eax

add %eax,0xfffffffc(%ebp)

addl $0x1,0xfffffff8(%ebp)

cmpl $0x4e1f,0xfffffff8(%ebp)

jle 80484cf <FuncA+0x1b>

mov 0xfffffffc(%ebp),%eax

leave

ret

FuncB

push %ebp

mov %esp,%ebp

sub $0x10,%esp

movl $0x0,0xfffffffc(%ebp)

movl $0x0,0xfffffff8(%ebp)

jmp 80483d7 <FuncB+0x25>

call 8048384 <FuncA>

add 0x8(%ebp),%eax

add %eax,0xfffffffc(%ebp)

addl $0x1,0xfffffff8(%ebp)

cmpl $0x270e,0xfffffff8(%ebp)

jle 80483c8 <FuncB+0x16>

mov 0xfffffffc(%ebp),%eax

leave

ret

push %ebp

mov %esp,%ebp

sub $0x10,%esp

call 804837c <mcount@plt> =>Glibc 提供的mcount 函式

movl $0x0,0xfffffffc(%ebp)

movl $0x0,0xfffffff8(%ebp)

jmp 8048511 <FuncB+0x2a>

call 80484b4 <FuncA>

add 0x8(%ebp),%eax

add %eax,0xfffffffc(%ebp)

addl $0x1,0xfffffff8(%ebp)

cmpl $0x270e,0xfffffff8(%ebp)

jle 8048502 <FuncB+0x1b>

mov 0xfffffffc(%ebp),%eax

leave

ret

[root@localhostpg]# gcc -g -pg pg.c -o pg

[root@localhostpg]# ./pg

Result:785467424

[root@localhostpg]# ls -l gmon.out

-rw-r--r--1 root root 464 May 13 06:32 gmon.out

[root@localhostpg]# gprof --brief ./pg

[root@localhostpg]# gprof --brief ./pg

Flatprofile:

Eachsample counts as 0.01 seconds.

% time

cumulative (seconds)

self (seconds)

calls

Self (ms/call)

Total (ms/call)

name

100.54

0.47

0.47

10000

0.05

0.05

FuncA

0

0.47

0

1

0

472.49

FuncB

=> 简要说明每次呼叫FuncA 需要0.05ms, 总共呼叫了10000 耗时0.47 ㄟ也许应该说每次呼叫FuncA 需要0.047ms 会比较精确一点), FnucB 被呼叫耗时472.49ms( funcB 中会执行9999 FuncA).

Callgraph

granularity:each sample hit covers 2 byte(s) for 2.12% of 0.47 seconds

index

% time

self

children

called

name

0

0

1/10000

main [2]

0.47

0

9999/10000

FuncB [3]

[1]

100

0.47

0

10000

FuncA [1]

=> 简要说明FuncA 为主体来对比,FuncA 执行了10000 次共0.47 秒的时间,FuncB 呼叫了FuncA9999 ( 占总数9999/10000),main 呼叫了FuncA1 次 占总数1/10000)

index

% time

self

children

called

name

[2]

100

0

0.47

main [2]

0

0.47

1

FuncB [3]

0

0

1/10000

FuncA [1]

=> 简要说明main 为主体来对比,main 呼叫的函式(children) 花了0.47 分别呼叫了FuncB 占了9999/10000(约等于1) 的时间与呼叫了FuncA 占了1/ 10000 的时间.

index

% time

self

children

called

name

0

0.47

1

main [2]

[3]

100

0

0.47

1

FuncB [3]

0.47

0

9999/10000

FuncA [1]

=> 简要说明funcB 为主体来对比,main 呼叫的函式FuncA funcB(children) 花了0.47 ,FuncB 呼叫的函式FuncA 花了0.47 因为最小单位为0.01 太接近的两个数字如果差距是在0.01 秒以内数字就有机会变成一样),FuncB 被呼叫,FuncA FuncB 呼叫9999 

Indexby function name

[1]FuncA [3] FuncB

Infrastructurefor profiling code inserted by 'gcc -pg'.

http://www.network-theory.co.uk/docs/gccintro/gccintro_80.html

LinuxKernel EnableTracer

要在核心中支援Ftrace, 除了GCC 编译器要支援-pg 外, 所采用的C 函式库也要支援相关mcount 的函式, 笔者用AndroidSDK 带的arm-eabi-gcc4.4.0 会产生编译错误“ undefinedreference to `__gnu_mcount_nc' “. 笔者后来是到Sourcery网址http://www.codesourcery.com/sgpp/lite/arm/portal/subscription3053下载arm-2007q3 版本的编译器与函式库环境, 以此为基础进行ARM 环境LinuxKernel 开启Ftrace 的编译, 就可以解决无法Link'__gnu_mcount_nc' 的错误了.( 有关编译环境与KernelSource Code 版本的选择, 会随着版本演进而有所差异, 如有遇到编译错误发生时, 还请以各位自己所选择的环境为主来判断.)

接下来执行 make menuconfig.

如果是在x86 的机器上, 要Enable“Kernel Function Graph Trace” 的功能, 就要透过Generalsetup --->Optimize for size , 选择关闭“ Optimize for size “. 而在ARM 平台上, 目前没有“ KernelFunction Graph Trace” 的选项, 所以就不受此限制.

此外, 在LinuxKernel 2.6.31 给ARM 环境的组态中, 目前并不支援DynamicFtrace, 所以像是set_ftrace_filter与set_ftrace_nontrace 这类可以动态设定函式名称过滤原则的机制, 在笔者环境中就无法支援, 我在说明时, 会以x86 版本来替代, 后续支援与否请以LinuxKernel 版本演进为主.

在选单中进入Kernelhacking ---> Tracers ---> 就可以选择要开启哪些Tracers 功能, 以笔者手中针对ARM 版本的Config内容如下( 我是都勾选了...)

-*-Kernel Function Tracer

[*]Interrupts-off Latency Tracer

[*]Scheduling Latency Tracer

-*-Trace process context switches

[*]Trace boot initcalls

[*]Trace likely/unlikely profiler

[*] Profile all if conditionals

[*]Trace likely/unlikely instances

[*]Trace max stack

最后确认DebugFilesystem 是否有被勾选, 路径为Kernelhacking --->-*- Debug Filesystem.

退出选单, 由于刚才已经勾选“ CONFIG_FUNCTION_TRACER” 组态, 可以参考档案kernel/trace/Makefile 的内容, 设定CONFIG_FUNCTION_TRACER 后, 就会把KBUILD_CFLAGS 加上-pg, 每个核心函式中都会被置入mcount 函式的呼叫

ifdefCONFIG_FUNCTION_TRACER

ORIG_CFLAGS:= $(KBUILD_CFLAGS)

KBUILD_CFLAGS= $(subst -pg,,$(ORIG_CFLAGS))

...

endif

Kernel 内部有关除错, 或是Ftrace 相关的档案, 会移除-pg 的编译参数, 避免影响统计的结果, 例如在kernel/Makefile 档案中

ifdefCONFIG_FUNCTION_TRACER

# Donot trace debug files and internal ftrace files

CFLAGS_REMOVE_lockdep.o= -pg

CFLAGS_REMOVE_lockdep_proc.o= -pg

CFLAGS_REMOVE_mutex-debug.o= -pg

… ............

endif

比较一下, 有打开FunctionTracer 跟没有打开FunctionTracer 的核心编译结果如下所示, 可以看到GCC 编译器, 对编译结果的影响.

没有打开Ftracer 的do_fork 函式

打开Ftracer 的do_fork 函式

00001458<do_fork>:

push {r4, r5, r6, r7, r8, r9, sl, lr}

tst r0, #268435456 ; 0x10000000

sub sp, sp, #32 ; 0x20

mov r5, r0

mov r7, r1

mov r6, r2

mov sl, r3

bne 1688 <do_fork+0x230>

ands r4, r5, #33554432 ; 0x2000000

moveq r9, #0 ; 0x0

movne r9, #1 ; 0x1

bne 16c0 <do_fork+0x268>

ldr r3, [r6, #64]

tst r3, #15 ; 0xf

bne 149c <do_fork+0x44>

tst r5, #8388608 ; 0x800000

beq 1604 <do_fork+0x1ac>

mov r8, #0 ; 0x0

ldr ip, [sp, #68]

mov r1, r7

str ip, [sp]

mov r2, r6

000018b0<do_fork>:

mov ip, sp

push {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}

sub fp, ip, #4 ; 0x4

sub sp, sp, #52 ; 0x34

mov ip, lr

bl 0 <mcount>

.word 0x00000040

tst r0, #268435456 ; 0x10000000

mov r7, r0

mov sl, r1

mov r6, r2

str r3, [fp, #-72]

bne 1c7c <do_fork+0x3cc>

ands r5, r7, #33554432 ; 0x2000000

moveq r8, #0 ; 0x0

movne r8, #1 ; 0x1

mov r1, r8

ldr r0, [pc, #1060] ; 1d20 <do_fork+0x470>

mov r2, #0 ; 0x0

bl 0 <ftrace_likely_update>

subs r1, r8, #0 ; 0x0

DebugFSFileSystem

Ftrace 会使用虚拟的档案系统debugfs 做为设定档与输出结果的储存位置, 我们可以先在根目录产生/debug 档案, 然后mountdebugfs 到/debug 目录下(Ftrace 文件建议可以mount 到/sys/kernel/debug 目录下)

#mkdir /debug

#mount -t debugfs nodev /debug

之后进入/debug/tracing 目录下

# cd/debug/tracing

查询系统中支援哪些Tracer

$ catavailable_tracers

function_graphfunction_duration function sched_switch nop

选择sched_switch 作为目前运作的Tracer

#echo sched_switch > current_tracer

可以检视目录下的trace 档案, 观察sched_switch 输出的结果

#cat trace

#tracer: sched_switch

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<idle>-0 [000] 745.934676: 0:140:R ==> [000] 2892:120:R

gnome-terminal-2892 [000] 745.934770: 2892:120:S ==> [000] 0:140:R

<idle>-0 [000] 745.934861: 0:140:R ==> [000] 2892:120:R

gnome-terminal-2892 [000] 745.934937: 2892:120:S ==> [000] 0:140:R

bash-5175 [001] 745.934960: 5175:120:S + [000] 2892:120:S

bash-5175 [001] 745.935149: 5175:120:S + [000] 2892:120:S

暂停Ftrace 的运作,

#echo nop > current_tracer

上述步骤, 为透过debugfs 操作Ftrace 的基本行为, 接下来让我们初步认识Ftrace 相关的控制档案

介绍Ftrace 目录tracing 下的档案

我们以AndroidARM 平台搭配LinuxKernel 2.6.31 为例子, 首先建立/data/debug 目录, 并且把debugfs 虚拟档案系统载入

# mkdir/data/debug

# mount-t debugfs nodev /data/debug

# cd/data/debug

浏览目录下的内容,

# ls

sched_features

mmc0

tracing

bdi

#

进入目录tracing 后,ls 浏览该目录的结果

# cd/data/debug

# ls -l

-r--r--r--root root 0 1970-01-01 00:00 stack_trace

-rw-r--r--root root 0 1970-01-01 00:00 stack_max_size

drwxr-xr-xroot root 1970-01-01 00:00 events

-rw-r--r--root root 0 1970-01-01 00:00 set_event

-r--r--r--root root 0 1970-01-01 00:00 available_events

-r--r--r--root root 0 1970-01-01 00:00 printk_formats

drwxr-xr-xroot root 1970-01-01 00:00 per_cpu

drwxr-xr-xroot root 1970-01-01 00:00 options

-r--r--r--root root 0 1970-01-01 00:00 saved_cmdlines

--w--w----root root 0 1970-01-01 00:00 trace_marker

-rw-r--r--root root 0 1970-01-01 00:00 buffer_size_kb

-r--r--r--root root 0 1970-01-01 00:00 trace_pipe

-r--r--r--root root 0 1970-01-01 00:00 README

-rw-r--r--root root 0 1970-01-01 00:00 tracing_thresh

-rw-r--r--root root 0 1970-01-01 00:00 tracing_max_latency

-rw-r--r--root root 0 1970-01-01 00:00 current_tracer

-r--r--r--root root 0 1970-01-01 00:00 available_tracers

-rw-r--r--root root 0 1970-01-01 00:00 trace

-rw-r--r--root root 0 1970-01-01 00:00 tracing_cpumask

-rw-r--r--root root 0 1970-01-01 00:00 trace_options

-rw-r--r--root root 0 1970-01-01 00:00 tracing_enabled

-rw-r--r--root root 0 1970-01-01 00:00 tracing_on

-rw-r--r--root root 0 1970-01-01 00:00 function_profile_enabled

drwxr-xr-xroot root 1970-01-01 00:00 trace_stat

-rw-r--r--root root 0 1970-01-01 00:00 set_ftrace_pid

接下来, 笔者以这目录下的档案, 挑选认为应该说明的部份, 如下所示

档案名称

说明

current_tracer

用来显示目前被设定的Tracer.

如果没有任何被设定的Tracer 就会返回nop

# cat current_tracer

nop

以 sched_switch 设定到 current_tracer 来示范这档案的功能

# echo >/data/debug/tracing/trace => 清空trace 内容

# echo sched_switch >/data/debug/tracing/current_tracer

# echo 1 >/data/debug/tracing/tracing_enabled

# sleep 1

# echo 0 >/data/debug/tracing/tracing_enabled

#cat/data/debug/tracing/trace

#tracer: sched_switch

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-9560 [000] 52138.209612: 9560:120:R ==> [000] 9538:120:Rkworker/0:1

kworker/0:1-9538 [000] 52138.209903: 9538:120:S ==> [000] 9558:120:Rin.telnetd

in.telnetd-9558 [000] 52138.211017: 9558:120:S ==> [000] 9560:120:R bash

bash-9560 [000] 52138.211412: 9560:120:S + [000] 9560:120:S bash

bash-9560 [000] 52138.211613: 9560:120:R + [000] 9538:120:Rkworker/0:1

bash-9560 [000] 52138.211820: 9560:120:R ==> [000] 9538:120:Rkworker/0:1

kworker/0:1-9538 [000] 52138.211990: 9538:120:R + [000] 9558:120:R in.telnetd

kworker/0:1-9538 [000] 52138.212148: 9538:120:S ==> [000] 9558:120:Rin.telnetd

in.telnetd-9558 [000] 52138.212953: 9558:120:S ==> [000] 9560:120:R bash

bash-9560 [000] 52138.213221: 9560:120:S ==> [000] 0:120:R <idle>

<idle>-0 [000] 52138.414815: 0:120:R + [000] 9538:120:Rkworker/0:1

<idle>-0 [000] 52138.414976: 0:120:R ==> [000] 9538:120:Rkworker/0:1

kworker/0:1-9538 [000] 52138.415243: 9538:120:S ==> [000] 0:120:R <idle>

<idle>-0 [000] 52138.417111: 0:120:R + [000] 9538:120:Rkworker/0:1

<idle>-0 [000] 52138.417312: 0:120:R ==> [000] 9538:120:Rkworker/0:1

kworker/0:1-9538 [000] 52138.417541: 9538:120:S ==> [000] 0:120:R <idle>

<idle>-0 [000] 52138.448254: 0:120:R + [000] 1811:120:R pcscd

<idle>-0 [000] 52138.448547: 0:120:R ==> [000] 1811:120:Rpcscd

pcscd-1811 [000] 52138.450170: 1811:120:S ==> [000] 0:120:R <idle>

<idle>-0 [000] 52138.540657: 0:120:R + [000] 1892:139:Rgam_server

available_tracers

列出目前LinuxKernel 中在编译时有被启用的Tracer. 我们只要把这些对应的名字设定到current_tracer 中就可以启用对应的Tracer. 如下所示为笔者环境中所支持的Tracer.

# cat available_tracers

blk kmemtrace branchwakeup_rt wakeup irqsoff function sched_switch initcall nop

tracing_enabled

用以控制Tracer 的启动或是停止, 当为1 时表示Tracer 启动, 反之, 为0 就是停止, 如下所示

启动Tracer

#echo1 > /data/debug/tracing/tracing_enabled

暂停Tracer

#echo0 > /data/debug/tracing/tracing_enabled

trace

用以把Tracer 的结果呈现出人可阅读的格式.

#more/data/debug/tracing/trace

清空 Tracer 结果内容

#echo >/data/debug/tracing/trace

trace_pipe

支援以pipe 的机制读取跟trace 档案一样的内容, 并以Block 的机制读取, 直到有资料进来后才会返回, 每次资料读取后, 下一次读取, 就会读取到新的资料, 适合用来循序读取, 把Trace 内容依序读出来.

如果希望每次都读取到完整的 tracebuffer 内容, 就从trace 档案中读取, 反之, 如果是每次都要读到没读取到的资料, 就可以从trace_pipe 中读取.

trace_options

可以用来控制trace 要显示的资料内容.( ㄟ也必须要该Plug-inTracer 有支援对应的Options).

#cat trace_options

print-parent

nosym-offset

nosym-addr

noverbose

noraw

nohex

nobin

noblock

nostacktrace

nosched-tree

trace_printk

noftrace_preempt

nobranch

annotate

nouserstacktrace

nosym-userobj

noprintk-msg-only

context-info

nolatency-format

noglobal-clock

sleep-time

graph-time

控制方式为, 把Option 内容选择加上no ( 关闭) 或是移除no( 开启),

例如:

关闭print-parent

#echo noprint-parent > /data/debug/tracing/trace_options

重新cattrace_options 就会看到print-parent 变成noprint-parent

反之, 原本设定为nosym-addr, 透过

#echosym-addr > /data/debug/tracing/trace_options

重新cattrace_options 就会看到nosym-addr 变成 sym-addr

tracing_max_latency

用以显示刚才的 Tracer 进行 Latency 统计时 ( 例如 :irqsoff 或是 wakeup...etc), 最大的 Latency 数值为何 ( 单位为 us), 以提供核心设计者 , 找出系统中比较缺乏效率的部份 , 加以改善 .

#echo irqsoff > /data/debug/tracing/ current_tracer

#echo 1 > /data/debug/tracing/ tracing_enabled

… .dosomehting....sleep....

#echo 0 > /data/debug/tracing/ tracing_enabled

#more tracing_max_latency

7367

#more /data/debug/tracing/ trace

#tracer: irqsoff

#

#irqsoff latency trace v1.1.5 on 2.6.38.6

#------------------------------------------------- -------------------

#latency: 7367 us, #58/58, CPU#0 | (M:desktop VP:0, KP:0, SP:0 HP:0#P:1)

# -----------------

# | task: bash-1905 (uid:0 nice:0 policy:0 rt_prio:0)

# -----------------

# => started at: apic_timer_interrupt

# => ended at: call_on_stack

#

#

# _------=> CPU#

# / _-----=> irqs-off

# | / _----=> need-resched

# || / _---=> hardirq/softirq

# ||| / _--=> preempt-depth

# |||| /_--=> lock-depth

# |||||/ delay

# cmd pid |||||| time | caller

# / / |||||| / | /

...etc

buffer_size_kb

用来设定每个处理器要用多少记忆体空间当做TracerBuffer ( 单位为kbytes)( 一般而言一个Page 单位为4kbytes)( 每个处理器都会依据此值配置一样大的空间),

例如:

#cat buffer_size_kb

1408

就表示在笔者环境中为每个处理器用1.408MB 当做TracerBuffer.

这个值只有在current_tracer 内容为“ nop” 时才可以修改.( 也就是说要没有启用任何TracerPlug-in 才可以修改这个值)

tracing_cpumask

用来设定Tracer 要在哪个处理器上搜集资讯. 显示的为字串16 进位的字串. 在笔者单核ARM 的环境中执行如下

#cat tracing_cpumask

1

#

set_ftrace_filter

用在动态Ftrace 的组态下, 程式码在编译过程中被gcc-pg 置入呼叫mcount 函式的行为, 在支援动态Ftrace(Dynamic Ftrace) 的环境中, 只有在透过这档案设定的函式, 才会被纳入FunctionTrace 中.

设定TraceFuncton 开头为 account 与 run 的函式呼叫行为 , 如下指令所示

#echo >/debug/tracing/trace

#echo 'account*' 'run*' >/debug/tracing/set_ftrace_filter

#echo function >/debug/tracing/current_tracer

#echo 1 >/debug/tracing/tracing_enabled

#sleep 1

#echo 0 >/debug/tracing/tracing_enabled

#cat /debug/tracing/trace

#tracer: function

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1951 [000] 2602.286489: account_process_tick <-update_process_times

bash-1951 [000] 2602.286501: account_system_time <-account_process_tick

bash-1951 [000] 2602.286510: run_local_timers <-update_process_times

bash-1951 [000] 2602.286565: run_posix_cpu_timers <-update_process_times

bash-1951 [000] 2602.286605: run_timer_softirq <-__do_softirq

kworker/0:0-4 [000] 2602.287494: account_process_tick<-update_process_times

kworker/0:0-4 [000] 2602.287503: account_system_time <-account_process_tick

kworker/0:0-4 [000] 2602.287509: run_local_timers <-update_process_times

kworker/0:0-4 [000] 2602.287565: run_posix_cpu_timers<-update_process_times

kworker/0:0-4 [000] 2602.287605: run_timer_softirq <-__do_softirq

… .

在笔者的LinuxKernel 2.6.31 ARM 的设置中, 目前并没有支援HAVE_DYNAMIC_FTRACE, 也就是说在ARM 版本中这个档案属性会无法使用.(还请以各位手中的LinuxKernel 版本为主, 看是否有新的更新.)

set_ftrace_notrace

跟set_ftrace_filter 相反, 在动态Ftrace(DynamicFtrace) 的组态下, 那设定到这档案中的函式名称, 都会被取消呼叫mcount 的动作, 不纳入FunctionTrace 的机制中. 如果同一个函式同时被设定到set_ftrace_filter 与set_ftrace_notrace, 则该函式将会以set_ftrace_notrace 为主, 将不纳入Trace 中.

设定不要Trace 有包含cpu 与align 字元的函式名称, 如下指令所示

# echo '*cpu*' '*align*' >/debug/tracing/set_ftrace_notrace

#echo function >/debug/tracing/current_tracer

#echo 1 >/debug/tracing/tracing_enabled

#sleep 1

#echo 0 >/debug/tracing/tracing_enabled

#cat /debug/tracing/trace

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1951 [000] 2331.630911: calc_global_load <-do_timer

bash-1951 [000] 2331.630921: update_process_times <-tick_periodic

bash-1951 [000] 2331.630929: account_process_tick <-update_process_times

bash-1951 [000] 2331.630937: account_system_time <-account_process_tick

bash-1951 [000] 2331.630945: run_local_timers <-update_process_times

bash-1951 [000] 2331.630953: hrtimer_run_queues <-run_local_timers

bash-1951 [000] 2331.630967: __current_kernel_time <-hrtimer_run_queues

bash-1951 [000] 2331.630974: __get_wall_to_monotonic <-hrtimer_run_queues

bash-1951 [000] 2331.630984: _raw_spin_lock <-hrtimer_run_queues

bash-1951 [000] 2331.630995: raise_softirq <-run_local_timers

bash-1951 [000] 2331.631006: rcu_check_callbacks <-update_process_times

bash-1951 [000] 2331.631014: rcu_bh_qs <-rcu_check_callbacks

bash-1951 [000] 2331.631022: __rcu_pending <-rcu_check_callbacks

… .

在笔者的LinuxKernel 2.6.31 ARM 的设置中, 目前并没有支援HAVE_DYNAMIC_FTRACE, 也就是说在ARM 版本中这个档案属性会无法使用.(还请以各位手中的LinuxKernel 版本为主, 看是否有新的更新.)

set_ftrace_pid

设定Functiontracer 只针对特定的PID 进行搜集.( 如果不设定这个值, 而是对全系统搜集, 很有可能会让系统Hang 住=> 在我的ARM 环境中不设定PID 缩小范围, 就会Hang 住...@_@)

操作范例如下,

#cat/debug/tracing/set_ftrace_pid

no pid

#ps => 找一个要Trace ProcessID

USER PID PPID VSIZE RSS WCHAN PC NAME

… .

system 65 31 152436 25296 ffffffff afd0db4c S system_server

app_23 128 31 111664 20728 ffffffff afd0eb08 S com.android.launcher

… .

#echo 65 > /data/debug/tracing/set_ftrace_pid

#echo function > /data/debug/tracing/current_tracer

#echo 1 > /data/debug/tracing/tracing_enabled

… .dosomething....

#cat/data/debug/tracing/trace

… . 此时 trace 中就只会显示该 PID 的 tracing 结果 ...

available_filter_functions

这个档案会列出目前所有可以供 "set_ftrace_filter" 或 "set_ftrace_notrace" 用来设定过滤条件的函式名称 .

例如:

# more/debug/tracing/available_filter_functions

_stext

do_one_initcall

run_init_process

init_post

name_to_dev_t

match_dev_by_uuid

thread_saved_pc

get_wchan

prepare_to_copy

release_thread

copy_thread

start_thread

__show_regs

cpu_idle

setup_sigcontext

align_sigframe

signal_fault

sys_sigaltstack

restore_sigcontext

sys_sigaction

sys_rt_sigreturn

do_notify_resume

… .etc

介绍Ftrace 每个模组

Ftrace 的设计概念为提供Plug-inFramework 的机制, 随着核心模组的演进, 如果需要针对新的核心模组进行效能上的统计分析时, 就可以透过Plug-in 的方式, 撰写新的Ftrace 模组达成新的tracer 目的, 作为一个可延展性的Tracer 架构, 本段落会介绍Ftrace 主要支援的Tracer 模组, 这些模组的数量或是功能, 都有可能随着LinuxKernel 演进而有所改动( 例如:Kernel2.6.39 移除 KernelLock), 版本的更迭, 都请以最新的LinuxKernel Source Code 为主要依据.

名称

说明

Function tracer

设定路径为Kernelhacking --->Tracers --->Kernel Function Tracer

用以显示 ,Function 呼叫的流程与顺序

操作范例如下所示 :

#echo 1855 >/debug/tracing/set_ftrace_pid

=> 选择vsftpd PID(=1855)

#echo function >/debug/tracing/current_tracer

=> 选择FunctionTracer

#echo 1 >/debug/tracing/tracing_enabled

=> 之后透过另一台电脑经由FTP 连线到这主机来就可以记录到这DaemonFunction操作的行为

#echo 0 >/debug/tracing/tracing_enabled

#cat /debug/tracing/trace >/trace.txt

#echo nop >/debug/tracing/current_tracer

=> 移除Tracer

再来看trace.txt 中结果如下

#tracer: function

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

vsftpd-1964 [000] 272.754213: irq_exit <-smp_apic_timer_interrupt

vsftpd-1964 [000] 272.754222: do_softirq <-irq_exit

vsftpd-1964 [000] 272.754229: call_on_stack <-do_softirq

vsftpd-1964 [000] 272.754235: __do_softirq <-call_on_stack

vsftpd-1964 [000] 272.754241: __local_bh_disable <-__do_softirq

vsftpd-1964 [000] 272.754279: run_timer_softirq <-__do_softirq

vsftpd-1964 [000] 272.754302: hrtimer_run_pending <-run_timer_softirq

vsftpd-1964 [000] 272.754324: _raw_spin_lock_irq <-run_timer_softirq

vsftpd-1964 [000] 272.754347: rcu_bh_qs <-__do_softirq

vsftpd-1964 [000] 272.754378: rcu_process_callbacks <-__do_softirq

vsftpd-1964 [000] 272.754400: __rcu_process_callbacks<-rcu_process_callbacks

vsftpd-1964 [000] 272.754422: force_quiescent_state<-__rcu_process_callbacks

vsftpd-1964 [000] 272.754444: rcu_gp_in_progress <-force_quiescent_state

… ...

可以看到在vsftpd 对应处理Client 需求的行程运作时,LinuxKernel 这所对应调用的函式行为与时间值.

Dynamicselection of functions

设定路径为Kernelhacking --->Tracers --->enable/disable ftrace tracepointsdynamically

由于对全部FunctionTracing 的成本很高, 以笔者所用的ARM 环境而言, 几乎会导致系统无法正常的反应(mmm, 如果你是用 ARMCortex A 系列的处理器 , 应该就会很顺了 ...) ,Ftrace也提供了动态选择Function(Dynamicselection of functions) 进行Tracing 的机制, 以笔者所验证的LinuxKernel 2.6.31 而言, 目前在ARM 平台尚未支援这机制, 而X86 平台则可以支援.

使用范例如下的写法, 选择只追踪函式名称包含有spin 与process 字串的LinuxKernel Function 呼叫

#echo '*spin*' '*process*'> /debug/tracing/set_ftrace_filter

执行结果如下所示

#tracer: function

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

vsftpd-1855 [000] 5064.651690: _raw_spin_lock_bh <-lock_sock_nested

vsftpd-1855 [000] 5064.651739: _raw_spin_lock_bh <-release_sock

vsftpd-1855 [000] 5064.651760: _raw_spin_unlock_bh <-release_sock

vsftpd-1855 [000] 5064.651780: _raw_spin_lock_bh <-lock_sock_nested

vsftpd-1855 [000] 5064.651800: _raw_spin_lock_bh <-release_sock

vsftpd-1855 [000] 5064.651819: _raw_spin_unlock_bh <-release_sock

vsftpd-1855 [000] 5064.651840: _raw_spin_lock <-fd_install

vsftpd-1855 [000] 5064.651871: _raw_spin_lock_irq <-sigprocmask

vsftpd-1855 [000] 5064.651924: _raw_spin_lock_irq <-sigprocmask

vsftpd-1855 [000] 5064.651974: _raw_spin_lock <-tick_periodic

vsftpd-1855 [000] 5064.652009: update_process_times <-tick_periodic

vsftpd-1855 [000] 5064.652017: account_process_tick <-update_process

_times

vsftpd-1855 [000] 5064.652034: _raw_spin_lock <-hrtimer_run_queues

vsftpd-1855 [000] 5064.652082: _raw_spin_lock <-scheduler_tick

vsftpd-1855 [000] 5064.652164: _raw_spin_lock_irq <-run_timer_softir

q

vsftpd-1855 [000] 5064.652241: copy_process <-do_fork

vsftpd-1855 [000] 5064.652278: _raw_spin_lock <-cache_alloc_refill

… ..

就只会看到有包含spin 与process 字串的函式呼叫,

接下来, 如果要把有包含raw 与times 字元的函式过滤掉, 可透过如下设定

# echo '*raw*' '*times*' >/debug/tracing/set_ftrace_notrace

执行结果如下所示

#tracer: function

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

vsftpd-2099 [000] 5220.419859: tcp_rcv_state_process <-tcp_v4_do_rcv

vsftpd-2099 [000] 5220.419996: account_process_tick <-update_process_times

vsftpd-2099 [000] 5220.420520: tcp_child_process <-tcp_v4_do_rcv

vsftpd-2099 [000] 5220.420542: tcp_rcv_state_process <-tcp_child_process

vsftpd-2099 [000] 5220.420913: wake_up_process <-wake_up_worker

vsftpd-2099 [000] 5220.421737: account_process_tick <-update_process_times

vsftpd-1855 [000] 5220.422045: account_process_tick <-update_process_times

vsftpd-1855 [000] 5220.422358: copy_process <-do_fork

vsftpd-1855 [000] 5220.422953: account_process_tick <-update_process_times

vsftpd-2099 [000] 5220.423830: tcp_rcv_state_process <-tcp_v4_do_rcv

vsftpd-2099 [000] 5220.423903: kick_process <-signal_wake_up

vsftpd-2099 [000] 5220.423961: account_process_tick <-update_process_times

vsftpd-2099 [000] 5220.424257: kick_process <-signal_wake_up

… ..

可以看到最后的结果, 就是会包含有spin 与process 字串的函式呼叫, 并且把其中有包括raw与times 字串的函式呼叫过滤掉.

Functiongraph tracer

设定路径为Kernelhacking --->Tracers --->Kernel Function Tracer --->KernelFunction Graph Tracer

以笔者所验证的LinuxKernel 2.6.31 而言, 目前在ARM 平台尚未支援这机制, 而X86 平台则可以支援.

操作范例如下所示 ,

#echo '*' >/debug/tracing/set_ftrace_filter

=> 恢复对所有函式的Tracing

#echo function_graph >/debug/tracing/current_tracer

#echo 1 >/debug/tracing/tracing_enabled

=> 让FTP Client 连进来

# echo 0 >/debug/tracing/tracing_enabled

执行结果如下所示

#tracer: function_graph

#

# TIME CPU DURATION FUNCTION CALLS

# | | | | | | | |

0) 7.525 us | } /* idle_cpu */

0)+ 36.032 us | } /* irq_enter */

0) | tick_handle_periodic() {

0) | tick_periodic() {

0) | do_timer() {

0)+ 16.017 us | update_wall_time();

0) 6.749 us | calc_global_load();

0)+ 43.684 us | }

0) | account_process_tick() {

0) 6.852 us | account_system_time();

0)+ 20.041 us | }

0) | run_local_timers() {

0) | hrtimer_run_queues() {

0) 6.243 us | __current_kernel_time();

0) 6.183 us | __get_wall_to_monotonic();

0)+ 35.781 us | }

0) 9.591 us | raise_softirq();

0)+ 65.198 us | }

0) | rcu_check_callbacks() {

0) 6.357 us | idle_cpu();

0) | __rcu_pending() {

0) 6.199 us | rcu_gp_in_progress();

0) 6.218 us | cpu_has_callbacks_ready_to_invoke();

0) 6.265 us | cpu_needs_another_gp();

0) 6.175 us | rcu_gp_in_progress();

0)+ 59.513 us | }

0) 6.867 us | raise_softirq();

0)+ 98.833 us | }

0) 6.292 us | printk_tick();

0) | scheduler_tick() {

0)+ 11.142 us | ktime_get();

0) 7.172 us | update_rq_clock();

0) | sched_avg_update() {

0) 6.353 us | sched_avg_period();

0)+ 19.685 us | }

0) | task_tick_fair() {

0) 6.826 us | update_cu​​rr();

0) | sched_slice() {

0) 6.851 us | calc_delta_mine();

0)+ 20.522 us | }

原本结果显示的是时间差, 也可以透过 trace_options 选择显示绝对时间值

# echo funcgraph-abstime>/debug/tracing/trace_options

执行结果如下所示

#tracer: function_graph

#

# TIME CPU DURATION FUNCTION CALLS

# | | | | | | | |

8919.132197| 0) ! 201.630 us | } /* __do_softirq */

8919.132218| 0) ! 265.733 us | } /* do_softirq */

8919.132229| 0) ! 297.422 us | } /* irq_exit */

------------------------------------------

0) vsftpd-2125 => <...>-1855

------------------------------------------

8919.132798| 0) + 50.964 us | irq_enter();

8919.132908| 0) + 25.462 us | raise_softirq();

8919.133053| 0) | irq_exit() {

8919.133076| 0) | do_softirq() {

8919.133095| 0) | __do_softirq() {

8919.133153| 0) + 43.064 us | run_timer_softirq();

8919.133245| 0) ! 148.201 us | }

8919.133260| 0) ! 185.542 us | }

8919.133272| 0) ! 221.503 us | }

8919.134684| 0) + 47.945 us | irq_enter();

8919.134785| 0) + 19.704 us | raise_softirq();

8919.134911| 0) | irq_exit() {

8919.134931| 0) | do_softirq() {

8919.134949| 0) | __do_softirq() {

8919.135019| 0) + 17.437 us | irq_enter();

8919.135080| 0) + 18.143 us | raise_softirq();

8919.135165| 0) + 19.679 us | irq_exit();

8919.135230| 0) + 39.134 us | run_timer_softirq();

8919.135307| 0) + 33.181 us | run_timer_softirq();

8919.135384| 0) ! 434.587 us | }

8919.135398| 0) ! 468.233 us | }

8919.135408| 0) ! 500.772 us | }

------------------------------------------

0) <...>-1855 => vsftpd-2125

------------------------------------------

8919.135778| 0) + 43.128 us | irq_enter();

8919.135900| 0) + 18.773 us | raise_softirq();

8919.136019| 0) | irq_exit() {

8919.136037| 0) | do_softirq() {

8919.136052| 0) | __do_softirq() {

8919.136100| 0) + 37.945 us | run_timer_softirq();

8919.136179| 0) ! 125.562 us | }

8919.136192| 0) ! 155.517 us | }

8919.136201| 0) ! 184.853 us | }

Latency Tracing

1,irqsoff tracer

设定路径为Kernelhacking --->Tracers --->Interrupts-off Latency Tracer

主要用来Tracing 中断被关闭的行为, 并且会把关闭最久的时间与对应的呼叫动作显示出来, 提供系统效能分析的判断之用, 例如: 当在中断中做了过多I/O 的行为, 就会对系统效能造成影响, 透过分析可以把这类设计移到Bottom-Half(HISR) 中处理, 减少系统把中断关闭所导致的效能影响 .( 属于 I/O 的等待应该放到系统闲置的时间才处理 , 在中断里要越快结束越好 , 把处理器执行时间让给优先级高的 Task).

执行范例如下所示

# echo nop >current_tracer

# echo irqsoff> current_tracer

# echo 1 >tracing_enabled

# sleep 3

# echo 0>tracing_enabled

显示结果如下

#tracer: irqsoff

#

#irqsoff latency trace v1.1.5 on 2.6.38.6

#------------------------------------------------- -------------------

#latency: 10747 us, #123/123, CPU#0 | (M:desktop VP:0, KP:0, SP:0HP:0 #P:1)

# -----------------

# | task: vsftpd-1961 (uid:0 nice:0 policy:0 rt_prio:0)

# -----------------

# => started at: __make_request

# => ended at: __blk_run_queue

#

#

# _------=> CPU#

# / _-----=> irqs-off

# | / _----=> need-resched

# || / _---=> hardirq/softirq

# ||| / _--=> preempt-depth

# |||| /_--=> lock-depth

# |||||/ delay

# cmd pid |||||| time | caller

# / / |||||| / | /

vsftpd-1961 0dN​​... 23us+: _raw_spin_lock_irq <-__make_request

vsftpd-1961 0dN​​... 103us+: cpu_coregroup_mask <-__make_request

vsftpd-1961 0dN​​... 118us!: elv_queue_empty <-__make_request

vsftpd-1961 0dN​​... 997us+: cfq_queue_empty <-elv_queue_empty

vsftpd-1961 0dN​​... 1055us+: blk_plug_device <-__make_request

vsftpd-1961 0dN​​... 1109us!: mod_timer <-blk_plug_device

vsftpd-1961 0dN​​... 1216us+: lock_timer_base <-mod_timer

vsftpd-1961 0dN​​... 1231us+: _raw_spin_lock_irqsave <-lock_timer_base

vsftpd-1961 0dN​​... 1253us+: internal_add_timer <-m​​od_timer

vsftpd-1961 0dN​​... 1270us+: _raw_spin_unlock_irqrestore <-mod_timer

vsftpd-1961 0dN​​... 1369us!: drive_stat_acct <-__make_request

vsftpd-1961 0dN​​... 1480us!: disk_map_sector_rcu <-drive_stat_acct

vsftpd-1961 0dN​​... 1713us+: part_round_stats <-drive_stat_acct

vsftpd-1961 0dN​​... 1782us+: part_round_stats_single <-part_round_stats

vsftpd-1961 0dN​​... 1832us!: part_round_stats_single <-part_round_stats

vsftpd-1961 0dN​​... 1938us+: __elv_add_request <-__make_request

vsftpd-1961 0dN​​... 1993us!: elv_insert <-__elv_add_request

vsftpd-1961 0dN​​... 2100us!: elv_rqhash_add <-elv_insert

vsftpd-1961 0dN​​... 2259us+: cfq_insert_request <-elv_insert

vsftpd-1961 0dN​​... 2330us+: cfq_init_prio_data <-cfq_insert_request

vsftpd-1961 0dN​​... 2421us+: cfq_add_rq_rb <-cfq_insert_request

vsftpd-1961 0dN​​... 2489us!: elv_rb_add <-cfq_add_rq_rb

vsftpd-1961 0dN​​... 2637us+: cfq_resort_rr_list <-cfq_add_rq_rb

vsftpd-1961 0dN​​... 2689us+: cfq_service_tree_add <-cfq_resort_rr_list

vsftpd-1961 0dN​​... 272​​4us+: cfqq_type <-cfq_service_tree_add

… ..

vsftpd-1961 0dN​​... 10463us+: _raw_spin_lock_irqsave <-lock_timer_base

vsftpd-1961 0dN​​... 10476us+: internal_add_timer <-m​​od_timer

vsftpd-1961 0dN​​... 10490us+: _raw_spin_unlock_irqrestore <-mod_timer

vsftpd-1961 0dN​​... 10562us!: _raw_spin_lock <-scsi_request_fn

vsftpd-1961 0dN​​... 10736us+: scsi_request_fn <-__blk_run_queue

vsftpd-1961 0dN​​... 10760us+: trace_hardirqs_on <-__blk_run_queue

… .

其中, 中间六个属性数值意义分别为

1,CPU : 该任务所运作的CPUID

2,irqs-off : 'd'= 关闭中断,'.'= 中断没关闭,'X'= 该平台不支援读取IRQFlag

3,need-resched:'N'=need_resched 被设置( 表示行程会重新排程),'.'= 前项不成立.

4,hardirq/softirq:'H'= 在软体中断进行过程中, 发生的硬体中断, 'h' = 正在硬体中断处理中, 's'= 正在软体中断处理中,'.' = 一般行程运作中

5,preempt-depth: 表示preempt_disabled 的Level

6,lock-depth:

接下来属于time 的栏位, 单位为us, 代表的是从呼叫的函式到被呼叫的函式所经过的时间,这段时间如果超过preempt_mark_thresh(default 100) 的值, 时间后面就会标示' !', 如果超过1个us, 就会标示'+', 如果小于或等于1us 则部会标示任何符号.

以这例子来说, 起点会在函式__make_request( 实作在block/blk-core.c 中) 呼叫spin_lock_irq关闭硬体中断, 最后在函式__blk_run_queue( 实作在block/blk-core.c 中) 后, 恢复硬体中断运作.

=> 恢复中断的流程是呼叫函式trace_hardirqs_on( 实作在kernel/lockdep.c ), 再呼叫到函式trace_hardirqs_on_caller( 实作在kernel/lockdep.c ), 完成恢复硬体中断的动作.

2,Wakeup tracer

设定路径为Kernelhacking --->Tracers --->Scheduling Latency Tracer

可用以显示 Real-TimeTask 取得执行权所需等待的时间 , 操作范例如下所示

# echo wakeup >current_tracer

# echo 1 >tracing_enabled

# chrt -f 10 ps ==>  real-Time 权限 10 执行 ps 指令

执行结果如下

#tracer: wakeup

#

#wakeup latency trace v1.1.5 on 2.6.38.6

#------------------------------------------------- -------------------

#latency: 5961 us, #149/149, CPU#0 | (M:desktop VP:0, KP:0, SP:0HP:0 #P:1)

# -----------------

# | task: kworker/0:1-9481 (uid:0 nice:0 policy:0 rt_prio:0)

# -----------------

#

# _------=> CPU#

# / _-----=> irqs-off

# | / _----=> need-resched

# || / _---=> hardirq/softirq

# ||| / _--=> preempt-depth

# |||| /_--=> lock-depth

# |||||/ delay

# cmd pid |||||| time | caller

# / / |||||| / | /

gam_serv-1892 0dNs.. 15us!: 1892:139:R + [000] 9481:120:R kworker/0:1

gam_serv-1892 0dNs.. 171us+: wake_up_process <-wake_up_worker

gam_serv-1892 0dNs.. 187us+: check_preempt_curr <-try_to_wake_up

gam_serv-1892 0dNs.. 199us+​​: check_preempt_wakeup <-check_preempt_curr

gam_serv-1892 0dNs.. 214us+: update_cu​​rr <-check_preempt_wakeup

… .

gam_serv-1892 0.N... 5392us+: mutex_lock <-inotify_poll

gam_serv-1892 0.N... 5416us+: _cond_resched <-mutex_lock

gam_serv-1892 0.N... 5431us!: __cond_resched <-_cond_resched

gam_serv-1892 0.N... 5668us+: schedule <-__cond_resched

gam_serv-1892 0.N... 5697us+: rcu_note_context_switch <-schedule

gam_serv-1892 0.N... 5727us+: rcu_sched_qs <-rcu_note_context_switch

gam_serv-1892 0.N... 5755us+: _raw_spin_lock_irq <-schedule

gam_serv-1892 0dN... 5785us+: update_rq_clock <-schedule

gam_serv-1892 0dN... 5798us+: put_prev_task_fair <​​-schedule

gam_serv-1892 0dN... 5805us+: update_cu​​rr <-put_prev_task_fair

gam_serv-1892 0dN... 5812us+: check_spread <-put_prev_task_fair

gam_serv-1892 0dN... 5821us+: __enqueue_entity <-put_prev_task_fair

gam_serv-1892 0dN... 5839us+: pick_next_task_fair <​​-schedule

gam_serv-1892 0dN... 5845us+: __pick_next_entity <-pick_next_task_fair

gam_serv-1892 0dN... 5853us+: clear_buddies <-pick_next_task_fair

gam_serv-1892 0dN... 5862us+: set_next_entity <-pick_next_task_fair

gam_serv-1892 0dN... 5869us+: update_stats_wait_end <-set_next_entity

gam_serv-1892 0dN... 5880us+: __dequeue_entity <-set_next_entity

gam_serv-1892 0d.... 5937us+: schedule <-__cond_resched

gam_serv-1892 0d.... 5943us : 1892:139:R ==> [000] 9481:120:Rkworker/0:1

根据上述的结果, 我们可以看到花了约5961us 从由kworker 交出执行权到重新取得执行权,上面的列表中, 包括了超过1us 的函式呼叫标示为'+', 与超过100us 的函式呼叫标示为'!', 以如下的行为来说, 就是从函式set_next_entity 呼叫函式update_stats_wait_end 到函式set_next_entity 呼叫函式__dequeue_entity, 中间间隔了5880-5869=11us 的时间( 因为超过1us 所以标示为'+')

gam_serv-1892 0dN...5869us+: update_stats_wait_end <-set_next_entity

gam_serv-1892 0dN...5880us+: __dequeue_entity <-set_next_entity

或是

gam_serv-1892 0.N...5431us!: __cond_resched <-_cond_resched

gam_serv-1892 0.N...5668us+: schedule <-__cond_resched

Task Context-SwitchSchedule tracer

设定路径为Kernelhacking --->Tracers --->Scheduling Latency Tracer

用以解析 TaskContext-Switch 的资讯, 可以参考如下的范例

# echo >/data/debug/tracing/trace => 清空trace 内容

# echo sched_switch >/data/debug/tracing/current_tracer

# echo 1 >/data/debug/tracing/tracing_enabled

# sleep 1

# echo 0 >/data/debug/tracing/tracing_enabled

#cat/data/debug/tracing/trace

#tracer: sched_switch

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

events/0-4 [000] 1044.598519: 4:115:S ==> [000] 87:120:RAlarmManager

AlarmManager-87 [000] 1044.598749: 87:120:R + [000] 69:118:SActivityManager

AlarmManager-87 [000] 1044.599057: 87:120:R ==> [000] 69:118:RActivityManager

ActivityManager-69 [000] 1044.599411: 69:118:S ==> [000] 87:120:RAlarmManager

AlarmManager-87 [000] 1044.599643: 87:120:R + [000] 69:118:SActivityManager

AlarmManager-87 [000] 1044.599957: 87:120:R ==> [000] 69:118:RActivityManager

ActivityManager-69 [000] 1044.600498: 69:118:S ==> [000] 87:120:RAlarmManager

AlarmManager-87 [000] 1044.600929: 87:120:R + [000] 69:118:SActivityManager

AlarmManager-87 [000] 1044.601509: 87:120:R ==> [000] 69:118:RActivityManager

ActivityManager-69 [000] 1044.602102: 69:118:R + [000] 72:120:SProcessStats

ActivityManager-69 [000] 1044.604484: 69:118:R + [000] 67:118:Ser.ServerThread

ActivityManager-69 [000] 1044.604661: 69:118:R ==> [000] 67:118:Rer.ServerThread

er.ServerThread-67 [000] 1044.605145: 67:118:S ==> [000] 72:120:RProcessStats

ProcessStats-72 [000] 1044.611966: 72:120:R ==> [000] 69:118:RActivityManager

如上所示, 所列出的数据分别包含TaskID/Name, 运作的处理器ID( 供多核心的环境分析),每次触发的时间值, 如下以上述例子做一些说明

AlarmManager-87 [000] 1044.600929: 87:120:R + [000] 69:118:SActivityManager

=>PID87, 执行优先级120,Task 状态为Running, 运作在处理器AlarmManager, 会唤醒PID69, 执行优先级118,Task 状态为Sleep 运作在处理器ActivityManager

AlarmManager-87 [000] 1044.601509: 87:120:R ==> [000] 69:118:RActivityManager

=>PID87, 执行优先级120,Task 状态为Running, 运作在处理器AlarmManager, 会把执行权切换(Context-Switch) PID69, 执行优先级118,Task 状态为Running 运作在处理器ActivityManager

ActivityManager-69 [000] 1044.602102: 69:118:R + [000] 72:120:SProcessStats

=>PID69, 执行优先级118,Task 状态为Running, 运作在处理器ActivityManager,会唤醒PID72, 执行优先级120,Task 状态为Sleep 运作在处理器ProcessStats

ActivityManager-69 [000] 1044.604484: 69:118:R + [000] 67:118:Ser.ServerThread

=>PID69, 执行优先级118,Task 状态为Running, 运作在处理器ActivityManager,会唤醒PID67, 执行优先级118,Task 状态为Sleep 运作在处理器er.ServerThread

ActivityManager-69 [000] 1044.604661: 69:118:R ==> [000] 67:118:Rer.ServerThread

=>PID69, 执行优先级118,Task 状态为Running, 运作在处理器ActivityManager,会把执行权切换(Context-Switch) PID67, 执行优先级118,Task 状态为Running 运作在处理器er.ServerThread

有关TaskPriority 参考如下表

技术部分也可以参考笔者这篇文章Linux 2.4/2.6 核心排程机制剖析”http://loda.hala01.com/2009/04/linux-2426-%e6%a0%b8%e5%bf%83 %e6%8e%92%e7%a8%8b%e6%a9%9f%e5%88%b6%e5%89%96%e6%9e%90/”)

Kernel task priority

说明

0 to 99

Real-Time priority 99 to0

100 to 139

对应到TaskNice Value -20 to 19

140

idle task priority

有关Task 状态参考如下表

状态符号

说明

R (Running)

Wants to run, may not

S(Sleep)ctually be running

Processis waiting to be woken up (handles signals)

D(Disk sleep)

(uninterruptiblesleep) Process must be woken up (ignores signals)

T(Stopped)

Processsuspended

t(Traced)

Processis being traced (with something like gdb)

Z(Zombie)

Processwaiting to be cleaned up

X (U nknown)

Block Device Tracer

设定路径为Kernelhacking --->Tracers --->Support for tracing block ioactions

可以用来监控储存装置的使用状况, 与行为

例如笔者要启动BlockDevice Tracer 监控目前正在编译程式码的储存装置sda2, 如下操作指令

#echo 0 >/debug/tracing/tracing_enabled

#echo 1>/sys/block/sda/sda2/trace/enable

# echo blk >current_tracer

#echo 1 >/debug/tracing/tracing_enabled

… .. 执行编译的行为....

#echo 0 >/debug/tracing/tracing_enabled

#echo 0>/sys/block/sda/sda2/trace/enable

再来检视trace 中的结果如下所示,

#tracer: blk

#

mv-21550[000] 6663.719323: 8,2 m N cfq21550 sl_used=4 disp=1charge=4 iops=0 sect=8

mv-21550[000] 6663.719341: 8,2 m N cfq21550 del_from_rr

mv-21550[000] 6663.719367: 8,2 m N cfq21550 put_queue

cc1-21557[000] 6663.920569: 8,2 AR 221728392 + 56 <- (253,0)221728008

cc1-21557[000] 6663.920576: 8,2 AR 221937237 + 56 <- (8,2)221728392

cc1-21557[000] 6663.920577: 8,2 QR 221937237 + 56 [cc1]

cc1-21557[000] 6663.920751: 8,2 m N cfq21557 alloced

cc1-21557[000] 6663.920816: 8,2 GR 221937237 + 56 [cc1]

cc1-21557[000] 6663.920875: 8,2 PN [cc1]

cc1-21557[000] 6663.921844: 8,2 IR 221937237 + 56 [cc1]

cc1-21557[000] 6663.921870: 8,2 m N cfq21557 insert_request

cc1-21557[000] 6663.921906: 8,2 m N cfq21557 add_to_rr

as-21558[000] 6663.923906: 8,2 UT N [as] 1

kworker/0:1-16318[000] 6663.924047: 8,2 UN [kworker/0:1] 1

kworker/0:1-16318[000] 6663.924102: 8,2 m N cfq workload slice:100

kworker/0:1-16318[000] 6663.924146: 8,2 m N cfq21557 set_active wl_prio:0wl_type:2

… ..............

ld-21578[000] 6665.826767: 8,2 UN [ld] 0

ld-21578[000] 6665.826865: 8,2 UN [ld] 0

ld-21578[000] 6665.829130: 8,2 UN [ld] 0

ld-21578[000] 6665.831853: 8,2 UN [ld] 0

ld-21578[000] 6665.839538: 8,2 m N cfq21578 put_queue

<...>-21532[000] 6665.902373: 8,2 m N cfq21532 put_queue

make-21583[000] 6665.920115: 8,2 AR 221728880 + 8 <- (253,0)221728496

make-21583[000] 6665.920121: 8,2 AR 221937725 + 8 <- (8,2)221728880

make-21583[000] 6665.920123: 8,2 QR 221937725 + 8 [make]

make-21583[000] 6665.920468: 8,2 m N cfq21583 alloced

make-21583[000] 6665.920646: 8,2 GR 221937725 + 8 [make]

make-21583[000] 6665.920691: 8,2 PN [make]

make-21583[000] 6665.920741: 8,2 IR 221937725 + 8 [make]

make-21583[000] 6665.920770: 8,2 m N cfq21583 insert_request

make-21583[000] 6665.920800: 8,2 m N cfq21583 add_to_rr

make-21583[000] 6665.920861: 8,2 UN [make] 1

make-21583[000] 6665.920897: 8,2 m N cfq workload slice:100

make-21583[000] 6665.920923: 8,2 m N cfq21583 set_active wl_prio:0wl_type:2

… ..............

Branch tracer

1,Trace likely/unlikely profiler

设定路径为Kernelhacking --->Tracers --->Branch Profiling --->Tracelikely/unlikely profiler

用以显示 Kernel 基于 likely/unlikely 的 Run-Time 统计结果

操作范例如下所示

#echo 0 >tracing_enabled

# echo branch >current_tracer

#echo 1 >tracing_enabled

… ..do something.....

#echo 0 >tracing_enabled

查看结果如下

#tracer: branch

#

# TASK-PID CPU# TIMESTAMP CORRECT FUNC:FILE:LINE

# | | | | | |

<idle>-0 [000] 55415.397835: [ ok ] read_seqretry:seqlock.h:110

<idle>-0 [000] 55415.397848: [ ok ] native_sched_clock:tsc.c:55

<idle>-0 [000] 55415.397859: [ ok ] native_sched_clock:tsc.c:55

… .

<idle>-0 [000] 55415.398682: [ ok ] __local_bh_enable:softirq.c:138

<idle>-0 [000] 55415.398695: [ ok ]update_wall_time:timekeeping.c:789

<idle>-0 [000] 55415.398710: [ MISS ]timekeeping_adjust:timekeeping.c:711

<idle>-0 [000] 55415.398725: [ ok ]update_wall_time:timekeeping.c:839

<idle>-0 [000] 55415.398734: [ ok ]update_wall_time:timekeeping.c:859

… ..

<idle>-0 [000] 55415.401654: [ ok ]update_wall_time:timekeeping.c:789

<idle>-0 [000] 55415.401668: [ MISS ]timekeeping_adjust:timekeeping.c:711

<idle>-0 [000] 55415.401677: [ ok ]update_wall_time:timekeeping.c:839

<idle>-0 [000] 55415.401687: [ ok ]update_wall_time:timekeeping.c:859

… ..

针对MISS 比较多的段落写法, 我们可以透过修改likely/unlikely 的配置,让gcc__builtin_expect 的函式发挥作用, 把真正的热区放在循序的执行过程中, 非热区放在需要Jump/Branch 的位址, 减少处理器Pipeline 被Flush 的机会, 从而也可以让系统的运作效率更佳.

2,Profile all if conditionals

设定路径为Kernelhacking --->Tracers --->Branch Profiling --->Profileall if conditionals

操作范例如下所示

#echo 0 >tracing_enabled

# echo branch >current_tracer

#echo 1 >tracing_enabled

… ..do something.....

#echo 0 >tracing_enabled

查看结果如下

#tracer: branch

#

# TASK-PID CPU# TIMESTAMP CORRECT FUNC:FILE:LINE

# | | | | | |

<...>-1806 [000] 297.131833: [ ok ] native_sched_clock:tsc.c:55

<...>-1806 [000] 297.131843: [ ok ] native_sched_clock:tsc.c:55

<...>-1806 [000] 297.131850: [ ok ] sched_clock_local:sched_cloc

kc:149

<...>-1806 [000] 297.131860: [ ok ] sched_clock_cpu:sched_clock.

c:219

<...>-1806 [000] 297.131866: [ ok ] sched_clock_cpu:sched_clock.

c:219

<...>-1806 [000] 297.131873: [ ok ] sched_clock_cpu:sched_clock.

c:224

<...>-1806 [000] 297.131879: [ ok ] native_sched_clock:tsc.c:55

<...>-1806 [000] 297.131886: [ ok ] sched_clock_local:sched_cloc

kc:149

<...>-1806 [000] 297.131896: [ ok ] update_cu​​rr:sched_fair.c:576

<...>-1806 [000] 297.131903: [ ok ] calc_delta_fair:sched_fair.c

:477

<...>-1806 [000] 297.131913: [ ok ] trace_sched_stat_runtime:sch

ed.h:363:

<...>-1806 [000] 297.131922: [ ok ] __sched_period:sched_fair.c:496

<...>-1806 [000] 297.131928: [ ok ] sched_slice:sched_fair.c:521

<...>-1806 [000] 297.131935: [ MISS ] calc_delta_mine:sched.c:1327

<...>-1806 [000] 297.131942: [ ok ] resched_task:sched.c:1158

<...>-1806 [000] 297.131949: [ MISS ] test_tsk_need_resched:sched.h:2378

<...>-1806 [000] 297.131956: [ ok ]perf_event_task_tick:perf_event.c:1828

<...>-1806 [000] 297.131963: [ ok ]perf_event_task_tick:perf_event.c:1828

<...>-1806 [000] 297.131970: [ MISS ]trigger_load_balance:sched_fair.c:3989

<...>-1806 [000] 297.131978: [ ok ]run_posix_cpu_timers:posix-cpu-timers.c:1312

<...>-1806 [000] 297.131995: [ ok ] __local_bh_disable:softirq.c:98

<...>-1806 [000] 297.132002: [ ok ] __local_bh_disable:softirq.c:98

<...>-1806 [000] 297.132032: [ ok ] trace_softirq_entry:irq.h:117

<...>-1806 [000] 297.132054: [ ok ] trace_softirq_exit:irq.h:131

Kernel memory tracer

内存tracer 主要用来跟踪slaballocator 的分配情况。包括kfree ,kmem_cache_alloc 等API的调用情况,用户程序可以根据tracer 收集到的信息分析内部碎片情况,找出内存分配最频繁的代码片断,等等

设定路径为Kernelhacking --->Tracers --->Trace SLAB allocations

操作范例如下所示

# echo 0 > tracing_enabled

# echo kmemtrace >current_tracer

# echo 1 > tracing_enabled

# echo 0 > tracing_enabled

… .etc

Workqueue statisticaltracer

这是一个statistictracer ,主要用来统计系统所有workqueue 现况 , 可以知道有多少 work 被插入到 queue 中 , 以及有多 ​​少被执行 , 与 work 的名称 , 可用以提供开发端对于 workqueue机制实现的参考 .

设定路径为Kernelhacking --->Tracers --->Traceworkqueues, 系统启动后, 可以到/data/debug/tracing/trace_stat/workqueues 下, 查看内容, 如下所示

# CPU INSERTED EXECUTED NAME

# | | | |

0 2139 2139 events/0

0 0 0 khelper

0 0 0 suspend

0 1 1 kblockd/0

0 1 1 kmmcd

0 0 0 aio/0

0 0 0 crypto/0

0 0 0 rpciod/0

Profiling

1,unlikely/likely

可用以显示 likely/unlikely 条件判断式的统计结果

统计结果位于/debug/tracing/trace_stat/branch_annotated

如下所示

correctincorrect % Function File Line

---------------- - -------- ---- ----

0 1 100 tcp_synack_options tcp_output.c 535

0 1 100 tcp_synack_options tcp_output.c 529

0 1 100 tcp_synack_options tcp_output.c 524

0 9 100 tcp_options_write tcp_output.c 397

0 3622 100 tcp_established_options tcp_output.c 562

0 7 100 sys_inotify_add_watch inotify_user.c 750

0 7 100 fput_light file.h 29

0 17920 100 get_futex_key futex.c 269

0 28 100 clocksource_adjust timekeeping.c 472

0 4 100 blocking_notifier_chain_regist notifier.c 220

0 1 100 signal_pending sched.h 2251

0 6849 100 trace_workqueue_execution workqueue.h 53

0 8 100 trace_workqueue_creation workqueue.h 76

0 6849 100 trace_workqueue_insertion workqueue.h 31

0 38 100 yield_task_fair sched_fair.c 1016

0 25617 100 _pick_next_task_rt sched_rt.c 1041

0 92856 100 sched_info_switch sched_stats.h 269

0 85509 100 sched_info_queued sched_stats.h 222

0 54733 100 sched_info_dequeued sched_stats.h 177

0 1 100 consistent_init dma-mapping.c 470

9 1710 99 tcp_options_write tcp_output.c 396

2 354 99 disk_put_part genhd.h 209

606 67234 99 fput_light file.h 29

35 9260 99 trace_kmalloc kmem.h 79

313 12957 97 fput_light file.h 29

542 10337 95 sys_gettimeofday time.c 111

70 770 91 blk_update_request blk-core.c 1968

28116 135585 82 fget_light file_table.c 332

2 8 80 trace_kmalloc kmem.h 79

24893 53424 68 fput_light file.h 29

4547 8951 66 need_resched sched.h 2273

750 1338 64 fput_light file.h 29

15323 25008 62 wakeup_gran sched_fair.c 1382

44 61 58 mmdrop sched.h 2024

821 1006 55 pskb_trim_rcsum skbuff.h 1690

84797 95325 52 calc_delta_fair sched_fair.c 400

1 1 50 remap_pte_range memory.c 1634

270 270 50 isolate_lru_pages vmscan.c 926

32028 27195 45 rmqueue_bulk page_alloc.c 907

1970 1505 43 copy_pte_range memory.c 618

24549 17984 42 trace_kfree kmem.h 208

2,brancheall

可用以显示所有 if 条件判断式的统计结果

统计结果位于/debug/tracing/trace_stat/branch_all

如下所示

miss hit % Function File Line

---------------- - -------- ---- ----

0 1 100 i386_start_kernel head32.c 50

1 0 0 reserve_ebda_region head.c 51

1 0 0 reserve_ebda_region head.c 47

0 1 100 reserve_ebda_region head.c 42

0 0 X nrcpus main.c 167

0 0 X maxcpus main.c 178

1098 0 0 do_one_initcall main.c 773

1098 0 0 do_one_initcall main.c 769

1098 0 0 do_one_initcall main.c 765

1098 0 0 do_one_initcall main.c 762

1098 0 0 do_one_initcall main.c 755

1 0 0 start_kernel main.c 682

0 1 100 start_kernel main.c 675

1 0 0 start_kernel main.c 661

1 0 0 start_kernel main.c 647

1 0 0 start_kernel main.c 630

1 0 0 start_kernel main.c 611

1 0 0 kernel_init main.c 914

0 1 100 kernel_init main.c 911

1 0 0 kernel_init main.c 901

1 0 0 smp_init main.c 399

1 0 0 smp_init main.c 397

1 1 50 cpumask_next cpumask.h 172

0 0 X init_post main.c 850

0 1 100 init_post main.c 838

0 0 X unknown_bootoption main.c 321

0 0 X unknown_bootoption main.c 313

0 0 X unknown_bootoption main.c 309

0 0 X unknown_bootoption main.c 305

0 0 X unknown_bootoption main.c 302

0 0 X unknown_bootoption main.c 299

0 2 100 unknown_bootoption main.c 295

0 0 X unknown_bootoption main.c 286

0 1 100 unknown_bootoption main.c 284

1 1 50 unknown_bootoption main.c 282

0 2 100 obsolete_checksetup main.c 235

2 0 0 obsolete_checksetup main.c 231

0 0 X obsolete_checksetup main.c 229

2 0 0 obsolete_checksetup main.c 224

28 2 6 obsolete_checksetup main.c 223

1 1 50 parse_early_param main.c 496

0 0 X do_early_param main.c 476

368 0 0 do_early_param main.c 475

1 0 0 readonly do_mounts.c 44

3,Functions

可用以显示所有函式执行次数与时间的统计结果 .

操作范例如下所示

# echo 1 >/debug/tracing/function_profile_enabled

… ..do something.....

# echo 0 >/debug/tracing/function_profile_enabled

#cat/debug/tracing/trace_stat/function0

可看到如下结果

Function Hit Time Avg s^2

-------- --- ---- ------

schedule 752 99800000 us 132712.7 us2635264000 us

poll_schedule_timeout 57 37432000 us 656701.7 us 2143996599 us

schedule_hrtimeout_range 55 37429000 us 680527.2 us 339918459 us

schedule_hrtimeout_range_clock 55 37424000 us 680436.3 us 237544596 us

sys_select 87 25028000 us 287678.1 us306802216 us

core_sys_select 87 25012000 us 287494.2 us155578451 us

do_select 87 24875000 us 285919.5 us323446561 us

smp_apic_timer_interrupt 15677 16056000 us 1024.175 us 76796.05 us

do_timer 15677 15677000 us 1000.000 us0.000 us

tick_periodic 15677 15677000 us 1000.000 us 0.000us

tick_handle_periodic 15677 15677000 us 1000.000 us 0.000 us

sys_poll 14 14227000 us 1016214 us 3 503583162 us

do_sys_poll 14 14217000 us 1015500 us 3379054126 us

sys_nanosleep 15 13957000 us 930466.6 us1834329984 us

hrtimer_nanosleep 15 13945000 us 929666.6 us 1719729983us

do_nanosleep 15 13944000 us 929600.0 us1710319131 us

sys_read 167 13503000 us 80856.28 us1298120022 us

vfs_read 172 13490000 us 78430.23 us2981769264 us

tty_read 61 13297000 us 217983.6 us2678381427 us

n_tty_read 61 13256000 us 217311.4 us2834883001 us

schedule_timeout 20 12966000 us 648300.0 us2458710875 us

Max Stack Tracer

可用以显示核心函式呼叫最深的 Stack 大小与在该情况下的 CallStack 路径 .

设定路径为Kernelhacking --->Tracers --->Trace max stack

# echo 1 >/proc/sys/kernel/stack_tracer_enabled

# sleep 10

# echo 0 >/proc/sys/kernel/stack_tracer_enabled

# cat stack_max_size

2152

# cat stack_trace

Depth Size Location (22 entries)

----- ---- --------

0) 2084 68 update_cu​​rr+0x100/0x210

1) 2016 56 enqueue_task_fair+0x90/0x4e0

2) 1960 24 enqueue_task+0x8d/0xb0

3) 1936 12 activate_task+0x25/0x50

4) 1924 88 try_to_wake_up+0x24a/0x5f0

5) 1836 8 wake_up_process+0x14/0x20

6) 1828 8 hrtimer_wakeup+0x2c/0x30

7) 1820 80 hrtimer_run_queues+0x1d4/0x480

8) 1740 8 run_local_timers+0xd/0x20

9) 1732 20 update_process_times+0x34/0x90

10) 1712 8 tick_periodic+0x7a/0x90

11) 1704 32 tick_handle_periodic+0x1e/0xb0

12) 1672 8 smp_apic_timer_interrupt+0x9c/0x9e

13) 1664 108 apic_timer_interrupt+0x2f/0x34

14) 1556 232 schedule+0x62b/0x10f0

15) 1324 76 schedule_hrtimeout_range_clock+0x14b/0x170

16) 1248 12 schedule_hrtimeout_range+0x17/0x20

17) 1236 20 poll_schedule_timeout+0x4c/0x70

18) 1216 764 do_select+0x789/0x7c0

19) 452 332 core_sys_select+0x27d/0x460

20) 120 40 sys_select+0x40/0xe0

21) 80 80 syscall_call+0x7/0xb

主要会列出目前最深的StackSize, 与根据该StackSize 发生的情况下, 完整的CallStack 流程与每个函式所占的空间( 会包括区域变数与FunctionParameters 所占的Stack 空间). 让开发者, 可以根据这流程去检讨函式与呼叫流程设计的合理性.

Event tracing

Event 几乎是整个Ftrace 中, 各种资讯的集合, 浏览/debug/tracing/events 目录中的档案名称如下所示

drwxr-xr-x 4 root root 0XXX 20 23:55 bkl

drwxr-xr-x 20 root root 0XXX 20 23:55 block

-rw-r--r-- 1 root root 0XXX 20 23:55 enable

drwxr-xr-x 14 root root 0XXX 20 23:55 ftrace

-r--r--r-- 1 root root 0XXX 20 23:55 header_event

-r--r--r-- 1 root root 0XXX 20 23:55 header_page

drwxr-xr-x 7 root root 0XXX 20 23:55 irq

drwxr-xr-x 14 root root 0XXX 20 23:55 kmem

drwxr-xr-x 3 root root 0XXX 20 23:55 mce

drwxr-xr-x 7 root root 0XXX 20 23:55 module

drwxr-xr-x 3 root root 0XXX 20 23:55 napi

drwxr-xr-x 6 root root 0XXX 20 23:55 net

drwxr-xr-x 12 root root 0XXX 20 23:55 power

drwxr-xr-x 4 root root 0XXX 20 23:55 raw_syscalls

drwxr-xr-x 18 root root 0XXX 20 23:55 sched

drwxr-xr-x 7 root root 0XXX 20 23:55 scsi

drwxr-xr-x 6 root root 0XXX 20 23:55 signal

drwxr-xr-x 5 root root 0XXX 20 23:55 skb

drwxr-xr-x 634 root root 0XXX 20 23:55 syscalls

drwxr-xr-x 14 root root 0XXX 20 23:55 timer

drwxr-xr-x 15 root root 0XXX 20 23:55 vmscan

drwxr-xr-x 6 root root 0XXX 20 23:55 workqueue

drwxr-xr-x 23 root root 0XXX 20 23:55 writeback

除了​​enable,header_event 与header_page 这三个控制档案外, 其他每个目录都包含一种类别的Event 参数, 以目前笔者所使用的环境,Event 包含了以下的类别

名称

说明

bkl

BKL 为 LinuxKernel2.2 时 , 为了提供一个暂时简易的支援 SMP 机制 , 除了让多核心的架构可以支援多个 Tasks 同时运作外 , 还需要支援一个GlobalSpin-Lock 机制 , 确保同一时间只有一个 Task 在一个需要保护的子系统中运作 , 因此 , 就有了 BKL 机制的诞生 , 然而 ,BKL 机制本身仍有诸多缺陷 ( 详情 , 后续会再抽空用其他文章描述多核心的 Kernel 运作 ),也因此 , 新版的 LinuxKernel 会逐步的移除 BKL 机制 , 让核心可以采用更适当的多核心设计机制 .

参考KernelLock 实作/lib/kernel_lock.c,BKL 全名为Big KernelLock, 主要是提供各别子系统, 确保同一时间只有一个Task 可以在该子系统中运作(例如, 在Kernel2.6.31 的reiserfs 档案系统实作中, 针对SMP(SymmetricMulti-Processors) 处理器组态, 就用到BKL 确保同一时间只有一个Task 可以对reiserfs 进行操作), 目前BKL 并不建议在新设计的程式码中使用, 在最新的LinuxKernel 2.6.39 中,BKL 机制也已经移除.

检视 events/bkl 目录下 , 共支援以下的 Events

lock_kernel unlock_kernel

#echo 1 >/debug/tracing/events/bkl/enable

检视/debug/tracing/trace 下的结果,

block

会把blk-core(in block/blk-core.c) 中相关处理的动作, 记录下来, 供开发者观察相关行程对Block 装置的行为,

检视 events/block 目录下 , 共支援以下的 Events

block_bio_backmerge block_bio_remap block_rq_insert block_split block_bio_bounceblock_getrq block_rq_issue block_unplug_io block_bio_completeblock_plug block_rq_remap block_unplug_timerblock_bio_frontmerge block_rq_abort block_rq_requeue block_bio_queue block_rq_complete block_sleeprq

#echo 1 >/debug/tracing/events/block/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

kjournald-48 [000] 5699.102000: block_bio_queue: 253,0 WS 217891064 + 8[kjournald]

kjournald-48 [000] 5699.102000: block_bio_remap: 8,2 WS 217891448 + 8 <-(253,0) 217​​891064

kjournald-48 [000] 5699.102000: block_bio_remap: 8,0 WS 218100293 + 8 <-(8,2) 217​​891448

kjournald-48 [000] 5699.102000: block_bio_queue: 8,0 WS 218100293 + 8[kjournald]

kjournald-48 [000] 5699.102000: block_getrq: 8,0 WS 218100293 + 8[kjournald]

kjournald-48 [000] 5699.102000: block_plug: [kjournald]

kjournald-48 [000] 5699.102000: block_rq_insert: 8,0 WS 0 () 218​​100293 +8 [kjournald]

kjournald-48 [000] 5699.102000: block_rq_issue: 8,0 WS 0 () 218​​100293 +8 [kjournald]

<...>-13394[000] 5699.114000: block_rq_complete: 8,0 WS () 218​​100293 + 8[0]

<...>-13394[000] 5699.114000: block_bio_complete: 253,0 WS 217891064 + 8[0]

kjournald-48 [000] 5699.126000: block_bio_queue: 253,0 WS 61864 + 8[kjournald]

kjournald-48 [000] 5699.126000: block_bio_remap: 8,2 WS 62248 + 8 <-(253,0) 61864

kjournald-48 [000] 5699.126000: block_bio_remap: 8,0 WS 271093 + 8 <-(8,2) 62248

kjournald-48 [000] 5699.126000: block_bio_queue: 8,0 WS 271093 + 8[kjournald]

kjournald-48 [000] 5699.126000: block_getrq: 8,0 WS 271093 + 8[kjournald]

kjournald-48 [000] 5699.126000: block_plug: [kjournald]

kjournald-48 [000] 5699.126000: block_rq_insert: 8,0 WS 0 () 271093 + 8[kjournald]

kjournald-48 [000] 5699.126000: block_rq_issue: 8,0 WS 0 () 271093 + 8[kjournald]

kjournald-48 [000] 5699.127000: block_rq_complete: 8,0 WS () 271093 + 8[0]

kjournald-48 [000] 5699.127000: block_bio_complete: 253,0 WS 61864 + 8[0]

kjournald-48 [000] 5699.128000: block_bio_queue: 253,0 WS 61872 + 8[kjournald]

kjournald-48 [000] 5699.128000: block_bio_remap: 8,2 WS 62256 + 8 <-(253,0) 61872

kjournald-48 [000] 5699.128000: block_bio_remap: 8,0 WS 271101 + 8 <-(8,2) 62256

kjournald-48 [000] 5699.128000: block_bio_queue: 8,0 WS 271101 + 8[kjournald]

kjournald-48 [000] 5699.128000: block_getrq: 8,0 WS 271101 + 8[kjournald]

kjournald-48 [000] 5699.128000: block_plug: [kjournald]

kjournald-48 [000] 5699.128000: block_rq_insert: 8,0 WS 0 () 271101 + 8[kjournald]

kjournald-48 [000] 5699.128000: block_rq_issue: 8,0 WS 0 () 271101 + 8[kjournald]

kjournald-48 [000] 5699.129000: block_rq_complete: 8,0 WS () 271101 + 8[0]

kjournald-48 [000] 5699.129000: block_bio_complete: 253,0 WS 61872 + 8[0]

kjournald-48 [000] 5699.129000: block_bio_queue: 253,0 WS 61880 + 8[kjournald]

irq

检视 events/irq 目录下 , 共支援以下的 Events

irq_handler_entry softirq_entry softirq_raise irq_handler_exit softirq_exit

#echo 1 >/debug/tracing/events/irq/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<idle>-0 [000] 5601.436000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.436000: softirq_raise: vec=9 [action=RCU]

<idle>-0 [000] 5601.436000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.436000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.436000: softirq_entry: vec=9 [action=RCU]

<idle>-0 [000] 5601.436000: softirq_exit: vec=9 [action=RCU]

<idle>-0 [000] 5601.437000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.437000: softirq_raise: vec=9 [action=RCU]

<idle>-0 [000] 5601.437000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.437000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.437000: softirq_entry: vec=9 [action=RCU]

<idle>-0 [000] 5601.437000: softirq_exit: vec=9 [action=RCU]

<idle>-0 [000] 5601.438000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.438000: softirq_raise: vec=9 [action=RCU]

<idle>-0 [000] 5601.438000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.438000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.438000: softirq_entry: vec=9 [action=RCU]

<idle>-0 [000] 5601.438000: softirq_exit: vec=9 [action=RCU]

<idle>-0 [000] 5601.439000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.439000: softirq_raise: vec=9 [action=RCU]

<idle>-0 [000] 5601.439000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.439000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.439000: softirq_entry: vec=9 [action=RCU]

<idle>-0 [000] 5601.439000: softirq_exit: vec=9 [action=RCU]

<idle>-0 [000] 5601.440000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.440000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.440000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.441000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.441000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.441000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.442000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.442000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.442000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.443000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.443000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.443000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.444000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.444000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.444000: softirq_exit: vec=1 [action=TIMER]

<idle>-0 [000] 5601.445000: softirq_raise: vec=1 [action=TIMER]

<idle>-0 [000] 5601.445000: softirq_entry: vec=1 [action=TIMER]

<idle>-0 [000] 5601.445000: softirq_exit: vec=1 [action=TIMER]

kmem

检视 events/kmem 目录下 , 共支援以下的 Events

kmalloc_nodemm_page_alloc mm_page_pcpu_drain kmem_cache_allocmm_page_alloc_extfrag mm_pagevec_free kfreekmem_cache_alloc_node mm_page_alloc_zone_locked kmallockmem_cache_free mm_page_free_direct

#echo 1 >/debug/tracing/events/kmem/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

cc1-12884[000] 5513.761000: kmem_cache_alloc: call_site=c0527d6eptr=f4ed5300 bytes_req=192 bytes_alloc=192gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: kmem_cache_free: call_site=c047fb8bptr=f59e7740

cc1-12884[000] 5513.762000: kmem_cache_free: call_site=c0527d1bptr=f4eb3680

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050c13aptr=f4f2217c bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050c13aptr=f4f2222c bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050be6eptr=f4f53b1c bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: mm_page_alloc: page=f7490cc0 pfn=316902order=0 migratetype=0gfp_flags=GFP_KERNEL|GFP_REPEAT|GFP_ZERO|0x2

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c0511475ptr=f4f407d0 bytes_req=24 bytes_alloc=24 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c05114c5ptr=f4f58ac8 bytes_req=16 bytes_alloc=16 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: mm_page_alloc: page=f7214760 pfn=235451order=0 migratetype=2 gfp_flags=GFP_HIGHUSER_MOVABLE

cc1-12884[000] 5513.762000: kmalloc: call_site=c057c8e7 ptr=f4cc7800bytes_req=192 bytes_alloc=192 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050c13aptr=f4f79124 bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050af83ptr=f4f221d4 bytes_req=88 bytes_alloc=88 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: kmem_cache_free: call_site=c050a063ptr=f4f221d4

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050c13aptr=f4f221d4 bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: mm_page_alloc: page=f7490c80 pfn=316900order=0 migratetype=0gfp_flags=GFP_KERNEL|GFP_REPEAT|GFP_ZERO|0x2

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c0511475ptr=f4edb368 bytes_req=24 bytes_alloc=24 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c05114c5ptr=f4f58438 bytes_req=16 bytes_alloc=16 gfp_flags=GFP_KERNEL

cc1-12884[000] 5513.762000: mm_page_alloc: page=f7284d80 pfn=249836order=0 migratetype=2 gfp_flags=GFP_HIGHUSER_MOVABLE

cc1-12884[000] 5513.762000: kfree: call_site=c057cac7 ptr=f4cc7800

cc1-12884[000] 5513.762000: kfree: call_site=c057be25 ptr=f4f517e0

cc1-12884[000] 5513.762000: kfree: call_site=c057be2d ptr=f5af3280

cc1-12884[000] 5513.762000: kmem_cache_alloc: call_site=c050baa3ptr=f4f79f94 bytes_req=88 bytes_alloc=88gfp_flags=GFP_KERNEL|GFP_ZERO

cc1-12884[000] 5513.762000: mm_page_alloc: page=f727d7a0 pfn=248893order=0 migratetype=2 gfp_flags=GFP_HIGHUSER_MOVABLE|GFP_ZERO

cc1-12884[000] 5513.762000: kfree: call_site=c057b030 ptr=f4ee5f40

cc1-12884[000] 5513.762000: kfree: call_site=c052ce9b ptr=f5af3480

cc1-12884[000] 5513.762000: kmem_cache_free: call_site=c0536936ptr=f4cdf000

cc1-12884[000] 5513.762000: mm_page_alloc: page=f72571c0 pfn=243982order=0 migratetype=2 gfp_flags=GFP_HIGHUSER_MOVABLE

cc1-12884[000] 5513.763000: mm_page_alloc: page=f7490be0 pfn=316895order=0 migratetype=0gfp_flags=GFP_KERNEL|GFP_REPEAT|GFP_ZERO|0x2

cc1-12884[000] 5513.763000: mm_page_alloc: page=f7274860 pfn=247747order=0 migratetype=2 gfp_flags=GFP_HIGHUSER_MOVABLE

mce

检视 events/mce 目录下 , 共支援以下的 Events

mce_record

module

检视 events/module 目录下 , 共支援以下的 Events

module_free module_load module_request module_get module_put

#echo 1 >/debug/tracing/events/module/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

insmod-12522[000] 5384.763000: module_load: cramfs

insmod-12522[000] 5384.766000: module_put: cramfscall_site=sys_init_module refcnt=2

rmmod-12526[000] 5396.917000: module_free: cramfs

napi

检视 events/napi 目录下 , 共支援以下的 Events

napi_poll

#echo 1 >/debug/tracing/events/napi/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<...>-12085[000] 5144.521000: napi_poll: napi poll on napi structf5981460 for device eth0

<...>-12090[000] 5144.69500​​0: napi_poll: napi poll on napi structf5981460 for device eth0

<...>-12090[000] 5144.69500​​0: napi_poll: napi poll on napi structf5981460 for device eth0

make-12099[000] 5144.895000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12099[000] 5144.895000: napi_poll: napi poll on napi structf5981460 for device eth0

cc1-12102[000] 5144.969000: napi_poll: napi poll on napi structf5981460 for device eth0

cc1-12102[000] 5144.972000: napi_poll: napi poll on napi structf5981460 for device eth0

as-12103[000] 5145.005000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12111[000] 5145.175000: napi_poll: napi poll on napi structf5981460 for device eth0

date-12120[000] 5145.363000: napi_poll: napi poll on napi structf5981460 for device eth0

in.telnetd-1955 [000] 5145.366000: napi_poll: napi poll on napi structf5981460 for device eth0

grep-12132[000] 5145.566000: napi_poll: napi poll on napi structf5981460 for device eth0

sh-12136[000] 5145.631000: napi_poll: napi poll on napi structf5981460 for device eth0

bash-1957 [000] 5145.634000: napi_poll: napi poll on napi structf5981460 for device eth0

sh-12143[000] 5145.834000: napi_poll: napi poll on napi structf5981460 for device eth0

top-9088 [000] 5145.855000: napi_poll: napi poll on napi structf5981460 for device eth0

sh-12143[000] 5145.857000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12147[000] 5145.915000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12147[000] 5145.920000: napi_poll: napi poll on napi structf5981460 for device eth0

cc1-12152[000] 5146.053000: napi_poll: napi poll on napi structf5981460 for device eth0

cc1-12152[000] 5146.053000: napi_poll: napi poll on napi structf5981460 for device eth0

as-12153[000] 5146.113000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12161[000] 5146.253000: napi_poll: napi poll on napi structf5981460 for device eth0

sh-12162[000] 5146.540000: napi_poll: napi poll on napi structf5981460 for device eth0

rm-12168[000] 5146.543000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12173[000] 5146.720000: napi_poll: napi poll on napi structf5981460 for device eth0

bash-1957 [000] 5146.724000: napi_poll: napi poll on napi structf5981460 for device eth0

ld-12179[000] 5146.901000: napi_poll: napi poll on napi structf5981460 for device eth0

ld-12179[000] 5146.903000: napi_poll: napi poll on napi structf5981460 for device eth0

make-12185[000] 5147.004000: napi_poll: napi poll on napi structf5981460 for device eth0

net

检视 events/net 目录下 , 共支援以下的 Events

net_dev_queue net_dev_xmit netif_receive_skb netif_rx

#echo 1 >/debug/tracing/events/net/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

in.telnetd-1955 [000] 4446.238000: net_dev_queue: dev=eth0 skbaddr=f5aa2470len=56

in.telnetd-1955 [000] 4446.238000: net_dev_xmit: dev=eth0 skbaddr=f5aa2470len=56 rc=0

<idle>-0 [000] 4446.436000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4446.436000: net_dev_queue: dev=eth0skbaddr=f5aa2bf0 len=80

<idle>-0 [000] 4446.436000: net_dev_xmit: dev=eth0 skbaddr=f5aa2bf0len=80 rc=0

<idle>-0 [000] 4446.593000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

in.telnetd-1955 [000] 4446.596000: net_dev_queue: dev=eth0 skbaddr=f5aa2bf0len=66

in.telnetd-1955 [000] 4446.596000: net_dev_xmit: dev=eth0 skbaddr=f5aa2bf0len=66 rc=0

in.telnetd-9058 [000] 4446.689000: net_dev_queue: dev=eth0 skbaddr=f5aa2470len=136

in.telnetd-9058 [000] 4446.689000: net_dev_xmit: dev=eth0 skbaddr=f5aa2470len=136 rc=0

<idle>-0 [000] 4446.782000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

in.telnetd-1955 [000] 4446.785000: net_dev_queue: dev=eth0 skbaddr=f5aa2bf0len=95

in.telnetd-1955 [000] 4446.785000: net_dev_xmit: dev=eth0 skbaddr=f5aa2bf0len=95 rc=0

<idle>-0 [000] 4446.888000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4446.888000: net_dev_queue: dev=eth0skbaddr=f5aa2d70 len=953

<idle>-0 [000] 4446.888000: net_dev_xmit: dev=eth0 skbaddr=f5aa2d70len=953 rc=0

<idle>-0 [000] 4446.983000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4447.087000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4447.550000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

in.telnetd-1955 [000] 4447.552000: net_dev_queue: dev=eth0 skbaddr=f5aa2d70len=82

in.telnetd-1955 [000] 4447.552000: net_dev_xmit: dev=eth0 skbaddr=f5aa2d70len=82 rc=0

<idle>-0 [000] 4447.752000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4447.974000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

in.telnetd-1955 [000] 4447.976000: net_dev_queue: dev=eth0 skbaddr=f5aa2d70len=56

in.telnetd-1955 [000] 4447.976000: net_dev_xmit: dev=eth0 skbaddr=f5aa2d70len=56 rc=0

<idle>-0 [000] 4448.175000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

<idle>-0 [000] 4448.175000: net_dev_queue: dev=eth0skbaddr=f5aa2bf0 len=1138

<idle>-0 [000] 4448.175000: net_dev_xmit: dev=eth0 skbaddr=f5aa2bf0len=1138 rc=0

<idle>-0 [000] 4448.373000: netif_receive_skb: dev=eth0skbaddr=f4f6ad40 len=46

in.telnetd-9058 [000] 4448.701000: net_dev_queue: dev=eth0 skbaddr=f5aa2bf0len=1004

in.telnetd-9058 [000] 4448.701000: net_dev_xmit: dev=eth0 skbaddr=f5aa2bf0len=1004 rc=0

power

检视 events/power 目录下 , 共支援以下的 Events

clock_disablecpu_frequency power_end clock_enable cpu_idle machine_suspendpower_frequency clock_set_rate power_domain_target power_start

#echo 1 >/debug/tracing/events/power/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<idle>-0 [000] 4370.240000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.240000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.241000: power_end: cpu_id=0

<idle>-0 [000] 4370.241000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.241000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.241000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.242000: power_end: cpu_id=0

<idle>-0 [000] 4370.242000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.242000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.242000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.243000: power_end: cpu_id=0

<idle>-0 [000] 4370.243000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.243000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.243000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.244000: power_end: cpu_id=0

<idle>-0 [000] 4370.244000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.244000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.244000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.245000: power_end: cpu_id=0

<idle>-0 [000] 4370.245000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.245000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.245000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.246000: power_end: cpu_id=0

<idle>-0 [000] 4370.246000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.246000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.246000: cpu_idle: state=1 cpu_id=0

<idle>-0 [000] 4370.247000: power_end: cpu_id=0

<idle>-0 [000] 4370.247000: cpu_idle: state=4294967295 cpu_id=0

<idle>-0 [000] 4370.247000: power_start: type=1 state=1 cpu_id=0

<idle>-0 [000] 4370.247000: cpu_idle: state=1 cpu_id=0

raw_syscalls

检视 events/raw_syscalls 目录下 , 共支援以下的 Events

sys_enter sys_exit

#echo 1 >/debug/tracing/events/raw_syscalls/enable

检视/debug/tracing/trace 下的结果,

bash-3798 [000] 9209.897945: sys_enter: NR 63 (a, 1, a, 0, a, bff53448)

bash-3798 [000] 9209.897966: sys_exit: NR 63 = 1

bash-3798 [000] 9209.897970: sys_enter: NR 221 (a, 1, 0, 0, b77cfff4,bff53328)

bash-3798 [000] 9209.897972: sys_exit: NR 221 = 1

bash-3798 [000] 9209.897975: s​​ys_enter: NR 6 (a, 1, 0, 0, 0, bff53448)

bash-3798 [000] 9209.897976: sys_exit: NR 6 = 0

bash-3798 [000] 9209.897988: sys_enter: NR 175 (0, 0, 80fe4dc,8,b77cfff4, bff535bc)

bash-3798 [000] 9209.897991: sys_exit: NR 175 = 0

bash-3798 [000] 9209.897994: sys_enter: NR 174 (2, bff53400, bff53374,8, b77cfff4, bff53498)

bash-3798 [000] 9209.897996: sys_exit: NR 174 = 0

sched

检视 events/sched 目录下 , 共支援以下的 Events

sched_process_exit sched_stat_sleep sched_process_fork sched_stat_waitsched_kthread_stop sched_process_free sched_switchsched_kthread_stop_ret sched_process_wait sched_wait_tasksched_migrate_task sched_stat_iowait sched_wakeupsched_pi_setprio sched_stat_runtime sched_wakeup_new

#echo 1 >/debug/tracing/events/sched/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1957 [000] 4232.264000: sched_stat_wait: comm=kworker/0:0 pid=4delay=0 [ns]

bash-1957 [000] 4232.264000: sched_switch: prev_comm=bash prev_pid=1957prev_prio=120 prev_state=R ==> next_comm=kworker/0:0next_pid=4 next_prio=120

kworker/0:0-4 [000] 4232.265000: sched_stat_runtime: comm=kworker/0:0pid=4 runtime=956546 [ns] vruntime=1353114806115 [ns]

kworker/0:0-4 [000] 4232.265000: sched_stat_sleep: comm=in.telnetdpid=1955 delay=3893232 [ns]

kworker/0:0-4 [000] 4232.265000: sched_wakeup: comm=in.telnetd pid=1955prio=120 success=1 target_cpu=000

kworker/0:0-4 [000] 4232.265000: sched_stat_wait: comm=in.telnetdpid=1955 delay=0 [ns]

kworker/0:0-4 [000] 4232.265000: sched_switch: prev_comm=kworker/0:0prev_pid=4 prev_prio=120 prev_state=S ==>next_comm=in.telnetd next_pid=1955 next_prio=120

in.telnetd-1955 [000] 4232.265000: sched_stat_wait: comm=bash pid=1957delay=956546 [ns]

in.telnetd-1955 [000] 4232.265000: sched_switch: prev_comm=in.telnetdprev_pid=1955 prev_prio=120 prev_state=S ==> next_comm=bashnext_pid=1957 next_prio=120

bash-1957 [000] 4232.266000: sched_stat_runtime: comm=bash pid=1957runtime=1329219 [ns] vruntime=1353118178788 [ns]

bash-1957 [000] 4232.267000: sched_stat_runtime: comm=bash pid=1957runtime=672432 [ns] vruntime=1353118851220 [ns]

bash-1957 [000] 4232.267000: sched_wakeup: comm=bash pid=1957 prio=120success=0 target_cpu=000

bash-1957 [000] 4232.267000: sched_switch: prev_comm=bash prev_pid=1957prev_prio=120 prev_state=S ==> next_comm=swapper next_pid=0next_prio=120

<idle>-0 [000] 4232.268000: sched_stat_sleep: comm=kworker/0:0pid=4 delay=3016584 [ns]

<idle>-0 [000] 4232.268000: sched_wakeup: comm=kworker/0:0 pid=4prio=120 success=1 target_cpu=000

<idle>-0 [000] 4232.268000: sched_stat_wait: comm=kworker/0:0 pid=4delay=0 [ns]

<idle>-0 [000] 4232.268000: sched_switch: prev_comm=swapperprev_pid=0 prev_prio=120 prev_state=R ==>next_comm=kworker/0:0 next_pid=4 next_prio=120

kworker/0:0-4 [000] 4232.268000: sched_stat_sleep: comm=in.telnetdpid=1955 delay=3016584 [ns]

kworker/0:0-4 [000] 4232.268000: sched_wakeup: comm=in.telnetd pid=1955prio=120 success=1 target_cpu=000

kworker/0:0-4 [000] 4232.268000: sched_stat_wait: comm=in.telnetdpid=1955 delay=0 [ns]

kworker/0:0-4 [000] 4232.268000: sched_switch: prev_comm=kworker/0:0prev_pid=4 prev_prio=120 prev_state=S ==>next_comm=in.telnetd next_pid=1955 next_prio=120

in.telnetd-1955 [000] 4232.268000: sched_switch: prev_comm=in.telnetdprev_pid=1955 prev_prio=120 prev_state=S ==>next_comm=swapper next_pid=0 next_prio=120

<idle>-0 [000] 4232.533000: sched_stat_sleep: comm=top pid=9088delay=2003729805 [ns]

<idle>-0 [000] 4232.533000: sched_wakeup: comm=top pid=9088prio=120 success=1 target_cpu=000

<idle>-0 [000] 4232.533000: sched_stat_wait: comm=top pid=9088delay=292215 [ns]

<idle>-0 [000] 4232.533000: sched_switch: prev_comm=swapperprev_pid=0 prev_prio=120 prev_state=R ==> next_comm=topnext_pid=9088 next_prio=120

<...>-9088 [000] 4232.533000: sched_stat_sleep: comm=in.telnetd pid=9058delay=2005198147 [ns]

<...>-9088 [000] 4232.533000: sched_wakeup: comm=in.telnetd pid=9058prio=120 success=1 target_cpu=000

<...>-9088 [000] 4232.534000: sched_stat_runtime: comm=top pid=9088runtime=889219 [ns] vruntime=1353116740439 [ns]

<...>-9088 [000] 4232.535000: sched_stat_runtime: comm=top pid=9088runtime=872178 [ns] vruntime=1353117612617 [ns]

<...>-9088 [000] 4232.536000: sched_stat_runtime: comm=top pid=9088runtime=1030578 [ns] vruntime=1353118643195 [ns]

scsi

检视 events/scsi 目录下 , 共支援以下的 Events

scsi_dispatch_cmd_donescsi_dispatch_cmd_start scsi_eh_wakeup scsi_dispatch_cmd_errorscsi_dispatch_cmd_timeout

#echo 1 >/debug/tracing/events/scsi/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

kjournald-48 [000] 4120.730000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=218489949 txlen=8 protect=0 raw=2a 00 0d 05 e4 5d 00 00 0800 )

<...>-10718[000] 4120.730000: scsi_dispatch_cmd_done: host_no=0 channel=0id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10 lba=218489949txlen=8 protect=0 raw=2a 00 0d 05 e4 5d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.734000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267293 txlen=8 protect=0 raw=2a 00 00 04 14 1d 00 00 08 00)

kjournald-48 [000] 4120.734000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267293 txlen=8 protect=0 raw=2a 00 00 04 14 1d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.734000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267301 txlen=8 protect=0 raw=2a 00 00 04 14 25 00 00 08 00)

kjournald-48 [000] 4120.734000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267301 txlen=8 protect=0 raw=2a 00 00 04 14 25 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.735000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267309 txlen=8 protect=0 raw=2a 00 00 04 14 2d 00 00 08 00)

kjournald-48 [000] 4120.735000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267309 txlen=8 protect=0 raw=2a 00 00 04 14 2d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.736000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267317 txlen=8 protect=0 raw=2a 00 00 04 14 35 00 00 08 00)

kjournald-48 [000] 4120.736000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267317 txlen=8 protect=0 raw=2a 00 00 04 14 35 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.736000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267325 txlen=8 protect=0 raw=2a 00 00 04 14 3d 00 00 08 00)

kjournald-48 [000] 4120.736000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267325 txlen=8 protect=0 raw=2a 00 00 04 14 3d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267333 txlen=8 protect=0 raw=2a 00 00 04 14 45 00 00 08 00)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267333 txlen=8 protect=0 raw=2a 00 00 04 14 45 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267341 txlen=8 protect=0 raw=2a 00 00 04 14 4d 00 00 08 00)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267341 txlen=8 protect=0 raw=2a 00 00 04 14 4d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267349 txlen=8 protect=0 raw=2a 00 00 04 14 55 00 00 08 00)

kjournald-48 [000] 4120.738000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267349 txlen=8 protect=0 raw=2a 00 00 04 14 55 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.742000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267357 txlen=8 protect=0 raw=2a 00 00 04 14 5d 00 00 08 00)

kjournald-48 [000] 4120.742000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267357 txlen=8 protect=0 raw=2a 00 00 04 14 5d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.742000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267365 txlen=8 protect=0 raw=2a 00 00 04 14 65 00 00 08 00)

kjournald-48 [000] 4120.742000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267365 txlen=8 protect=0 raw=2a 00 00 04 14 65 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.743000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267373 txlen=8 protect=0 raw=2a 00 00 04 14 6d 00 00 08 00)

kjournald-48 [000] 4120.743000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267373 txlen=8 protect=0 raw=2a 00 00 04 14 6d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.744000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267381 txlen=8 protect=0 raw=2a 00 00 04 14 75 00 00 08 00)

kjournald-48 [000] 4120.744000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267381 txlen=8 protect=0 raw=2a 00 00 04 14 75 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.744000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267389 txlen=8 protect=0 raw=2a 00 00 04 14 7d 00 00 08 00)

kjournald-48 [000] 4120.744000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267389 txlen=8 protect=0 raw=2a 00 00 04 14 7d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.745000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267397 txlen=8 protect=0 raw=2a 00 00 04 14 85 00 00 08 00)

kjournald-48 [000] 4120.745000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267397 txlen=8 protect=0 raw=2a 00 00 04 14 85 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

kjournald-48 [000] 4120.745000: scsi_dispatch_cmd_start: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267405 txlen=8 protect=0 raw=2a 00 00 04 14 8d 00 00 08 00)

kjournald-48 [000] 4120.745000: scsi_dispatch_cmd_done: host_no=0channel=0 id=0 lun=0 data_sgl=1 prot_sgl=0 cmnd=(WRITE_10lba=267405 txlen=8 protect=0 raw=2a 00 00 04 14 8d 00 00 08 00)result=(driver=DRIVER_OK host=DID_OK message=COMMAND_COMPLETEstatus=SAM_STAT_GOOD)

signal

检视 events/signal 目录下 , 共支援以下的 Events

signal_deliver signal_lose_info signal_generate signal_overflow_fail

#echo 1 >/debug/tracing/events/signal/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<...>-9862 [000] 3893.720000: signal_generate: sig=17 errno=0code=262145 comm=bash pid=1957

<...>-9863 [000] 3893.732000: signal_generate: sig=17 errno=0code=262145 comm=bash pid=1957

bash-1957 [000] 3893.733000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9864 [000] 3894.941000: signal_generate: sig=17 errno=0code=262145 comm=bash pid=1957

<...>-9865 [000] 3894.949000: signal_generate: sig=17 errno=0code=262145 comm=bash pid=1957

bash-1957 [000] 3894.949000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9868 [000] 3899.215000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9867

<...>-9869 [000] 3899.225000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9867

<...>-9867 [000] 3899.226000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9867 [000] 3899.228000: signal_generate: sig=17 errno=0code=262145 comm=make pid=9866

make-9866 [000] 3899.228000: signal_deliver: sig=17 errno=0 code=262145sa_handler=8053850 sa_flags=10000000

<...>-9870 [000] 3899.245000: signal_generate: sig=17 errno=0code=262145 comm=make pid=9866

make-9866 [000] 3899.246000: signal_deliver: sig=17 errno=0 code=262145sa_handler=8053850 sa_flags=10000000

<...>-9873 [000] 3899.336000: signal_generate: sig=17 errno=0code=262145 comm=arm-none-eabi-g pid=9872

<...>-9874 [000] 3899.412000: signal_generate: sig=17 errno=0code=262145 comm=arm-none-eabi-g pid=9872

<...>-9872 [000] 3899.414000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9871

<...>-9871 [000] 3899.414000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9875 [000] 3899.428000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9871

<...>-9871 [000] 3899.428000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9871 [000] 3899.431000: signal_generate: sig=17 errno=0code=262145 comm=make pid=9866

make-9866 [000] 3899.431000: signal_deliver: sig=17 errno=0 code=262145sa_handler=8053850 sa_flags=10000000

<...>-9878 [000] 3899.514000: signal_generate: sig=17 errno=0code=262145 comm=arm-none-eabi-g pid=9877

<...>-9879 [000] 3899.578000: signal_generate: sig=17 errno=0code=262145 comm=arm-none-eabi-g pid=9877

<...>-9877 [000] 3899.580000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9876

<...>-9876 [000] 3899.580000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9880 [000] 3899.593000: signal_generate: sig=17 errno=0code=262145 comm=sh pid=9876

<...>-9876 [000] 3899.594000: signal_deliver: sig=17 errno=0 code=262145sa_handler=807aa60 sa_flags=0

<...>-9876 [000] 3899.595000: signal_generate: sig=17 errno=0code=262145 comm=make pid=9866

make-9866 [000] 3899.595000: signal_deliver: sig=17 errno=0 code=262145sa_handler=8053850 sa_flags=10000000

<...>-9883 [000] 3899.682000: signal_generate: sig=17 errno=0code=262145 comm=arm-none-eabi-g pid=9882

skb

检视 events/skb 目录下 , 共支援以下的 Events

consume_skb kfree_skb skb_copy_datagram_iovec

#echo 1 >/debug/tracing/events/skb/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1957 [000] 3800.664000: consume_skb: skbaddr=f5aa2ef0

<idle>-0 [000] 3800.864000: consume_skb: skbaddr=f5aa2a70

top-9088 [000] 3801.184000: consume_skb: skbaddr=f5aa2a70

in.telnetd-1955 [000] 3801.281000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=3

<idle>-0 [000] 3801.285000: consume_skb: skbaddr=f5aa2ef0

in.telnetd-1955 [000] 3801.437000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=3

bash-1957 [000] 3801.440000: consume_skb: skbaddr=f5aa2ef0

in.telnetd-1955 [000] 3802.094000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=3

bash-1957 [000] 3802.098000: consume_skb: skbaddr=f5aa2ef0

in.telnetd-1955 [000] 3802.605000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=1

bash-1957 [000] 3802.607000: kfree_skb: skbaddr=f4f6a500 protocol=0location=c0814f61

bash-1957 [000] 3802.609000: consume_skb: skbaddr=f5aa2ef0

<idle>-0 [000] 3802.804000: consume_skb: skbaddr=f5aa2a70

top-9088 [000] 3803.193000: consume_skb: skbaddr=f5aa2a70

<idle>-0 [000] 3803.392000: consume_skb: skbaddr=f5aa2ef0

top-9088 [000] 3805.206000: consume_skb: skbaddr=f5aa2ef0

top-9088 [000] 3805.211000: consume_skb: skbaddr=f5aa2a70

top-9088 [000] 3805.212000: consume_skb: skbaddr=f5aa22f0

in.telnetd-1955 [000] 3805.970000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=3

in.telnetd-1955 [000] 3805.974000: consume_skb: skbaddr=f5aa22f0

in.telnetd-1955 [000] 3806.251000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=1

bash-1957 [000] 3806.252000: kfree_skb: skbaddr=f4f6a500 protocol=0location=c0814f61

bash-1957 [000] 3806.255000: consume_skb: skbaddr=f5aa22f0

<idle>-0 [000] 3806.457000: consume_skb: skbaddr=f5aa2a70

top-9088 [000] 3807.222000: consume_skb: skbaddr=f5aa2a70

top-9088 [000] 3807.222000: consume_skb: skbaddr=f5aa22f0

top-9088 [000] 3807.223000: consume_skb: skbaddr=f5aa22f0

in.telnetd-1955 [000] 3807.300000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=1

more-9857 [000] 3807.303000: consume_skb: skbaddr=f5aa2ef0

<idle>-0 [000] 3807.431000: consume_skb: skbaddr=f5aa2a70

<idle>-0 [000] 3807.471000: consume_skb: skbaddr=f5aa2770

in.telnetd-1955 [000] 3807.471000: skb_copy_datagram_iovec: skbaddr=f4f6a500len=3

syscalls

检视 events/syscalls 目录下 , 共支援以下的 Events

sys_enter_accept

sys_enter_accept4

sys_enter_access

sys_enter_acct

sys_enter_add_key

sys_enter_adjtimex

sys_enter_alarm

sys_enter_bdflush

sys_enter_bind

sys_enter_brk

… .

sys_exit_vmsplice

sys_exit_wait4

sys_exit_waitid

sys_exit_waitpid

sys_exit_write

sys_exit_writev

#echo 1 >/debug/tracing/events/syscalls/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1957 [000] 3716.573000: sys_open -> 0x3

bash-1957 [000] 3716.573000: sys_fcntl64(fd: 1, cmd: 1, arg: 0)

bash-1957 [000] 3716.573000: sys_fcntl64 -> 0x0

bash-1957 [000] 3716.573000: sys_fcntl64(fd: 1, cmd: 0, arg: a)

bash-1957 [000] 3716.573000: sys_fcntl64 -> 0xa

bash-1957 [000] 3716.573000: sys_fcntl64(fd: 1, cmd: 1, arg: 0)

bash-1957 [000] 3716.573000: sys_fcntl64 -> 0x0

bash-1957 [000] 3716.573000: sys_fcntl64(fd: a, cmd: 2, arg: 1)

bash-1957 [000] 3716.573000: sys_fcntl64 -> 0x0

bash-1957 [000] 3716.573000: sys_dup2(oldfd: 3, newfd: 1)

bash-1957 [000] 3716.573000: sys_dup2 -> 0x1

bash-1957 [000] 3716.573000: sys_close(fd: 3)

bash-1957 [000] 3716.573000: sys_close -> 0x0

bash-1957 [000] 3716.574000: sys_write(fd: 1, buf: b781c000, count: 1)

bash-1957 [000] 3716.574000: sys_write -> 0x1

bash-1957 [000] 3716.574000: sys_dup2(oldfd: a, newfd: 1)

bash-1957 [000] 3716.574000: sys_dup2 -> 0x1

bash-1957 [000] 3716.574000: sys_fcntl64(fd: a, cmd: 1, arg: 0)

bash-1957 [000] 3716.574000: sys_fcntl64 -> 0x1

bash-1957 [000] 3716.574000: sys_close(fd: a)

bash-1957 [000] 3716.574000: sys_close -> 0x0

bash-1957 [000] 3716.574000: sys_rt_sigprocmask(how: 0, set: 0, oset:80fe4dc, sigsetsize: 8)

bash-1957 [000] 3716.574000: sys_rt_sigprocmask -> 0x0

bash-1957 [000] 3716.574000: sys_rt_sigaction(sig: 2, act: bfd40dc0,oact: bfd40d34, sigsetsize: 8)

bash-1957 [000] 3716.574000: sys_rt_sigaction -> 0x0

bash-1957 [000] 3716.574000: sys_time(tloc: 0)

bash-1957 [000] 3716.574000: sys_time -> 0x4dd7d442

bash-1957 [000] 3716.574000: sys_rt_sigprocmask(how: 0, set: bfd4054c,oset: bfd404cc, sigsetsize: 8)

bash-1957 [000] 3716.574000: sys_rt_sigprocmask -> 0x0

bash-1957 [000] 3716.574000: sys_ioctl(fd: ff, cmd: 5410, arg:bfd404c4)

bash-1957 [000] 3716.574000: sys_ioctl -> 0x0

timer

检视 events/timer 目录下 , 共支援以下的 Events

hrtimer_expire_exit itimer_state timer_init hrtimer_init timer_cancel timer_starthrtimer_cancel hrtimer_start timer_expire_entryhrtimer_expire_entry itimer_expire timer_expire_exit

#echo 1 >/debug/tracing/events/timer/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1925 [000] 3590.212000: timer_cancel: timer=f58a10cc

bash-1925 [000] 3590.213000: timer_expire_entry: timer=f58a10ccfunction=delayed_work_timer_fn now=3290213

bash-1925 [000] 3590.213000: timer_expire_exit: timer=f58a10cc

in.telnetd-1923 [000] 3590.213000: timer_start: timer=f5446b4cfunction=tcp_write_timer expires=3290566 [timeout=353]

bash-1925 [000] 3590.215000: timer_start: timer=f58a10ccfunction=delayed_work_timer_fn expires=3290216 [timeout=1]

<idle>-0 [000] 3590.216000: timer_cancel: timer=f58a10cc

<idle>-0 [000] 3590.216000: timer_expire_entry: timer=f58a10ccfunction=delayed_work_timer_fn now=3290216

<idle>-0 [000] 3590.216000: timer_expire_exit: timer=f58a10cc

<idle>-0 [000] 3590.275000: timer_cancel: timer=f5446b68

<idle>-0 [000] 3590.275000: timer_expire_entry: timer=f5446b68function=tcp_delack_timer now=3290275

<idle>-0 [000] 3590.275000: timer_expire_exit: timer=f5446b68

<idle>-0 [000] 3590.409000: timer_cancel: timer=f5446b4c

<idle>-0 [000] 3590.409000: timer_start: timer=f5446b4cfunction=tcp_write_timer expires=3290767 [timeout=358]

<idle>-0 [000] 3590.458000: hrtimer_cancel: hrtimer=f4d21b80

<idle>-0 [000] 3590.458000: hrtimer_expire_entry: hrtimer=f4d21b80function=hrtimer_wakeup now=3612200721​​124

<idle>-0 [000] 3590.458000: hrtimer_expire_exit: hrtimer=f4d21b80

gam_server-1890 [000] 3590.459000: hrtimer_init: hrtimer=f4d21b80clockid=CLOCK_MONOTONIC mode=HRTIMER_MODE_ABS

gam_server-1890 [000] 3590.459000: hrtimer_start: hrtimer=f4d21b80function=hrtimer_wakeup expires=3613207309303softexpires=3613202309315

<idle>-0 [000] 3590.767000: timer_cancel: timer=f5446b4c

<idle>-0 [000] 3590.767000: timer_expire_entry: timer=f5446b4cfunction=tcp_write_timer now=3290767

<idle>-0 [000] 3590.767000: timer_expire_exit: timer=f5446b4c

<idle>-0 [000] 3591.002000: timer_cancel: timer=f64036b0

<idle>-0 [000] 3591.002000: timer_expire_entry: timer=f64036b0function=delayed_work_timer_fn now=3291002

<idle>-0 [000] 3591.002000: timer_expire_exit: timer=f64036b0

kworker/0:0-4 [000] 3591.002000: timer_start: timer=f64036b0function=delayed_work_timer_fn expires=3292002 [timeout=1000]

<idle>-0 [000] 3591.004000: timer_cancel: timer=f598135c

<idle>-0 [000] 3591.004000: timer_expire_entry: timer=f598135cfunction=e1000_watchdog now=3291004

<idle>-0 [000] 3591.004000: timer_start: timer=f598135cfunction=e1000_watchdog expires=3293004 [timeout=2000]

vmscan

检视 events/vmscan 目录下 , 共支援以下的 Events

mm_vmscan_memcg_isolatemm_vmscan_memcg_reclaim_begin mm_vmscan_direct_reclaim_beginmm_vmscan_memcg_reclaim_end mm_vmscan_direct_reclaim_endmm_vmscan_memcg_softlimit_reclaim_begin mm_vmscan_kswapd_sleepmm_vmscan_memcg_softlimit_reclaim_end mm_vmscan_kswapd_wakemm_vmscan_wakeup_kswapd mm_vmscan_lru_isolatemm_vmscan_writepage mm_vmscan_lru_shrink_inactive

#echo 1 >/debug/tracing/events/vmscan/enable

检视/debug/tracing/trace 下的结果,

workqueue

检视 events/workqueue 目录下 , 共支援以下的 Events

workqueue_activate_work workqueue_execute_start workqueue_execute_endworkqueue_queue_work

#echo 1 >/debug/tracing/events/workqueue/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

bash-1957 [000] 3205.721000: workqueue_queue_work: work struct=f58a24bcfunction=flush_to_ldisc workqueue=f600dac0 req_cpu=0 cpu=0

bash-1957 [000] 3205.721000: workqueue_activate_work: work structf58a24bc

kworker/0:0-4 [000] 3205.721000: workqueue_execute_start: work structf58a24bc: function flush_to_ldisc

kworker/0:0-4 [000] 3205.721000: workqueue_execute_end: work structf58a24bc

<idle>-0 [000] 3205.723000: workqueue_queue_work: workstruct=f58a24bc function=flush_to_ldisc workqueue=f600dac0req_cpu=0 cpu=0

<idle>-0 [000] 3205.723000: workqueue_activate_work: work structf58a24bc

kworker/0:0-4 [000] 3205.723000: workqueue_execute_start: work structf58a24bc: function flush_to_ldisc

kworker/0:0-4 [000] 3205.723000: workqueue_execute_end: work structf58a24bc

<idle>-0 [000] 3206.002000: workqueue_queue_work: workstruct=f64036a0 function=vmstat_update workqueue=f600dac0req_cpu=0 cpu=0

<idle>-0 [000] 3206.002000: workqueue_activate_work: work structf64036a0

kworker/0:0-4 [000] 3206.002000: workqueue_execute_start: work structf64036a0: function vmstat_update

kworker/0:0-4 [000] 3206.002000: workqueue_execute_end: work structf64036a0

<idle>-0 [000] 3206.347000: workqueue_queue_work: workstruct=f58bf8bc function=flush_to_ldisc workqueue=f600dac0req_cpu=0 cpu=0

<idle>-0 [000] 3206.347000: workqueue_activate_work: work structf58bf8bc

kworker/0:0-4 [000] 3206.347000: workqueue_execute_start: work structf58bf8bc: function flush_to_ldisc

kworker/0:0-4 [000] 3206.347000: workqueue_execute_end: work structf58bf8bc

<idle>-0 [000] 3206.349000: workqueue_queue_work: workstruct=f58a24bc function=flush_to_ldisc workqueue=f600dac0req_cpu=0 cpu=0

<idle>-0 [000] 3206.349000: workqueue_activate_work: work structf58a24bc

kworker/0:0-4 [000] 3206.349000: workqueue_execute_start: work structf58a24bc: function flush_to_ldisc

kworker/0:0-4 [000] 3206.349000: workqueue_execute_end: work structf58a24bc

<idle>-0 [000] 3206.654000: workqueue_queue_work: workstruct=f58bf8bc function=flush_to_ldisc workqueue=f600dac0req_cpu=0 cpu=0

<idle>-0 [000] 3206.654000: workqueue_activate_work: work structf58bf8bc

kworker/0:0-4 [000] 3206.654000: workqueue_execute_start: work structf58bf8bc: function flush_to_ldisc

kworker/0:0-4 [000] 3206.654000: workqueue_execute_end: work structf58bf8bc

writeback

检视 events/writeback 目录下 , 共支援以下的 Events

writeback_execwriteback_nothread wbc_balance_dirty_start writeback_noworkwbc_balance_dirty_wait writeback_pages_writtenwbc_balance_dirty_written writeback_queue wbc_writeback_startwriteback_thread_start wbc_writeback_wait writeback_thread_stopwbc_writeback_written writeback_wait_iff_congestedwbc_writepage writeback_wake_background writeback_bdi_registerwriteback_wake_forker_thread writeback_bdi_unregisterwriteback_wake_thread writeback_congestion_wait

#echo 1 >/debug/tracing/events/writeback/enable

检视/debug/tracing/trace 下的结果,

#tracer: nop

#

# TASK-PID CPU# TIMESTAMP FUNCTION

# | | | | |

<...>-2719 [000] 2262.160000: writeback_wake_thread: bdi 253:0

<...>-1921 [000] 2262.160000: wbc_writeback_start: bdi 253:0:​​ towrt=1024skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1d7b80 start=0x0 end=0x0

<...>-1921 [000] 2262.160000: wbc_writeback_written: bdi 253:0:​​towrt=1024 skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1d7b80 start=0x0 end= 0x0

<...>-1921 [000] 2262.160000: writeback_pages_written: 0

<...>-1921 [000] 2267.160000: wbc_writeback_start: bdi 253:0:​​ towrt=1024skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1d8f08 start=0x0 end=0x0

<...>-1921 [000] 2267.160000: wbc_writeback_written: bdi 253:0:​​towrt=1024 skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1d8f08 start=0x0 end= 0x0

<...>-1921 [000] 2267.160000: writeback_pages_written: 0

<...>-1921 [000] 2272.160000: wbc_writeback_start: bdi 253:0:​​ towrt=1024skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1da290 start=0x0 end=0x0

<...>-1921 [000] 2272.160000: writeback_pages_written: 0

<...>-1921 [000] 2277.160000: wbc_writeback_start: bdi 253:0:​​ towrt=1024skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1db618 start=0x0 end=0x0

<...>-1921 [000] 2277.160000: wbc_writeback_written: bdi 253:0:​​towrt=1024 skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1db618 start=0x0 end= 0x0

<...>-1921 [000] 2277.160000: writeback_pages_written: 0

<...>-1921 [000] 2282.160000: wbc_writeback_start: bdi 253:0:​​ towrt=1024skip=0 mode=0 kupd=1 bgrd=0 reclm=0 cyclic=1 more=0older=0x1dc9a0 start=0x0 end=0x0

结尾,

在平台移植与开发上, 效能调教对于产品化的影响很深, 本文主要介绍Ftrace 的概念与操作范例, 对笔者而言, 这套工具可以帮助在复杂行为下, 去分析系统效能的瓶颈, 例如, 是否有中断关闭过长的行为, 或是修改过的核心函式, 不适当的行为占据过多的处理器时间. 目前, 在Linux 平台上, 能使用的工具不少( 或是也可以使用商业的ICE 产品), 对这些工具内部运作原理掌握的程度越高, 我们就会有足够的知识背景帮助团队在问题发生时, 借重适当的工具去分析问题的原因,Ftrace 只是提供系统问题一部分的资讯, 其它可用的工具与分析问题的知识背景, 会是有志于在这产业的开发者, 需要持续努力的.

Android笔记-Linux Kernel Ftrace (Function Trace)解析相关推荐

  1. Android和Linux kernel发展史

    Android和Linux kernel发展史(BY 夕つ云 整理) 英文名 中文名 Android系统版本 发布时间 Linux kernel内核版本 备注 Astro 铁臂阿童木 Android  ...

  2. ?Android和Linux kernel发展史(BY 夕つ云 整理)

    http://www.eetop.cn/blog/html/52/51552-44700.html Android和Linux kernel发展史(BY 夕つ云 整理) 英文名 中文名 Android ...

  3. android linux kernel VS standard linux kernel

    在kernel子目录下存放的就是Android的Linux Kernel了, 通过和标准的Linux 2.6.25 Kernel的对比,我们可以发现,其主要增加了以下的内容: 1. 基于ARM架构增加 ...

  4. Android与Linux的区别

    Android这一词最先出现在法国作家利尔亚当在1886年发表的科幻小说<未来夏娃>中,作者将外表像人类的机器起名为Android,这也就是Android小人名字的由来.Android是基 ...

  5. 在linux kernel或android中解析cmdline参数

    文章目录 ★★★ 友情链接 : 个人博客导读首页-点击此处 ★★★ Kernel command line: earlycon androidboot.selinux=permissive uart_ ...

  6. Android/Linux Kernel 内存管理-入门笔记

    Android/Linux Kernel上下層的記憶體管理機制,由於牽涉到基礎,核心與使用者空間的Framework,這系列的文章會分為幾個單元,依據筆者自己的時間安排,逐一分享出來,並希望對各位有所 ...

  7. android compress函数,Linux Kernel(Android) 加密算法小结(cipher、compress、digest)

    Linux Kernel(Android) 加密算法总结(cipher.compress.digest) 1. Linux内核支持哪些加密算法 ? 内核支持的加密算法很多,包括: 对称加密算法,如AE ...

  8. Android 系统(4)---Android HAL层与Linux Kernel层驱动开发简介

    Android HAL层与Linux Kernel层驱动开发简介 近日稍微对Android中的驱动开发做了一些简要的了解,稍稍理清了一下Android驱动开发的套路,总结一下笔记. HAL:Hardw ...

  9. Android HAL层与Linux Kernel层驱动开发简介

    Android HAL层与Linux Kernel层驱动开发简介 阅读数:5070 近日稍微对Android中的驱动开发做了一些简要的了解,稍稍理清了一下Android驱动开发的套路,总结一下笔记. ...

最新文章

  1. php 运维系统开发,PHP开发运维管理系统笔记
  2. FAGLFLEXA 表和 BSEG 表有什么区别
  3. 天了噜!定义static字段还有顺序要求?
  4. Ocelot——初识基于.Net Core的API网关
  5. 并查集图冲突hdu1272
  6. 程序安装mysql数据库,安装mysql数据库
  7. html5中加入音频,在H5场景中插入自定义音频和视频(任意画面)
  8. ide循环执行用例 selenium_使用Selenium测试Web界面时使用循环控制功能
  9. 剑指offer——面试题41:和为S的连续整数序列
  10. Struts2--类型转换
  11. ECharts地图,echarts自定义map地图,echarts添加标注,自定义坐标、图标、icon
  12. python标准库需不需要导入_Python标准库需要导入吗_后端开发
  13. 微信小程序订阅消息通过服务通知发送
  14. 金仓数据库 KingbaseES 插件参考手册(23. dbms_utility)
  15. VBS word/excel 转 PDF
  16. 年龄在线计算机,年龄计算器在线计算2021 抖音上很火的精确年龄岁数计算器查询 - 房贷计算器...
  17. java之STS使用和相关目录解说、springBoot微服务项目、前后端发送和接收参数的方式、文件图片视频上传
  18. 单芯片无线供电IC 无线充电芯片 无线输电芯片FS68001
  19. 看我如何用云函数撸一个PC小程序代码包在线解密工具
  20. Git-用 cherry-pick 挑好看的小樱桃

热门文章

  1. Javassist使用指南1
  2. (附源码)spring boot火车票订票系统 毕业设计171538
  3. 单点登录:HTTPS相关知识
  4. 8月30日云栖精选夜读:Nodejs进阶:使用DiffieHellman密钥交换算法
  5. 如何设计一个通用的权限管理系统?说的太详细了!
  6. JAVA编程思想笔记 : 并发 [ 一 ]
  7. Haroopad也许不如Typora
  8. 译文 Ceph:一个可扩展,高性能分布式文件系统
  9. Android -- 每日一问:如何设计一个照片上传 app ?
  10. ANSYS apdl命令流笔记8---载荷步与载荷子步的运用