WEB开发网
开发学院软件开发VC 利用模板元编程实现解循环优化 阅读

利用模板元编程实现解循环优化

 2008-08-09 19:26:08 来源:WEB开发网   
核心提示: 循环点积计算: 编译器甚至连inline也不做了,进行正式的函数调用,利用模板元编程实现解循环优化(9),模板元点击计算:依然就地展开,dim=32:循环点积计算:不展开,优化的第二原则(仅适用于专家)是:还是不要优化,再三测试,调用模板元点积计算:比较有趣的是,编译器也没有将函数就地展开

循环点积计算: 编译器甚至连inline也不做了,进行正式的函数调用。

模板元点击计算:依然就地展开。

dim=32:

循环点积计算:不展开,调用

模板元点积计算:

比较有趣的是,编译器也没有将函数就地展开,而是分成3步。就地计算前9个乘法然后与DotProduct<23,int>的返回值相加。DP<23>也没有就地计算全部,而是计算前11个,然后与DP<12>的返回值相加。

3步计算当中都没有循环。

值得注意的是,循环点积计算函数也没有很老实的按照源代码的方式进行计算,而是进行了不完全的循环展开,类似于如下代码:

template< typename T>
T dot_product(int DIM,const T v1[],const T v2[]) {
  const int step = complierKnow;
  T results[step] = {0};
  int i=0;
  for (;i+step-1<DIM;i+=step) {
    results[0] += v1[i]*v2[i];
    results[1] += v1[i+1]*v2[i+1];
    ...
    results[step-1] += v1[i+step-1]*v2[i+step-1];
  }
  for (;i<DIM;++i)
    results[0] += v1[i]*v2[i];
  return results[0]+result[1]+...result[step-1];
}

DIM和step似乎没有什么固定的规律。

(详细代码见sample2,取不同的dim值即可。)

验证3:

sample2中,编译器对被计算的向量的上下文依然知情:v1,v2在main函数的栈中。

sample3做了小小的改动:dot_product_loop和dot_product_unloop将无从得知传递给它们的向量在何处。(当然,在main函数中,仍然使用函数指针来调用这2个函数,使得编译器不做inline)

sample3得到的结果和sample2基本相同,只是对向量寻址由esp+v1_offset,esp+v2_offset变为[esp+4],[esp+8]

(详细代码见sampl3)

验证4:

在sample3的基础上,通过控制台输入读取dim,使得编译对其不知情。

当然,在这种情况下,是无法使用模板元解循环的,因为它要求dim是编译时常量。

在这种情况下,循环点积计算终于被编译器翻译成真正的“循环”了。

总结:

循环版本有更大的灵活性:在dim为编译时常量时,编译器会根据其大小,进行完全解循环或部分解循环。同时也支持dim为运行时的值。

模板元版本必须使用编译时常量作为dim,而且总是完全解开循环。

循环版本与模板元版本最终都会使用相同次数的乘法与运算,区别在于乘法指令和跳转指令的数目。

模板元版本在dim较大的时候,可能会使用跳转指令,将部分工作交给更小维度的点积计算。但是乘法指令数目与维数一样。

循环版本可能会使用更多的跳转指令,使得乘法指令数目大大减少。

多出的跳转指令会占用运行时间,但也能减少目标代码体积。权衡应该使用那一种版本与权衡某个函数是否应该inline十分相似。

书中17章最后部分也提醒读者,不计后果的解循环并不总是能优化运行时间。

借用大师的观点来结束本文 —— 优化的第一原则是:不要优化。优化的第二原则(仅适用于专家)是:还是不要优化。再三测试,而后优化。

《C++编程规范》 第8条

上一页  4 5 6 7 8 9 

Tags:利用 模板 编程

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接