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为要预取的数据地址;它支持两个可选参数:rwlocality

  • rw:表示操作方向,1表示准备写入;0表示读取,默认为0.
  • locality: 可选值为 0,1,2,3,默认为3.
    • 0: 该数据无时间局部性,访问之后无需留在缓存中。
    • 3:该数据有最高的时间局部性,访问之后还应该在缓存中。
    • 1和2:表示较低和较高的时间局部性。

该特性是与硬件相关的,如果硬件不支持,该地址表达式被评估有副作用,那么不会生成优化代码,也不会有警告。

编译期属性

GCC编译器支持__attribute__机制,可用来设置函数、变量和类型属性,给编译器提供优化指导,增强错误检查能力。

一般开启所有警告选项,按具体情况,打开 -Werror 选项,将警告当做错误处理。

  • 函数属性

    1. __attribute__((noreturn)):告诉编译器该函数没有返回值,可优化掉函数返回代码
    2. __attribute__ ((warn_unused_result)):告诉编译器当该函数返回值在没有被使用时,提示警告。
    3. __attribute__ ((always_inline)):告诉编译器将该函数当做内联函数
    4. __attribute__ ((regparm(n))):指定最多可使用n个寄存器传递参数,n的范围是0~3,实参超过n时将参数压入栈中。
    5. __attribute__((unused)): 表明该函数或变量可能不使用,不要产生编译警告
  • 类型属性

    1. __attribute__ ((packed)) : 告知编译器取消对结构体的对齐优化,按照实际占用字节数进行对齐。
  • 变量相关

    1. __builtin_prefetch(x, 0, 0) : 将变量x预先读取到cache中。该指令可以让目标地址数据所在的整个cache line从主存中调入cache,后续的内存读取操作大概率不会触发cache miss
posted @ 2021-10-19 09:14  浩天之家  阅读(114)  评论(0编辑  收藏  举报