Fum*_*Eda 14 c++ embedded stack operator-overloading
我正在尝试创建一个C++类,其行为与内置int类型完全相同,只有一个例外:调用operator*(或operator*=)的地方,而是调用addition.
起初,我班级的表现很差(内置int类型的1/2 ),但我注意到这是因为我忘了在下面包含复制构造函数:
struct AlmostInt {
AlmostInt () { }
AlmostInt (const AlmostInt &a) : val(a.val) { } // forgetting this killed
// performance
AlmostInt operator+(const AlmostInt &a) const { AlmostInt result = *this;
result.val += a.val;
return result; }
AlmostInt operator-(const AlmostInt &a) const { AlmostInt result = *this;
result.val -= a.val;
return result; }
AlmostInt operator*(const AlmostInt &a) const { AlmostInt result = *this;
result.val = result.val + a.val;
return result; }
AlmostInt &operator+=(const AlmostInt &a) { this->val += a.val;
return *this; }
AlmostInt &operator-=(const AlmostInt &a) { this->val -= a.val;
return *this; }
AlmostInt &operator*=(const AlmostInt &a) { this->val = this->val + a.val);
return *this; }
private:
int val;
};
Run Code Online (Sandbox Code Playgroud)
不幸的是,我的程序仍然比它应该慢25%.检查为程序的两个不同版本生成的程序集(一个使用int,另一个使用AlmostInt),我看到有相同数量的+和 - 操作,所以事情在某种程度上"正常".
问题是使用AlmostInt类而不是本机int操作的代码中有明显更多的加载和存储操作.
有没有人对这个开销可能来自哪里有任何想法?我唯一的猜测是,也许编译器不理解AlmostInt具有所有相同属性的东西int(例如关联性,交换性),但如果这确实是一个问题,我会期望不同数量的'+'或' -代码中的说明,这不会发生.
我怀疑额外的加载和存储与额外的堆栈活动有关,但我现在可以说的是,它不仅仅是一些额外的堆栈加载和存储在每个函数的顶部和底部,而是额外的负载和商店在整个代码中出现.
有任何想法吗?我不知道是否有人可以点我一个编译器,它允许一个以达到int与自定义类的绩效水平.
更新:
这是一个简单的功能,你可以剪切和粘贴,看看你自己发生了什么.在x86-64 Linux(g ++ 4.3,4.4),AIX6 xlC和其他几个平台上,更改下面的"CHOOSE ONE ..."行应该会生成相同的代码(或至少代码具有相同的性能) ,但在实践中,代码显着膨胀.任何人都可以解释发生了什么(对于任何特定的平台/编译器),或者如何解决它?
class AlmostInt
{
int value;
public:
AlmostInt& operator+=(AlmostInt that)
{
value += that.value;
return *this;
}
AlmostInt& operator-=(AlmostInt that)
{
value -= that.value;
return *this;
}
AlmostInt& operator*=(AlmostInt that)
{
value *= that.value;
return *this;
}
};
AlmostInt operator+(AlmostInt lhs, AlmostInt rhs)
{
lhs += rhs;
return lhs;
}
AlmostInt operator-(AlmostInt lhs, AlmostInt rhs)
{
lhs -= rhs;
return lhs;
}
AlmostInt operator*(AlmostInt lhs, AlmostInt rhs)
{
lhs *= rhs;
return lhs;
}
// CHOOSE ONE OF THE FOLLOWING TWO LINES:
//typedef int real;
typedef AlmostInt real;
typedef struct {
real re;
real im;
} complex;
#define R(a0,a1,b0,b1,wre,wim) { \
t1 = a0 - a1; t2 = b0 - b1; \
t5 = t1 * wim; t6 = t2 * wim; \
t3 = a0; t1 *= wre; \
t3 += a1; t2 *= wre; \
t1 -= t6; t4 = b0; \
t2 += t5; t4 += b1; \
a0 = t3; b1 = t2; \
a1 = t4; b0 = t1; \
}
#define RZERO(a0,a1,b0,b1) { \
t1 = a0 - a1; t2 = b0 - b1; \
t3 = a0 + a1; t4 = b0 + b1; \
b0 = t1; a0 = t3; \
b1 = t2; a1 = t4; \
}
void rpass(real *a, const complex *w, unsigned int n)
{
real t1, t2, t3, t4, t5, t6, t7, t8;
real *b;
unsigned int k;
b = a + 4 * n;
k = n - 2;
RZERO(a[0],a[1],b[0],b[1]);
R(a[2],a[3],b[2],b[3],w[0].re,w[0].im);
R(a[4],a[5],b[4],b[5],w[1].re,w[1].im);
R(a[6],a[7],b[6],b[7],w[2].re,w[2].im);
for (;;) {
R(a[8],a[9],b[8],b[9],w[3].re,w[3].im);
R(a[10],a[11],b[10],b[11],w[4].re,w[4].im);
R(a[12],a[13],b[12],b[13],w[5].re,w[5].im);
R(a[14],a[15],b[14],b[15],w[6].re,w[6].im);
if (!(k -= 2)) break;
a += 8;
b += 8;
w += 4;
}
}
Run Code Online (Sandbox Code Playgroud)
(信用到期的信用:这个小基准来自Dan Bernstein的'djbfft'库)
也许您可以使用 s 的集合来执行操作,而不是您自己的类#define:
// For normal operations
#define specialplus +
#define specialmultiple *
// And a separate compilation with
#define specialplus min
#define specialmultiple +
Run Code Online (Sandbox Code Playgroud)
也许更好的是:
// normalmath.c
#define plus(a,b) (a)+(b)
#define star(a,b) (a)*(b)
#define FUNCTYPE normal
#include "yourcode.c"
// tropicalmath.c
#define plus(a,b) min((a),(b))
#define star(a,b) (a)+(b)
#define FUNCTYPE tropical
#include "yourcode.c"
// yourcode.c
int FUNCTYPE_opp(int x, int y)
{
// for example
return star(plus(x,y),52);
}
Run Code Online (Sandbox Code Playgroud)
(至少如果我没有弄乱我的 C 预处理器代码的话)。
或者至少是那种形式的东西?也许通过一些巧妙的函数命名来允许同时使用两种类型?