根据cachegrind的结果显示,这个校验和计算程序是整个应用中指令高速缓存加载和指令高速缓存未命中率最大的贡献者之一。
#include <stdint.h>
namespace {
uint32_t OnesComplementSum(const uint16_t * b16, int len) {
uint32_t sum = 0;
uint32_t a = 0;
uint32_t b = 0;
uint32_t c = 0;
uint32_t d = 0;
// helper for the loop unrolling
auto run8 = [&] {
a += b16[0];
b += b16[1];
c += b16[2];
d += b16[3];
b16 += 4;
};
for (;;) {
if (len > 32) {
run8();
run8();
run8();
run8();
len -= 32;
continue;
}
if (len > 8) {
run8();
len -= 8;
continue;
}
break;
}
sum += (a + b) + (c + d);
auto reduce = [&]() {
sum = (sum & 0xFFFF) + (sum >> 16);
if (sum > 0xFFFF) sum -= 0xFFFF;
};
reduce();
while ((len -= 2) >= 0) sum += *b16++;
if (len == -1) sum += *(const uint8_t *)b16; // add the last byte
reduce();
return sum;
}
} // anonymous namespace
uint32_t get(const uint16_t* data, int length)
{
return OnesComplementSum(data, length);
}
也许是由于循环展开导致的,但生成的目标代码似乎并不过多。
如何改进代码呢?
更新
- 因为校验和函数在匿名命名空间中,所以被内联和复制了两个函数,它们都位于同一个cpp文件中。
- 循环展开仍然是有益的。去掉它会使代码变慢。
改进无限循环可以加速代码(但出于某种原因,在我的Mac上得到相反的结果)。
- 修复之前:您可以看到两个校验和和17210 L1 IR缺失
- 修复之后:在修复内联问题和修复无限循环之后,L1指令缓存缺失下降到8324。
- "InstructionFetch"在修复后的示例中更高。我不确定如何解释这个现象。它只是意味着大部分活动发生在那里吗?还是暗示存在问题?