【发布时间】:2017-10-25 13:59:10
【问题描述】:
我刚刚发现间接成本大约是浮点乘法的 3 倍!
这是可以预期的吗?我的测试错了吗?
背景
阅读How much does pointer indirection affect efficiency? 后,我对间接成本感到恐慌。
由于现代 CPU 的工作方式,通过指针间接寻址可能会慢得多。
在我过早地优化我的真实代码之前,我想确保它真的像我担心的那样花费很多。
我做了一些技巧来找到粗略的数字(3x),如下所示:-
步骤 1
- Test1 : 无间接 -> 计算一些东西
- Test2 :间接 -> 计算一些东西(相同)
我发现 Test2 比 Test1 花费更多时间。
这里没有什么奇怪的。
第二步
- Test1 : 无间接 -> 计算一些昂贵的东西
- Test2:间接 -> 计算一些便宜的东西
我尝试将calculate something expensive 中的代码一点一点地更改为更昂贵,以使两个测试 的成本几乎相同。
结果
最后,我发现使两个测试使用相同时间量(即收支平衡)的可能功能之一是:-
-
Test1 : 无间接 -> 返回
float*float*...3 次 -
Test2 : 间接 -> 只需返回
float
这是我的测试用例 (ideone demo) :-
class C{
public: float hello;
public: float hello2s[10];
public: C(){
hello=((double) rand() / (RAND_MAX))*10;
for(int n=0;n<10;n++){
hello2s[n]= ((double) rand() / (RAND_MAX))*10;
}
}
public: float calculateCheap(){
return hello;
}
public: float calculateExpensive(){
float result=1;
result=hello2s[0]*hello2s[1]*hello2s[2]*hello2s[3]*hello2s[4];
return result;
}
};
这里是主要的:-
int main(){
const int numTest=10000;
C d[numTest];
C* e[numTest];
for(int n=0;n<numTest;n++){
d[n]=C();
e[n]=new C();
}
float accu=0;
auto t1= std::chrono::system_clock::now();
for(int n=0;n<numTest;n++){
accu+=d[n].calculateExpensive(); //direct call
}
auto t2= std::chrono::system_clock::now();
for(int n=0;n<numTest;n++){
accu+=e[n]->calculateCheap(); //indirect call
}
auto t3= std::chrono::system_clock::now();
std::cout<<"direct call time ="<<(t2-t1).count()<<std::endl;
std::cout<<"indirect call time ="<<(t3-t2).count()<<std::endl;
std::cout<<"print to disable compiler cheat="<<accu<<std::endl;
}
直接通话时间和间接通话时间调整为与上述相似(通过编辑calculateExpensive)。
结论
间接成本 = 3x 浮点乘法。
在我的桌面(带有 -O2 的 Visual Studio 2015)中,它是 7x。
问题
是否可以预期间接成本约为浮点乘法的 3 倍?
如果不是,我的测试怎么错了?
(感谢enhzflep提出改进建议,已编辑。)
【问题讨论】:
-
一个
public:访问说明符就足够了。您还使用new运算符泄漏内存。如果你想使用 C++,我建议你忘记你所知道的关于 Java 的一切。 -
@Raw N 是的,先生!但我觉得(java)这样回家。 XD
-
@javaLover - 在没有看到编译器生成的代码的情况下,我不太确定您实际上是在将 13 次乘法的成本与间接相乘的成本进行比较。大多数现代编译器都足够聪明,可以避免从您提供的源代码生成执行 13 次乘法运算的代码。更好的测试是将不同的变量相乘,从而强制编译器生成与源代码包含的一样多的乘法。例如:
a*b*c*d*e*f*g*h*i*j*k*l*m*n -
@enhzflep 哦,我的错。我改进后,它变成了3x-6x。 (编辑添加)谢谢。在您看来,现在是一个合理的数字吗?
-
还应该注意的是,您的成本的很大一部分不会纯粹是由于间接性,而是更有可能部分是由于内存碎片。请注意,您调用了
new C()100'000 次。这将在你的内存中创建 100'000 个 C scatter 实例。分配为数组 (new C[numTest]) 可能会产生完全不同的结果。次要补充:像这样C d[numTest] = {};初始化将在每个元素上调用构造函数
标签: c++ optimization c++14 indirection