如何提升C++ 代码性能-以loop为例

一个简单的累加

对于C++开发者来说,写一个累加算法是可以说是小菜一碟,但是对于累加算法的性能却各有不同,一个简单的累加算法如下:

int res = 0;
int num = 5000000;
start = std::chrono::system_clock::now();
for (int i = 1; i <= num; i++)
    {
        res += i;
    }
end = std::chrono::system_clock::now();
std::chrono::duration<double> dura = end - start;
std::cout << "共耗时:" << dura.count() << "s" << std::endl;

对于此程序,我们可以测试其性能,测试结果如下:

循环展开-流水线(Pipeline)优化

使用相同变量进行累加

为了优化上述程序,我们可以将循环进行部分展开,以减少循环次数,代码如下:

int res = 0;
int num = 5000000;
start = std::chrono::system_clock::now();
for (int i = 1; i <= num; i+=4)
    {
         res += i;
         res += i + 1;
         res += i + 2;
         res += i + 3;
    }
end = std::chrono::system_clock::now();
std::chrono::duration<double> dura = end - start;
std::cout << "共耗时:" << dura.count() << "s" << std::endl;

此时,我们将循环次数缩小四倍,每次循环时,将四个值累加到res中,性能如下:

可以看到性能提升了0.00463s。

使用不同变量进行累加

int res = 0;
int num = 5000000;
int r0 = 0, r1 = 0, r2 = 0, r3 = 0;
start = std::chrono::system_clock::now();
for (int i = 1; i <= num; i+=4)
    {
        r0 += i;
        r1 += i + 1;
        r2 += i + 2;
        r3 += i + 3;
    }
res = r0 + r1 + r2 + r3;
end = std::chrono::system_clock::now();
std::chrono::duration<double> dura = end - start;
std::cout << "共耗时:" << dura.count() << "s" << std::endl;

此时我们使用不同的变量进行累加,最终再将累加的结果求和,此时性能如下:

此时的性能又有了进一步提升,进一步提升了0.00418s。

register关键字

这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。代码如下:

int res = 0;
int num = 5000000;
register int r4 = 0, r5 = 0, r6 = 0, r7 = 0;
start = std::chrono::system_clock::now();
for (int i = 1; i <= num; i += 4)
    {
        r4 += i;
        r5 += i + 1;
        r6 += i + 2;
        r7 += i + 3;
    }
res1 = r4 + r5 + r6 + r7;
end = std::chrono::system_clock::now();
std::chrono::duration<double> dura = end - start;
std::cout << "共耗时:" << dura.count() << "s" << std::endl;

此时性能如下:

此时性能提升了0.00418s.注意是"尽可能",不是绝对。你想想,一个CPU 的寄存器也就那么几个或几十个,你要是定义了很多很多register 变量,它累死也可能不能全部把这些变量放入寄存器吧。

添加编译优化-O3

gcc提供了大量优化选项,用来对编译时间,目标文件长度,执行效率三个维度进行不同的取舍和平衡。

  • O1优化。 
    在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度
  • O2 优化。 
    该优化选项会牺牲部分编译速度,除了执行-O1所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。
  • O3优化。 
    该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等
  • Os优化。
    这个优化标识和-O3有异曲同工之妙,当然两者的目标不一样,-O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。

我们在上个优化的基础上,给cmake添加O3优化,如下:

set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3  -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3  -Wall")

测试结果如下:

此时性能提升了0.00322s, 可以看到编译器本身对程序优化效果还是很大的。

思考

O3优化本身就有优化展开的优化,和我们的循环展开有冲突吗?

附录

代码: https://github.com/xiaoycolor/cmakestudy

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sirly。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值