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