分类: LINUXhtml
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
你们看了就明白是什么意思了。可是我还有几点疑问:
(1)
(void) (&_min1 == &_min2);这行代码是用来干什么的?
(2)为何{}的外面要加(),不加的时候编译是不经过的,具体是什么缘由?
2 范围的扩展
(1) switch 语句
switch(a)
{
case 1 ... 3:
printf("fafadsf");
break;
case 4 ... 8:
printf("dsafaf");
break;
}
(2)数组的初始化
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
以上部份内核中用的不少。
3 零长度的数组
struct iso_block_store {
atomic_t refcount;
size_t data_size;
quadlet_t data[0];
};
这容许结构中的元素引用结构实例后面紧接着的内存。在须要数量可变的数组成员时,这个特性颇有用
应用实例:
struct iso_block_store * p =(void *)malloc(sizeof(struct iso_block_store) + data_size);
4 得到函数的返回地址
以下面的代码所示,__builtin_return_address
接收一个称为 level
的参数。这个参数定义但愿获取返回地址的调用堆栈级别。例如,若是指定 level
为 0
,那么就是请求当前函数的返回地址。若是指定 level
为 1
,那么就是请求进行调用的函数的返回地址,依此类推。linux
void * __builtin_turn_address( unsigned int level ); |
在下面的示例中(见 ./linux/kernel/softirq.c),local_bh_disable
函数在本地处理器上禁用软中断,从而禁止在当前处理器上运行 softirqs、tasklets 和 bottom halves。使用 __builtin_return_address
捕捉返回地址,以便在之后进行跟踪时使用这个地址。编程
void local_bh_disable(void) |
在编译时,可使用 GCC 提供的一个内置函数判断一个值是不是常量。这种信息很是有价值,由于能够构造出可以经过常量叠算(constant folding)优化的表达式。__builtin_constant_p
函数用来检测常量。缓存
__builtin_constant_p
的原型以下所示。注意,__builtin_constant_p
并不能检测出全部常量,由于 GCC 不容易证实某些值是不是常量。函数
int __builtin_constant_p( exp ) |
Linux 至关频繁地使用常量检测。在清单 3 所示的示例中(见 ./linux/include/linux/log2.h),使用常量检测优化 roundup_pow_of_two
宏。若是发现表达式是常量,那么就使用能够优化的常量表达式。若是表达式不是常量,就调用另外一个宏函数把值向上取整到 2 的幂。性能
|
GCC 提供许多函数级属性,能够经过它们向编译器提供更多数据,帮助编译器执行优化。本节描述与功能相关联的一些属性。优化
属性经过其余符号定义指定了别名。能够以此帮助阅读源代码参考,了解属性的使用方法(见 ./linux/include/linux/compiler-gcc3.h)。ui
|
定义是 GCC 中可用的一些函数属性。它们也是在 Linux 内核中最有用的函数属性。下面解释如何使用这些属性:
always_inline
让 GCC 之内联方式处理指定的函数,不管是否启用了优化。deprecated
指出函数已经被废弃,不该该再使用。若是试图使用已经废弃的函数,就会收到警告。还能够对类型和变量应用这个属性,促使开发人员尽量少使用它们。__used__
告诉编译器不管 GCC 是否发现这个函数的调用实例,都要使用这个函数。这对于从汇编代码中调用 C 函数有帮助。__const__
告诉编译器某个函数是无状态的(也就是说,它使用传递给它的参数生成要返回的结果)。warn_unused_result
让编译器检查全部调用者是否都检查函数的结果。这确保调用者适当地检验函数结果,从而可以适当地处理错误。下面是在 Linux 内核中使用这些属性的示例。deprecated
示例来自与体系结构无关的内核(./linux/kernel/resource.c),const
示例来自 IA64 内核源代码(./linux/arch/ia64/kernel/unwind.c)。
int __deprecated __check_region(struct resource |
在 Linux 内核中最经常使用的优化技术之一是 __builtin_expect
。在开发人员使用有条件代码时,经常知道最可能执行哪一个分支,而哪一个分支不多执行。若是编译器知道这种预测信息,就能够围绕最可能执行的分支生成最优的代码。
以下所示,__builtin_expect
的使用方法基于两个宏 likely
和 unlikely
(见 ./linux/include/linux/compiler.h)。
#define likely(x) __builtin_expect(!!(x), 1) |
经过使用 __builtin_expect
,编译器能够作出符合提供的预测信息的指令选择决策。这使执行的代码尽量接近实际状况。它还能够改进缓存和指令流水线。
例 如,若是一个条件标上了 “likely”,那么编译器能够把代码的 True 部分直接放在分支指令后面(这样就不须要执行分支指令)。经过分支指令访问条件结构的 False 部分,这不是最优的方式,可是访问它的可能性不大。按照这种方式,代码对于最可能出现的状况是最优的。
下面给出一个使用 likely
和 unlikely
宏的函数(见 ./linux/net/core/datagram.c)。这个函数预测 sum
变量将是零(数据包的 checksum
是有效的),并且 ip_summed
变量不等于 CHECKSUM_HW
。
|
另外一种重要的性能改进方法是把必需的数据缓存在接近处理器的地方。缓存能够显著减小访问数据花费的时间。大多数现代处理器都有三类内存:
为了尽量减小访问延时并由此提升性能,最好把数据放在最近的内存中。手工执行这个任务称为预抓取。GCC 经过内置函数 __builtin_prefetch
支持数据的手工预抓取。在须要数据以前,使用这个函数把数据放到缓存中。以下所示,__builtin_prefetch
函数接收三个参数:
rw
参数,使用它指明预抓取数据是为了执行读操做,仍是执行写操做locality
参数,使用它指定在使用数据以后数据应该留在缓存中,仍是应该清除
void __builtin_prefetch( const void *addr, int rw, int locality ); |
Linux 内核常用预抓取。一般是经过宏和包装器函数使用预抓取。下面是一个辅助函数示例,它使用内置函数的包装器(见 ./linux/include/linux/prefetch.h)。这个函数为流操做实现预抓取机制。使用这个函数一般能够减小缓存缺失和停顿,从而 提升性能。
|
除了本文前面讨论的函数属性以外,GCC 还为变量和类型定义提供了属性。最重要的属性之一是 aligned
属性,它用于在内存中实现对象对齐。除了对于性能很重要以外,某些设备或硬件配置也须要对象对齐。aligned
属性有一个参数,它指定所需的对齐类型。
下面的示例用于软件暂停(见 ./linux/arch/i386/mm/init.c)。在须要页面对齐时,定义 PAGE_SIZE
对象。
char __nosavedata swsusp_pg_dir[PAGE_SIZE] |
packed
属性打包一个结构的元素,从而尽量减小它们占用的空间。这意味着,若是定义一个 char
变量,它占用的空间不会超过一字节(8 位)。位字段压缩为一位,而不会占用更多存储空间。__attribute__
声明进行优化,它用逗号分隔的列表定义多个属性。
|
分类: LINUX
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
你们看了就明白是什么意思了。可是我还有几点疑问:
(1)
(void) (&_min1 == &_min2);这行代码是用来干什么的?
(2)为何{}的外面要加(),不加的时候编译是不经过的,具体是什么缘由?
2 范围的扩展
(1) switch 语句
switch(a)
{
case 1 ... 3:
printf("fafadsf");
break;
case 4 ... 8:
printf("dsafaf");
break;
}
(2)数组的初始化
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
以上部份内核中用的不少。
3 零长度的数组
struct iso_block_store {
atomic_t refcount;
size_t data_size;
quadlet_t data[0];
};
这容许结构中的元素引用结构实例后面紧接着的内存。在须要数量可变的数组成员时,这个特性颇有用
应用实例:
struct iso_block_store * p =(void *)malloc(sizeof(struct iso_block_store) + data_size);
4 得到函数的返回地址
以下面的代码所示,__builtin_return_address
接收一个称为 level
的参数。这个参数定义但愿获取返回地址的调用堆栈级别。例如,若是指定 level
为 0
,那么就是请求当前函数的返回地址。若是指定 level
为 1
,那么就是请求进行调用的函数的返回地址,依此类推。
void * __builtin_turn_address( unsigned int level ); |
在下面的示例中(见 ./linux/kernel/softirq.c),local_bh_disable
函数在本地处理器上禁用软中断,从而禁止在当前处理器上运行 softirqs、tasklets 和 bottom halves。使用 __builtin_return_address
捕捉返回地址,以便在之后进行跟踪时使用这个地址。
void local_bh_disable(void) |
在编译时,可使用 GCC 提供的一个内置函数判断一个值是不是常量。这种信息很是有价值,由于能够构造出可以经过常量叠算(constant folding)优化的表达式。__builtin_constant_p
函数用来检测常量。
__builtin_constant_p
的原型以下所示。注意,__builtin_constant_p
并不能检测出全部常量,由于 GCC 不容易证实某些值是不是常量。
int __builtin_constant_p( exp ) |
Linux 至关频繁地使用常量检测。在清单 3 所示的示例中(见 ./linux/include/linux/log2.h),使用常量检测优化 roundup_pow_of_two
宏。若是发现表达式是常量,那么就使用能够优化的常量表达式。若是表达式不是常量,就调用另外一个宏函数把值向上取整到 2 的幂。
|
GCC 提供许多函数级属性,能够经过它们向编译器提供更多数据,帮助编译器执行优化。本节描述与功能相关联的一些属性。
属性经过其余符号定义指定了别名。能够以此帮助阅读源代码参考,了解属性的使用方法(见 ./linux/include/linux/compiler-gcc3.h)。
|
定义是 GCC 中可用的一些函数属性。它们也是在 Linux 内核中最有用的函数属性。下面解释如何使用这些属性:
always_inline
让 GCC 之内联方式处理指定的函数,不管是否启用了优化。deprecated
指出函数已经被废弃,不该该再使用。若是试图使用已经废弃的函数,就会收到警告。还能够对类型和变量应用这个属性,促使开发人员尽量少使用它们。__used__
告诉编译器不管 GCC 是否发现这个函数的调用实例,都要使用这个函数。这对于从汇编代码中调用 C 函数有帮助。__const__
告诉编译器某个函数是无状态的(也就是说,它使用传递给它的参数生成要返回的结果)。warn_unused_result
让编译器检查全部调用者是否都检查函数的结果。这确保调用者适当地检验函数结果,从而可以适当地处理错误。下面是在 Linux 内核中使用这些属性的示例。deprecated
示例来自与体系结构无关的内核(./linux/kernel/resource.c),const
示例来自 IA64 内核源代码(./linux/arch/ia64/kernel/unwind.c)。
int __deprecated __check_region(struct resource |
在 Linux 内核中最经常使用的优化技术之一是 __builtin_expect
。在开发人员使用有条件代码时,经常知道最可能执行哪一个分支,而哪一个分支不多执行。若是编译器知道这种预测信息,就能够围绕最可能执行的分支生成最优的代码。
以下所示,__builtin_expect
的使用方法基于两个宏 likely
和 unlikely
(见 ./linux/include/linux/compiler.h)。
#define likely(x) __builtin_expect(!!(x), 1) |
经过使用 __builtin_expect
,编译器能够作出符合提供的预测信息的指令选择决策。这使执行的代码尽量接近实际状况。它还能够改进缓存和指令流水线。
例 如,若是一个条件标上了 “likely”,那么编译器能够把代码的 True 部分直接放在分支指令后面(这样就不须要执行分支指令)。经过分支指令访问条件结构的 False 部分,这不是最优的方式,可是访问它的可能性不大。按照这种方式,代码对于最可能出现的状况是最优的。
下面给出一个使用 likely
和 unlikely
宏的函数(见 ./linux/net/core/datagram.c)。这个函数预测 sum
变量将是零(数据包的 checksum
是有效的),并且 ip_summed
变量不等于 CHECKSUM_HW
。
|
另外一种重要的性能改进方法是把必需的数据缓存在接近处理器的地方。缓存能够显著减小访问数据花费的时间。大多数现代处理器都有三类内存:
为了尽量减小访问延时并由此提升性能,最好把数据放在最近的内存中。手工执行这个任务称为预抓取。GCC 经过内置函数 __builtin_prefetch
支持数据的手工预抓取。在须要数据以前,使用这个函数把数据放到缓存中。以下所示,__builtin_prefetch
函数接收三个参数:
rw
参数,使用它指明预抓取数据是为了执行读操做,仍是执行写操做locality
参数,使用它指定在使用数据以后数据应该留在缓存中,仍是应该清除
void __builtin_prefetch( const void *addr, int rw, int locality ); |
Linux 内核常用预抓取。一般是经过宏和包装器函数使用预抓取。下面是一个辅助函数示例,它使用内置函数的包装器(见 ./linux/include/linux/prefetch.h)。这个函数为流操做实现预抓取机制。使用这个函数一般能够减小缓存缺失和停顿,从而 提升性能。
|
除了本文前面讨论的函数属性以外,GCC 还为变量和类型定义提供了属性。最重要的属性之一是 aligned
属性,它用于在内存中实现对象对齐。除了对于性能很重要以外,某些设备或硬件配置也须要对象对齐。aligned
属性有一个参数,它指定所需的对齐类型。
下面的示例用于软件暂停(见 ./linux/arch/i386/mm/init.c)。在须要页面对齐时,定义 PAGE_SIZE
对象。
char __nosavedata swsusp_pg_dir[PAGE_SIZE] |
packed
属性打包一个结构的元素,从而尽量减小它们占用的空间。这意味着,若是定义一个 char
变量,它占用的空间不会超过一字节(8 位)。位字段压缩为一位,而不会占用更多存储空间。__attribute__
声明进行优化,它用逗号分隔的列表定义多个属性。
|