简短版本:我想知道是否有可能,以及如何最好地利用DLL中的CPU特定指令?
稍微长一点的版本:当从微软下载(32位)的DLL时,似乎一个尺寸适合所有的处理器。
这是否意味着它们是为最低公用分母(即操作系统支持的最低平台)而严格构build的? 还是有一些技术用于在DLL中导出单个接口,但在后台利用特定于CPU的代码来获得最佳性能? 如果是这样,它是怎么做的?
我不知道任何标准的技术,但如果我不得不做这样的事情,我会在DllMain()函数中编写一些代码来检测CPU类型,并用函数指针填充一个跳转表,以获得每个CPU优化版本功能。
当CPU类型未知时,还需要有一个最小公分母函数。
你可以在注册表中找到当前的CPU信息:
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor
预计DLL可以在WIN32上运行的每台计算机上工作,所以你一般都坚持使用i386指令集。 没有为特定指令集公开功能/代码的官方方法。 你必须手工和透明地做到这一点。
所使用的技术基本如下: – 在运行时确定像MMX,SSE这样的CPU功能 – 如果它们存在,使用它们,如果没有,则准备好备用代码
由于不能让编译器针对i386以外的任何其他设备进行优化,因此必须使用内联汇编器中的特定指令集编写代码。 我不知道是否有更高级的语言工具包。 确定CPU功能是直接的,但也可能需要在汇编程序中完成。
获得SSE / SSE2优化的简单方法是仅使用MSVC的/arch
参数。 我不会担心回退 – 除非你有一个很好的应用程序,否则没有理由支持下面的任何东西。
http://msdn.microsoft.com/en-us/library/7t5yh4fd.aspx
我相信gcc / g ++有等效的标志。
英特尔的ICC可以针对不同的体系结构编译两次代码。 这样,你可以吃你的蛋糕,吃它。 (好吧,你得到两个蛋糕 – 你的DLL会更大)。 甚至MSVC2005可以做非常具体的情况(例如memcpy()可以使用SSE4)
有很多方法可以在不同的版本之间切换。 一个DLL被加载,因为加载过程需要它的功能。 函数名称被转换成地址。 一个解决方案是让这个查找不仅取决于函数名称,还取决于处理器功能。 另一种方法使用名称寻址函数在临时步骤中使用指针表的事实; 你可以切换出整个表格。 或者你甚至可以在关键职能部门有一个分支。 所以foo()在更快的时候调用foo__sse4。
从Microsoft下载的DLL是针对通用x86体系结构的,原因很简单,它必须在所有机器上运行。
直到Visual Studio 6.0时间框架(我不知道它是否已经改变),微软用来优化其DLL的大小,而不是速度。 这是因为DLL的整体大小的减少比编译器可以产生的任何其他优化提供了更高的性能提升。 这是因为相比于没有CPU等待内存的速度提升,来自微处理优化的加速将明显降低。 速度的真正提高来自减少I / O或改进基本算法。
只有少数运行在程序核心的关键循环可以从微观优化中受益,仅仅是因为它们被调用的次数很多。 只有大约5-10%的代码可能属于这个类别。 您可以放心,这样的关键循环已经被Microsoft软件工程师在汇编程序中优化到了一定程度,而且不会让编译器找到太多后面的东西。 (我知道它期望太多,但我希望他们这样做)
正如你所看到的,增加的DLL代码只会有一些缺陷,包括代码的不同版本,这些代码是针对不同的架构进行调整的,当这些代码的大部分很少被使用/从来不是占用大部分CPU周期的关键代码的一部分。