C 程序性能优化


一、如何衡量程序的运行性能

二、性能优化技巧

1.利用高速缓存

  高速缓存对数据的访问速度是普通内存的上百倍,它对性能的提升,在于两点:时间局部性空间局部性

  时间局部性:被引用过一次的内存位置可能在不远的将来被多次访问。

  空间局部性:如果一个内存位置被引用了一次,那么程序很可能在不久的将来引用其附近的另一个位置。

  CPU 在缓存数据时,会按照局部性原则,缓存第一次访问的内存及其附近的数据,如果每次访问的数据不够连续或者同一数据长时间引用一次,使得缓存总是不被命中,导致直接对内存进行频繁的访问,最终使程序整体性能降低。为了更好的利用高速缓存,可以按照以下几个原则来编写代码:

——尽量确保定义的局部变量能被多次引用;

——在循环结构中,以较短的步长访问数据;

——对于数组结构,使用行优先遍历;

——循环体越小,循环迭代次数越多,则局部性越好;

alignas 关键字

  在计算机内部,高速缓存是以缓存行的形式被组织的,也就是说,一大块连续的高速缓存会被分为多个组,每个组有多个行,每个行有固定的大小,一般为 64 个字节。当缓存不命中时,CPU 会将数据从低层次缓存中以固定的块大小(通常为缓存行大小)拷贝到更高层次的缓存行中。为了减少 CPU 需要进行的内存拷贝次数,我们希望连续的数据被组织在尽可能少的缓存行中。利用 alignas 关键字,将较长的数据设为 64 字节对齐,当这段数据被拷贝到高速缓存中时,会从缓存行的开头处开始放置数据,这在最大程度上的减少了连续数据需要的缓存行数,如下段代码所示:

struct data {

  char x;

  alignas(64) char y[118];

};

  如果没有 64 字节对齐,这个数组可能会占三个缓存行,而现在只占了两个缓存行。

2.利用代码内联

  通过 inline 关键字,可以建议编译器,将某个函数的实现内联到它的实际调用处。通过这种方式,程序不需要通过 call 指令来调用函数,省去了函数帧栈的创建和销毁过程,以节省 CPU 时钟周期。这是一种典型的时间换空间的思想。在函数需要被频繁调用时,这种方式对性能的提升尤为明显。但是,inline 关键字只是对编译器的建议,至于是否会采纳,还要看编译器的具体实现;同时,在高优化等级下,编译器也会自动采用内联对程序进行优化。

3.利用 restrict 关键字

  restrict 关键字只能用于指针类型,用以表明该指针是数据的唯一访问方式

4.消除不必要的内存引用

5.

6.

7.

8.