跳到主要内容

代码优化手法

为什么要消除循环中的低效率计算?​

  • 问题: 循环条件或循环体内反复求值的表达式, 结果并不随迭代改变;
  • 做法: 把它移到循环体外, 只计算一次;
/* 优化前: 每次迭代都要调用一次 vec_length */
for (i = 0; i < vec_length(v); i++) { ... }

/* 优化后 */
long length = vec_length(v);
for (i = 0; i < length; i++) { ... }

为什么要消除不必要的内存引用?​

  • 问题: 反复读写指针指向的目标, 每次迭代都要访存;
  • 做法: 用临时变量保存中间结果, 循环结束后一次性写回;
  • 收益: 减少内存读写次数, 让累加值留在寄存器中;
data_t acc = IDENT;
for (i = 0; i < length; i++) {
acc = acc OP data[i];
}
*dest = acc;

循环展开怎样减少开销?​

  • 做法: 每次迭代处理多个元素, 从而减少迭代次数;
  • 收益: 减少索引计算与条件分支的次数;
  • 形式: 2×1 展开表示每轮循环处理 2 个元素、只使用 1 个累加器;
/* 2x1 loop unrolling */
long limit = length - 1;
data_t acc = IDENT;
for (i = 0; i < limit; i += 2) {
acc = (acc OP data[i]) OP data[i + 1];
}
for (; i < length; i++) {
acc = acc OP data[i];
}
*dest = acc;

分支预测和惩罚怎样影响优化?​

  • 建议: 让 if 条件的走向尽量一致, 便于 CPU 预测;
  • 替代: 用条件运算符代替 if 语句, 让编译器生成条件传送指令;