它可以通过两种方式进行优化,一种是改进算法,技术是在指令级改进它,即尽可能以更快的速度执行每项操作。通过查看您的代码,您似乎正在尝试实现第二个代码,并且您做得非常正确。现代处理器中的一项功能是使用“指令流水线”,它的阶段很少。代码执行顺序是——
IF Instruction Fetch
ID Instruction Decode
EX Execution
Mem Memory access
WB Write Back
这些操作可以并行完成,即当您为操作执行 ID 时,您可以提前为下一个操作执行 IF。在第一种技术中, sum += array[j];
在这个实现中,IF 保持先前的操作完全执行,即由于 CPU 周期停止。IF、ID、EX、Mem、WB 它们都需要 1 个 cpu 周期,因此需要 5 个 cpu 周期来完成完整的指令。但是随着循环展开,
sum += array[j]; // first op
sum += array[j+1]; // second op
sum += array[j+2];
sum += array[j+3];
sum += array[j+4]; // fifth op
在此实现中,在执行第一个 ID 的同时,执行 IF 可在同一周期(即同时)上为第二个执行。在第二个 cpu 周期中,您正在执行第一个操作的 ID 和第二个操作的 IF;在第 3 个周期,您在第三个操作上使用 IF,在第二个操作上使用 ID,在第一个操作上使用 Ex,因此它利用了指令级并行性并减少了停滞的 cpu 周期数。
基于这种技术,优化循环的典型方法是“展开”它,即。循环展开,您可以在此链接中获得“循环展开”和指令管道的完整示意图和详细信息。
为了证明我试图解释的内容,让我们做一个测试。我已经编译了您的代码并创建了两个具有两个不同循环的可执行文件,我使用 perf 来了解事情的进展情况,结果如下:
Performance counter stats for './test':
17739.862565 task-clock # 1.000 CPUs utilized
183 context-switches # 0.010 K/sec
5 cpu-migrations # 0.000 K/sec
138 page-faults # 0.008 K/sec
===> 58,408,599,809 cycles # 3.293 GHz
===> 34,387,134,201 stalled-cycles-frontend # 58.87% frontend cycles idle
===> 4,229,714,038 stalled-cycles-backend # 7.24% backend cycles idle
72,056,092,464 instructions # 1.23 insns per cycle
# 0.48 stalled cycles per insn
6,011,271,479 branches # 338.857 M/sec
618,206 branch-misses # 0.01% of all branches
17.744254427 seconds time elapsed
现在使用展开循环测试:
Performance counter stats for './unroll-loop-test':
2395.115499 task-clock # 1.000 CPUs utilized
22 context-switches # 0.009 K/sec
2 cpu-migrations # 0.001 K/sec
138 page-faults # 0.058 K/sec
====> 7,885,935,372 cycles # 3.293 GHz
====> 1,569,263,256 stalled-cycles-frontend # 19.90% frontend cycles idle
====> 50,629,264 stalled-cycles-backend # 0.64% backend cycles idle
24,911,629,893 instructions # 3.16 insns per cycle
# 0.06 stalled cycles per insn
153,158,495 branches # 63.946 M/sec
607,999 branch-misses # 0.40% of all branches
2.395806562 seconds time elapsed
仔细查看执行的周期数,展开循环 - 停滞周期少得多,因此需要更少的 cpu 周期数,另一方面 - 没有展开 - 停滞周期数消耗更多 cpu 周期,因此很差表现。所以,是的,您正在做非常好的优化,并且他们正在执行相同数量的算术运算。但也要记住,如果你在多处理器系统上运行这个程序,那么另一个优化级别是将整个程序分成几个部分,并将每个部分分配给系统上可用的每个 CPU,这就是所谓的“并行编程”。希望我的回答能澄清你的概念。