通过实例了解uprobe及其对性能的影响-爱代码爱编程
前言
uprobe是用户空间探针的意思,可以用来给用户程序的任何地方下探针,不仅仅是函数粒度层级的。所以异常灵活。
如果不熟悉ftrace、uprobe, 可参考以下文档:
https://www.kernel.org/doc/Documentation/trace/ftrace.txt
https://www.kernel.org/doc/Documentation/trace/uprobetracer.txt
市面上有很多关于uprobe用法及原理的讨论,但是关于其性能方面的还比较少,本文就通过一个例子简单讲讲,同时读者也能从中直观的看到如何使用uprobe.
试验
#include<unistd.h>
#include <stdio.h>
#include <time.h>
long Fibon(int n)
{
long f1 = 1;
long f2 = 1;
long f3 = 1;
for(int i=2; i<n; i++)
{
f3 = f1+f2;
f1 = f2;
f2 = f3;
}
return f3;
}
clock_t start,stop;
double duration;
int main()
{
printf("beginning...\n");
start=clock();
int n=90;
for(int j=0; j<10000; j++){
for(int i=1;i<n;i++){
Fibon(i);
}
}
stop=clock();
duration=((double)(stop-start));
printf("ending..., cost=%f\n", duration);
getchar();
}
gcc fibon.c -o fibon
运行90*10000次Fibon函数,如果不启用uprobe,需要
ending…, cost=168160.000000, 单位不管。
下面启用uprobe:
cd /sys/kernel/debug/tracing
echo 'p:fib /root/perf-tools/bin/fibon:0x666 %di' > uprobe_events
echo 1 > events/uprobes/enable
echo 1 > tracing_on
cat trace_pipe
0x616是函数Fibon相对于fibon二进制文件的偏移(偏移可以是任何地方,此处定为Fibon函数的起始位置, 也可以用Fibon代替),%di是Fibon函数的第一个参数。
trace_pipe的输出:
<...>-1212121 [000] d... 51234725.814331: fib: (0x400666) arg1=0x1
<...>-1212121 [000] d... 51234725.814332: fib: (0x400666) arg1=0x2
<...>-1212121 [000] d... 51234725.814333: fib: (0x400666) arg1=0x3
<...>-1212121 [000] d... 51234725.814334: fib: (0x400666) arg1=0x4
...
花费的时间:
# ./fibon
beginning...
ending..., cost=1216286.000000
168160 VS 1216286
大概慢了7倍。也就是探针花费的时间大概相当于6个Fibon函数自身的时间。
uprobe的原理大概是:
executable+offset处的代码会被替换成int3 -> 执行到此会触发SIGTRAP -> 转向内核处理中断 -> 转向用户态执行uprobe代码-> 继续执行原来的代码。内核与用户态的转换比较耗时。
executable+offset处的代码会被替换成int3(0xCC):
(gdb) disass Fibon
Dump of assembler code for function Fibon:
0x0000000000400666 <+0>: *int3*
0x0000000000400667 <+1>: mov %rsp,%rbp
0x000000000040066a <+4>: mov %edi,-0x24(%rbp)
0x000000000040066d <+7>: movq $0x1,-0x8(%rbp)
关闭uprobe后,指令恢复:
(gdb) disass Fibon
Dump of assembler code for function Fibon:
0x0000000000400666 <+0>: push %rbp
0x0000000000400667 <+1>: mov %rsp,%rbp
0x000000000040066a <+4>: mov %edi,-0x24(%rbp)
如果于0x667处下探针:
(gdb) disass Fibon
Dump of assembler code for function Fibon:
0x0000000000400666 <+0>: push %rbp
0x0000000000400667 <+1>: int3
0x0000000000400668 <+2>: mov %esp,%ebp
0x000000000040066a <+4>: mov %edi,-0x24(%rbp)
好了,春节期间,简单写写。