问题描述
|
我在热点代码中有一个虚函数,因此需要返回一个结构。我有两个选择:
virtual Vec4 generateVec() const = 0; // return value
virtual void generateVec(Vec4& output) const = 0; // output parameter
我的问题是,这些功能的性能一般是否有差异?我认为第二个更快,因为它不涉及在堆栈上复制数据。但是,第一个通常更方便使用。如果第一个仍然稍微慢一点,这是否可以测量?我也迷恋吗:)
让我强调一下,此函数每秒将被调用数百万次,而且结构Vec4的大小很小-16个字节。
解决方法
如前所述,尝试一下-但是您很可能会发现ѭ1实际上更快。返回值优化将避免复制操作,而
void generateVec(Vec4& output)
可能会不必要地初始化output
参数。
有什么方法可以避免将函数虚拟化?如果您每秒调用数百万次,则值得研究一下额外的间接级别。
, 每秒调用数百万次的代码意味着您确实确实需要优化速度。
根据派生的generateVec主体的复杂程度,两者之间的差异可能不明显,也可能很大。
最好的选择是同时尝试它们和配置文件,以查看是否需要担心优化代码的这一特定方面。
, 感觉有点无聊,所以我想到了这个:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
struct A {
int n[4];
A() {
n[0] = n[1] = n[2] = n[3] = rand();
}
};
A f1() {
return A();
}
A f2( A & a ) {
a = A();
}
const unsigned long BIG = 100000000;
int main() {
unsigned int sum = 0;
A a;
clock_t t = clock();
for ( unsigned int i = 0; i < BIG; i++ ) {
a = f1();
sum += a.n[0];
}
cout << clock() - t << endl;
t = clock();
for ( unsigned int i = 0; i < BIG; i++ ) {
f2( a );
sum += a.n[0];
}
cout << clock() - t << endl;
return sum & 1;
}
-O2优化的结果是没有显着差异。
, 第一种解决方案有可能更快。
一篇非常好的文章:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
, 出于好奇,我编写了2个类似的函数(使用8字节数据类型)来检查其汇编代码。
long long int ret_val()
{
long long int tmp(1);
return tmp;
}
// ret_val() assembly
.globl _Z7ret_valv
.type _Z7ret_valv,@function
_Z7ret_valv:
.LFB0:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp,%ebp
.cfi_offset 5,-8
.cfi_def_cfa_register 5
subl $16,%esp
movl $1,-8(%ebp)
movl $0,-4(%ebp)
movl -8(%ebp),%eax
movl -4(%ebp),%edx
leave
ret
.cfi_endproc
令人惊讶的是,下面的按值传递方法还需要一些说明:
void output_val(long long int& value)
{
long long int tmp(2);
value = tmp;
}
// output_val() assembly
.globl _Z10output_valRx
.type _Z10output_valRx,@function
_Z10output_valRx:
.LFB1:
.cfi_startproc
.cfi_personality 0x0,%esp
movl $2,-4(%ebp)
movl 8(%ebp),%ecx
movl -8(%ebp),%edx
movl %eax,(%ecx)
movl %edx,4(%ecx)
leave
ret
.cfi_endproc
这些功能在测试代码中的调用方式为:
long long val = ret_val();
long long val2;
output_val(val2);
由gcc编译。