Haproxy代码分析系列-一些小的Tips

  • likely与unlikely
    #define likely(x) (__builtin_expect((x) != 0, 1))
    #define unlikely(x) (__builtin_expect((x) != 0, 0)) 
    这个宏定义主要是告诉编译器x变量更可能是1或者是0,方便编译器进行分支优化,__builtin_expect是gcc的一个宏,并没有改变变量x的值
    例如,程序:
    #define LIKELY(x) __builtin_expect((x) != 0, 1)
    #define UNLIKELY(x) __builtin_expect((x) != 0, 0)
    int test_likely(int x)
    {
            if(LIKELY(x))
            {
                    x=2;
            }
            else
            {
                    x=3;
            }
            return x;
    }
    int test_unlikely(int x)
    {
            if(UNLIKELY(x))
            {
                    x=2;
            }
            else
            {
                    x=3;
            }
            return x;
    }
    编译查看其汇编代码:gcc -fprofile-arcs -O2 -c like.c
    objdump -d like.o 
    0000000000000000 <test_unlikely>:
       0:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 8 <test_unlikely+0x8>
       7:   01 
       8:   85 ff                   test   %edi,%edi
       a:   75 0e                   jne    1a <test_unlikely+0x1a> 此处认为条件判断不成立可能性更大
       c:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 14 <test_unlikely+0x14>
      13:   01 
      14:   b8 03 00 00 00          mov    $0x3,%eax
      19:   c3                      retq   
      1a:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 22 <test_unlikely+0x22>
      21:   01 
      22:   b8 02 00 00 00          mov    $0x2,%eax
      27:   c3                      retq   
      28:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
      2f:   00 
    
    0000000000000030 <test_likely>:
      30:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 38 <test_likely+0x8>
      37:   01 
      38:   85 ff                   test   %edi,%edi
      3a:   74 0e                   je     4a <test_likely+0x1a> 此处认为很可能比较成立
      3c:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 44 <test_likely+0x14>
      43:   01 
      44:   b8 02 00 00 00          mov    $0x2,%eax
      49:   c3                      retq   
      4a:   48 83 05 00 00 00 00    addq   $0x1,0(%rip)        # 52 <test_likely+0x22>
      51:   01 
      52:   b8 03 00 00 00          mov    $0x3,%eax
      57:   c3                      retq   
      58:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  • REGPRM1-3
haproxy中出现很多这种函数标示,宏定义是:
#ifndef REGPRM1
#if CONFIG_REGPARM >= 1 && __GNUC__ >= 3
#define REGPRM1	__attribute__((regparm(1)))
#else
#define REGPRM1
#endif
#endif

#ifndef REGPRM2
#if CONFIG_REGPARM >= 2 && __GNUC__ >= 3
#define REGPRM2	__attribute__((regparm(2)))
#else
#define REGPRM2 REGPRM1
#endif
#endif

#ifndef REGPRM3
#if CONFIG_REGPARM >= 3 && __GNUC__ >= 3
#define REGPRM3	__attribute__((regparm(3)))
#else
#define REGPRM3 REGPRM2
#endif
#endif
主要用到__attribute__,该关键字可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。比如我们指定 __attribute__((regparm(0))) ,则表示不用寄存器来传递参数,所有参数都通过堆栈来传递;如果我们指定 __attribute__((regparm(3))),那么就是说会用 3 个寄存器来传递参数(EAX, EDX, ECX),其余的参数通过堆栈来传递。
  • syscall1-3
大多数系统调用都在各种C语言函数库中有所实现,所以在一般情况下,我们都可以像调用普通的库函数那样调用系统调用,只在极个别的情况下,我们才有机会用到_syscall*()这几个宏,在unistd.h中定义了7个宏:
syscall0(type,name)
_syscall1(type,name,type1,arg1)
_syscall2(type,name,type1,arg1,type2,arg2)
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)
_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)
_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,static _syscall1 (int, epoll_create, int, size);
它们的作用是形成相应的系统调用函数原型,供我们在程序中调用,这是系统调用的标准用法。我们很容易就能发现规律,_syscall后面的数字和typeN,argN的数目一样 多。事实上,_syscall后面跟的数字指明了展开后形成函数的参数的个数,比如:
static _syscall1 (int, epoll_create, int, size);
展开之后是:
int epoll_create(int size)
{
    long __res;
    __asm__ volatile("int $0x80" : "=a" (__res) : "0" (13),"b" ((long)(tloc)));
    do {
        if ((unsigned long)(__res) >= (unsigned long)(-125)) {
            errno = -(__res);
            __res  = -1;
        }
        return (int) (__res);
    } while (0) ;
}
可以看出,static _syscall1 (int, epoll_create, int, size);展开成一个名为epoll_create的函数,原参数int就是函数的返回类型,原参数int和size分别构成新函数的参数。函数中相当于把epoll_create引用进来设为static
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值