Chinaunix首页 | 论坛 | 博客

分类: LINUX

2011-10-09 21:54:34

# 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)
阅读(1866) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~