针对不同的目标体系结构进行编译和优化

Pet*_*mit 16 c++ optimization gcc compilation

简介:我想利用编译器优化和处理器指令集,但仍然有一个可移植的应用程序(在不同的处理器上运行).通常我可以编译5次,让用户选择正确的运行.

我的问题是:我怎样才能自动执行此操作,以便在运行时检测处理器并执行正确的可执行文件而无需用户选择它?


我的应用程序有很多低级数学计算.这些计算通常会持续很长时间.

我想利用尽可能多的优化,最好也是(并不总是支持)指令集.另一方面,我希望我的应用程序可移植且易于使用(因此我不想编译5个不同的版本并让用户选择).

是否有可能编译我的代码的5个不同版本并动态运行在执行时可能的最优化版本?有5个不同的版本,我的意思是不同的指令集和不同的处理器优化.

我不关心应用程序的大小.

此刻我在Linux上使用gcc(我的代码是用C++编写的),但我对英特尔编译器和MinGW编译器的编译也感兴趣.

可执行文件不一定能够在不同的操作系统上运行,但理想情况下也可以自动选择32位和64位.

编辑:请明确指示如何操作,最好使用小代码示例或解释链接.从我的角度来看,我需要一个超级通用的解决方案,它适用于我后来的任何随机C++项目.

编辑我将奖金分配给了ShuggyCoUk,他有很多指针需要注意.我本来希望在多个答案之间拆分,但这是不可能的.我还没有实现,所以问题仍然是"开放"!请继续添加和/或改进答案,即使不再给予奖励.

谢谢大家!

小智 16

是的,这是可能的.将所有不同优化版本编译为具有公共入口点的不同动态库,并提供可执行存根,该存根在运行时通过入口点加载和运行正确的库,具体取决于配置文件或其他信息.


Byr*_*ock 6

你能用脚本吗?

您可以使用脚本检测CPU,并动态加载最适合体系结构的可执行文件.它也可以选择32/64位版本.

如果您使用的是Linux,则可以查询cpu

cat /proc/cpuinfo
Run Code Online (Sandbox Code Playgroud)

您可以使用bash/perl/python脚本或Windows上的Windows脚本主机来执行此操作.您可能不希望强制用户安装脚本引擎.一个在开箱即用的操作系统上工作的恕我直言,将是最好的.

事实上,在Windows上你可能想要编写一个小型的C#应用​​程序,这样你就可以更轻松地查询架构.C#app可以生成最快的任何可执行文件.

或者,您可以将不同版本的代码放在dll或共享对象中,然后根据检测到的体系结构动态加载它们.只要它们具有相同的呼叫签名,它就应该起作用.

  • 考虑到他已经(非常刻意地)编写了依赖于OS的代码,我认为没有必要确保OS检测是可移植的.虽然让应用程序的那部分可移植可能会让事情变得更容易. (2认同)

cam*_*amh 5

看一下liboil:http://liboil.freedesktop.org/wiki/ .它可以在运行时动态选择多媒体相关计算的实现.您可能会发现自己可以自行搜索,而不仅仅是它的技术.


Shu*_*oUk 5

如果您希望在Windows上干净地工作并充分利用附加的64位平台1.寻址空间和2.寄存器(可能对您更有用),您必须至少为64位处理器提供单独的进程.

您可以通过使用相关PE64标头的单独可执行文件来实现此目的.简单地使用CreateProcess将启动它作为相关的位数(除非启动的可执行文件位于某个重定向位置,否则无需担心WoW64文件夹重定向

鉴于Windows上的这种限制,很可能简单地"链接"到相关的可执行文件将是所有不同选项的最简单选项,并且使测试更简单.

它还意味着你的'main'可执行文件可以完全独立,具体取决于目标操作系统(因为检测cpu/OS功能本质上是非常特定于操作系统)然后将大部分代码作为共享对象/ DLL文件.如果您当前不认为使用不同功能有任何意义,您也可以"共享"两个不同体系结构的相同文件.

我建议主要的可执行文件能够被强制做出一个特定的选择,这样你就可以看到在更强大的机器上"较小"版本会发生什么(或者如果你尝试不同的东西会出现什么错误).

给出这个模型的其他可能性是:

  • 静态链接到标准运行时的不同版本(对于具有/不具有线程安全性的运行时),如果您在没有任何SMP/SMT功能的情况下运行,则适当地使用它们.
  • 检测是否存在多个核心以及它们是真实线程还是超线程(在这些情况下操作系统是否有效地了解计划)
  • 检查诸如系统计时器/高性能计时器之类的性能并使用针对此行为优化的代码,例如,如果您执行任何需要等待一段时间才能到期的事情,从而可以了解最佳可能的粒度.
  • 如果您希望根据缓存大小/框上的其他负载优化您的代码选择.如果您正在使用展开的循环,那么更积极的展开选项可能取决于具有一定数量的1/2级缓存.
  • 根据体系结构有条件地编译以使用双精度/浮点数.在intel硬件上不那么重要但是如果你的目标是某些ARM cpu,有些则具有实际的浮点硬件支持,而其他则需要仿真.即使只使用条件编译而不是使用优化编译器(1),最佳代码也会发生很大变化.
  • 利用具有CUDA功能的图形卡等协处理器硬件.
  • 检测虚拟化并改变行为(可能试图避免文件系统写入)

至于这个检查你有几个选项,最有用的一个是英特尔是cpuid指令.

或者,使用有关所需功能的可用文档重新实现/更新现有文档.

有很多单独的文档可以解决如何检测事物:

您在CPU-Z库中支付的大部分内容是有人为您完成所有这些(以及涉及的令人讨厌的小问题).


  1. 小心这一点 - 很难在这方面击败优秀的优化编译器