Fir*_*cer 5 c++ optimization gcc visual-studio-2012
在我的程序代码中有各种相当小的对象,范围从一个字节或2到16左右.例如Vector2(2*T),Vector3(3*T),Vector4(4*T),ColourI32(4),LightValue16(2) ),Tile(2)等(括号中的字节大小).
正在做一些分析(基于样本),这导致我比一些慢于预期的功能,例如
//4 bits per channel natural light and artificial RGB
class LightValue16
{
...
explicit LightValue16(uint16_t value);
LightValue16(const LightValueF &);
LightValue16(int r, int g, int b, int natural);
int natural()const;
void natural(int v);
int artificialRed()const;
...
uint16_t data;
};
...
LightValue16 World::getLight(const Vector3I &pos)
{ ... }
Run Code Online (Sandbox Code Playgroud)
这个函数做了一些数学运算,通过几个数组查找值,在世界的填充部分之上有一些默认值.内容很好地内联,看着反汇编看起来尽可能好.有大约100个指令.然而有一点是突出的,在所有返回网站上它实现了类似的东西:
mov eax, dword pyt [ebp + 8]
mov cx, word ptr[ecx + edx * 2] ; or say mov ecx, Fh
mov word ptr [eax], cx
pop ebp
ret 10h
Run Code Online (Sandbox Code Playgroud)
对于x64,我看到了几乎相同的东西.我没有检查我的GCC构建,但我怀疑它确实完全相同.
我做了一个小实验,并使用uint16_t返回类型找到.它实际上导致了World :: getLight函数内联(看起来几乎相同的核心80指令左右,没有条件/循环不同的作弊)和我正在调查的外部函数的总CPU使用率从16.87 %到14.04%虽然我可以根据具体情况来做这件事(同时尝试强制内联的东西),有什么实际的方法可以避免这样的性能问题开始吗?甚至可能在整个代码中加快几个百分点?
我刚才能想到的最好的就是在这种情况下使用原始类型(<4或者可能是8个字节的对象)并将所有当前成员的东西移动到非成员函数中,所以更像是在C中完成,只是使用名称空间.
考虑到这一点,我想在"t foo(浮动x,浮动y,浮动z)"之类的"t foo(const Vector3F&p)"之类的东西经常会有成本吗?如果是这样,在一个广泛使用const&的程序中,它是否会增加显着的差异?
在这个问题的评论中已经有很多讨论,是否允许编译器将您分析的函数class LightValue16作为简单函数处理。uint16_t
如果您的类不包含特殊的魔法(如虚函数) ,并且整个类对分析的函数可见,则编译器可以生成与仅使用 `uint16_t 类型 100% 同等有效的代码。
问题是“能”。尽管所有像样的编译器通常都会生成 100% 快的代码,但偶尔会出现一些优化不会被应用的情况,或者至少生成的代码会有所不同。可能只是启发式的参数发生变化(例如,不会应用内联,因为由于类的原因,某些优化步骤中只保留了一点点代码),或者某些优化过程在这个阶段确实需要一个普通的数字类型,这甚至不是编译器中真正的错误。例如,如果您将“template < bool NotUsed>”添加到上面的类中,这可能会更改编译器内的优化步骤,尽管从语义上讲您的程序不会改变。
因此,如果您想 100% 确定,请直接仅使用 int 或 double。但在 90% 的情况下,它会达到 100% 的速度,只有在 10% 的情况下,它才会达到 90% 的性能,这对于 99%(但不是 100%)的所有用例来说应该没问题。