Linux平台编译器小技巧
本文介绍Linux
平台上,Gcc
编译套件的优化用法。
分支预测优化
如果在某一个条件判断下,某条分支更有可能发生,或者非常不可能发生,可以通过特定的判断语法来告知编译器,辅助优化。
/** \brief hint for the branch prediction */
constexpr inline bool likely(bool expr)
{
return __builtin_expect(expr, true);
}
/** \brief hint for the branch prediction */
constexpr inline bool unlikely(bool expr)
{
return __builtin_expect(expr, false);
}
// xxx大多数情况为true时,可这样用。
if (likely(xxx)) {
// to do
}
// yyy大多数情况为false时,可这样用.
if (unlikely(yyy)){
// to do
}
结构体定义满足缓存对齐
c++11
引入对齐描述符 alignas
,它接收常量表达式和类型作为参数,可用来修饰变量、类的成员变量等,是往大对齐;与之相反,#pragma pack(n)
是往小的、紧凑方向对齐。
// 定义缓存行大小
#define CACHELINE_SIZE 64
// 定义变量x按照缓存行对齐,单位为字节
#define cache_aligned(x) alignas(CACHELINE_SIZE) x
class CTest{
private:
cache_aligned(volatile bool _running) {false}; /// 运行状态
cache_aligned(std::atomic<int64_t> _index) {-1}; // 初始化序号
};
预读
为减少访问延时,提高性能,可通过Gcc的内置 __builtin_prefetch
指令来预先读取数据。该函数接收三个参数,
void __builtin_prefetch (const void *addr, ...)
addr为要预取的数据地址;它支持两个可选参数:rw
和 locality
。
rw
:表示操作方向,1表示准备写入;0表示读取,默认为0.locality
: 可选值为 0,1,2,3,默认为3.- 0: 该数据无时间局部性,访问之后无需留在缓存中。
- 3:该数据有最高的时间局部性,访问之后还应该在缓存中。
- 1和2:表示较低和较高的时间局部性。
该特性是与硬件相关的,如果硬件不支持,该地址表达式被评估有副作用,那么不会生成优化代码,也不会有警告。
编译期属性
GCC编译器支持__attribute__
机制,可用来设置函数、变量和类型属性,给编译器提供优化指导,增强错误检查能力。
一般开启所有警告选项,按具体情况,打开 -Werror 选项,将警告当做错误处理。
-
函数属性
__attribute__((noreturn))
:告诉编译器该函数没有返回值,可优化掉函数返回代码__attribute__ ((warn_unused_result))
:告诉编译器当该函数返回值在没有被使用时,提示警告。__attribute__ ((always_inline))
:告诉编译器将该函数当做内联函数__attribute__ ((regparm(n)))
:指定最多可使用n个寄存器传递参数,n的范围是0~3,实参超过n时将参数压入栈中。__attribute__((unused))
: 表明该函数或变量可能不使用,不要产生编译警告
-
类型属性
__attribute__ ((packed))
: 告知编译器取消对结构体的对齐优化,按照实际占用字节数进行对齐。
-
变量相关
__builtin_prefetch(x, 0, 0)
: 将变量x预先读取到cache中。该指令可以让目标地址数据所在的整个cache line
从主存中调入cache
,后续的内存读取操作大概率不会触发cache miss