1 /* Accumulate result in local variable */
2 void combine4(vec_ptr v, data_t *dest)
3 {
4 int i;
5 int length = vec_length(v);
6 data_t *data = get_vec_start(v);
7 data_t x = IDENT;
8
9 *dest = IDENT;
10 for (i = 0; i < length; i++) {
11 x = x OPER data[i];
12 }
13 *dest = x;
14 }
在这段code中,如果OPER是加法,那么循环的这部分代码就可以编译成四条指令
1 .L24: loop:
2 addl (%eax,%edx,4),%ecx Multiply x by data[i]
3 incl %edx i++
4 cmpl %esi,%edx Compare i:length
5 jl .L24 If <, goto loop
我们可以看到,实际进行数据计算的就只有 addl一条指令,其余的三条指令都是用来做循环判断的。这就是loop overhead.
那如果我们在每次的循环中,多做几次加法运算,就可以减少loop overhead. 把combine4改写成如下:
1 /* Unroll loop by 3 */
2 void combine5(vec_ptr v, data_t *dest)
3 {
4 int length = vec_length(v);
5 int limit = length-2;
6 data_t *data = get_vec_start(v);
7 data_t x = IDENT;
8 int i;
9
10 /* Combine 3 elements at a time */
11 for (i = 0; i < limit; i+=3) {
12 x = x OPER data[i] OPER data[i+1] OPER data[i+2];
13 }
14
15 /* Finish any remaining elements */
16 for (; i < length; i++) {
17 x = x OPER data[i];
18 }
19 *dest = x;
20 }
这段代码每次循环算了三个值的和,这样就减少了loop overhead。
但是这样其实也有缺点:
1. 因为需要有另一个循环来处理,余下的元素,所以当length较小是,实际上性能变差。
2. 而且这样产生出的代码,要比原来的长。