# define unlikely(x) (__builtin_constant_p(x) ? ! !(x) :
__branch_check__(x, 0)) /*__builtin_constant_p()是gcc 专用函数
如果x在编译的时候就能获得常值,则为TRUE;如果是变量则为FALSE
||||||||||||||||||__branch_check__(x, expect) 同一个文件*/
#endif
#define __branch_check__(x, expect) ({ \ /*记录当前的trace点,并用后面的函数ftrace_likely_update记录likely的正确性,结果保存在ring buffer中。*/
int ______r;
\
static int ftrace_branch_data /*定义在本文件中*/
\
__attribute__((__aligned__(4)))
\
__attribute__((section("_ftrace_annotated_brach"))) \
________f = {
\
.func = __func___, /*这是宏定义见下面*/
\
.file = __FILE__, /*这些元素都是标志trace节点*/
\
.line = __LINE__,
\
};
\
______r = likely_notrace(x); /*likely_notrace和unlilely_notrace宏使用__builtin_expect函数,告诉编译器程序设计者期望的比较结果,以便编译器对代码进行优化,改变汇编中的跳转语句*/
\
ftrace_likely_update(&______f, ______r, expect); \
_____r;
\
})
#define likely_notrace(x) __builtin_expect(! !(x), 1) /*期望运行可以说这里对应到 jne ,如果命中了,那么就返回1。*/
#define unlikely_notrace(x) __builtin_expect(! !(x), 0) /*这里对应到je,如果期望不继续追逐*/
struct ftrace_branch_data { /*结构体用于记录ftrace branch的trace记录*/
const char *func;
const char *file;
unsigned line;
union {
struct {
unsigned long correct;
unsigned long incorrect;
};
struct {
unsigned long miss;
unsigned long hit;
};
unsigned long miss_hit[2];
};
};0000000
:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax /*这应该是取那个测试参数*/
6: 83 05 38 00 00 00 01 addl $0x1,0x38
d: 83 15 3c 00 00 00 00 adcl $0x0,0x3c
14: 85 c0 test %eax,%eax
16: 74 15 je 2d /*如果是 %eax是0的时候,zf边成1,就跳转.这就是test_likely的好处,为以后最可能的跳转准备好了一切。*/
18: 83 05 40 00 00 00 01 addl $0x1,0x40
1f: b8 05 00 00 00 mov $0x5,%eax
24: 83 15 44 00 00 00 00 adcl $0x0,0x44
2b: 5d pop %ebp
2c: c3 ret /*注意这里如果没有跳转,就已经返回了*/
---------------------------
以下就是修改地址部分*/
2d: 83 05 48 00 00 00 01 addl $0x1,0x48/*48 00 00 00 是32位地址,储存地址是大端模式。*/
34: b8 06 00 00 00 mov $0x6,%eax /*修改地址,以变成不同的分支*/
39: 83 15 4c 00 00 00 00 adcl $0x0,0x4c
40: 5d pop %ebp
41: c3 ret
42: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
49: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi /*这里是nop指令的汇编写法,占用可以看到是7个字节,而运行长字节指令快于多个短字节指令,0*0所以就用快的!*/
对于__FILE__,__LINE__,__func__这样的宏,在调试程序时是很有用的,因为你可以很容易的知道程序运行到了哪个文件的那一行,是哪个函数。
下面一个例子是打印上面这些预定义的宏的。
#include
#include
void why_me();
int main()
{
printf( "The file is %s.\n", __FILE__ );
printf( "The date is %s.\n", __DATE__ );
printf( "The time is %s.\n", __TIME__ );
printf( "This is line %d.\n", __LINE__ );
printf( "This function is %s.\n", __func__ );
why_me();
return 0;
}
void why_me()
{
printf( "This function is %s\n", __func__ );
printf( "The file is %s.\n", __FILE__ );
printf( "This is line %d.\n", __LINE__ );
} ./funcline
The file is funcline.c
The date is Sep 28 2011
The time is 10:21:54.
This is line 15
This function is main.
This function is why_me
The file is funcline.c
This is line 25
Gcc的内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数EXP 的值是常数,函数返回 1,否则返回 0。例如:
++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) /
250: (__builtin_constant_p(nr) ? /
251: constant_test_bit((nr),(addr)) : /
252: variable_test_bit((nr),(addr)))
很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。
在VDSP5中没有应的东西,因此直接在config.h中定义:
#define __builtin_constant_p(x) (0)
阅读(1936) | 评论(0) | 转发(0) |