人工智能在C++;:虚拟功能的成本有多高?可能的优化是什么? 在AI应用程序中,我用C++编写, 没有太多的数值计算 有许多结构需要运行时多态性 在计算过程中,许多多态结构经常相互作用
在这种情况下,是否有任何优化技术?虽然我不想现在优化应用程序,但是在项目中选择C++来代替java是为了使更多的杠杆优化和能够使用非面向对象的方法(模板、过程、重载)。p> 特别是,与虚拟函数相关的优化技术有哪些?虚拟函数是通过内存中的虚拟表实现的。是否有某种方法可以将这些虚拟表预取到二级缓存上(从内存/二级缓存获取的成本正在增加)人工智能在C++;:虚拟功能的成本有多高?可能的优化是什么? 在AI应用程序中,我用C++编写, 没有太多的数值计算 有许多结构需要运行时多态性 在计算过程中,许多多态结构经常相互作用,c++,optimization,C++,Optimization,在这种情况下,是否有任何优化技术?虽然我不想现在优化应用程序,但是在项目中选择C++来代替java是为了使更多的杠杆优化和能够使用非面向对象的方法(模板、过程、重载)。p> 特别是,与虚拟函数相关的优化技术有哪些?虚拟函数是通过内存中的虚拟表实现的。是否有某种方法可以将这些虚拟表预取到二级缓存上(从内存/二级缓存获取的成本正在增加) 除此之外,C++中是否存在对数据局部性技术的良好参考?这些技术将减少将数据提取到二级缓存中进行计算所需的等待时间 更新:也可以查看以下相关论坛:,您很少需要担心这些
除此之外,C++中是否存在对数据局部性技术的良好参考?这些技术将减少将数据提取到二级缓存中进行计算所需的等待时间
更新:也可以查看以下相关论坛:,您很少需要担心这些常用项目的缓存,因为它们只提取一次并保存在那里 缓存通常仅在处理以下大型数据结构时才会出现问题:
1) 顺便说一句,这就是为什么像memcpy这样的函数使用缓存绕过movnt(dq | q)这样的流式指令来进行超大(数兆字节)的数据输入。如果一个AI应用程序不需要大量的数字运算,我就不会担心虚拟函数的性能劣势。只有当它们出现在重复评估的复杂计算中时,性能才会受到轻微的影响。我认为您也不能强制虚拟表留在二级缓存中 虚拟函数有两种优化方法
您是否实际分析并找到了需要优化的位置和内容
当您发现虚拟函数调用实际上是瓶颈时,请实际优化它们。虚拟函数非常有效。假设32位指针,内存布局约为:
classptr -> [vtable:4][classdata:x]
vtable -> [first:4][second:4][third:4][fourth:4][...]
first -> [code:x]
second -> [code:x]
...
classptr指向通常在堆上的内存,偶尔在堆栈上,并以指向该类vtable的四字节指针开始。但是需要记住的重要一点是vtable本身并没有分配内存。它是一个静态资源,同一类类型的所有对象都将指向其vtable数组的完全相同的内存位置。调用不同的实例不会将不同的内存位置拉入二级缓存
这显示了具有虚拟func1、func2和func3的类A的vtable。不超过12个字节。不同类的vtables很有可能在编译库中物理上相邻(您需要验证这一点,这是您特别关心的),这可以从微观上提高缓存效率
CONST SEGMENT
??_7A@@6B@
DD FLAT:?func1@A@@UAEXXZ
DD FLAT:?func2@A@@UAEXXZ
DD FLAT:?func3@A@@UAEXXZ
CONST ENDS
另一个性能问题是通过vtable函数调用的指令开销。这也是非常有效的。与调用非虚函数几乎相同。再次从以下方面:
在本例中,堆栈帧基指针ebp的变量A*pa
偏移量为零。寄存器eax在位置[ebp]处加载值,因此它具有A*,而edx在位置[eax]处加载值,因此它具有A类vtable。然后用[ebp]加载ecx,因为ecx代表“this”,它现在保存A*,最后调用位置[edx+8]处的值,该位置是vtable中的第三个函数地址
如果此函数调用不是虚拟的,则不需要mov eax和mov edx,但性能差异将非常小。您可以在运行时使用虚拟函数实现polymorfism,在编译时使用模板实现polymorfism。可以用模板替换虚拟函数。查看本文以了解更多信息-动态多态性的解决方案可以是静态多形性,如果您的类型在编译类型(CRTP(奇怪的循环模板模式)中已知,则可以使用它
Wikipedia上的解释非常清楚,如果您真的确定虚拟方法调用是性能瓶颈的来源,那么它可能会帮助您。虚拟调用不会比普通函数带来更大的开销。尽管如此,最大的损失是以多态方式调用虚函数时无法内联。在很多情况下,内联将代表性能上的一些实际收益 你可以做些什么来防止浪费
; A* pa;
; pa->func3();
mov eax, DWORD PTR _pa$[ebp]
mov edx, DWORD PTR [eax]
mov ecx, DWORD PTR _pa$[ebp]
call DWORD PTR [edx+8]
Class A {
inline virtual int foo() {...}
};
class B : public A {
inline virtual int foo()
{
//...do something different
}
void bar()
{
//logic...
B::foo();
// more logic
}
};