当前位置: 首页 > 面试题库 >

如何在Linux上基于CPU功能进行运行时绑定

况景龙
2023-03-14
问题内容

是否可以让linux库(例如“ libloader.so”)加载另一个库来解析任何外部符号?

我有一堆代码,这些代码有条件地被编译以支持SIMD级别(SSE2,AVX,AVX2)。如果构建平台与运行时平台相同,则此方法运行良好。但这阻碍了不同处理器代之间的重用。

一种想法是让executable哪个调用function链接libloader.so不直接实现function。而是根据cpuflags
从另一个已加载的库(例如libimpl_sse2.solibimpl_avx2.so等等)中解析(绑定?)该符号。

需要以这种方式动态绑定数百个函数,因此更改声明或调用代码不切实际。程序链接相当容易更改。运行时环境变量也可以更改,但我不希望更改。

我已经通过ld标志制作了一个以未解决的外部符号(UES)开头并生成的可执行文件 --unresolved-symbols=ignore- all。但是,随后加载impl lib不会使UES函数的值从NULL更改。


问题答案:

编辑:
我后来发现,下面描述的技术仅在有限的情况下有效。具体来说,您的共享库必须仅包含函数,而没有任何全局变量。如果要分派到的库中有全局变量,则最终将出现运行时动态链接器错误。这是因为全局变量在调用共享库构造函数之前已重定位。因此,链接器需要尽早解析这些引用,然后才能运行这里描述的调度方案。

完成所需操作的一种方法是(ab)使用DT_SONAME共享库的ELF标头中的字段。这可用于更改动态加载程序(ld-linux- so*)在运行时加载的文件的名称,以解决共享库的依赖性。最好用一个例子来解释。说我libtest.so用以下命令行编译共享库:

g++ test.cc -shared -o libtest.so -Wl,-soname,libtest_dispatch.so

这将创建一个共享库,其名称为libtest.so,但其DT_SONAME字段设置为libtest_dispatch.so。让我们看看将程序链接到该程序时会发生什么:

g++ testprog.cc -o test -ltest

让我们检查生成的应用程序二进制文件的运行时库依赖项test

> ldd test
linux-vdso.so.1 =>  (0x00007fffcc5fe000)
libtest_dispatch.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd1e4a55000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd1e4e4f000)

请注意,libtest.so动态加载程序不是要查找而是要加载libtest_dispatch.so。您可以利用它来实现所需的调度功能。这是我的处理方式:

  • 创建共享库的各种版本。我假设有一些“通用”版本可以始终使用,并在运行时适当地使用其他优化版本。我会说出通用版“普通的”库名libtest.so,并命名无论您选择的其他人(例如libtest_sse2.solibtest_avx.so等)。

  • 链接库的通用版本时,请将其覆盖DT_SONAME到其他名称,例如libtest_dispatch.so

  • 创建一个名为的调度程序库libtest_dispatch.so。在应用程序启动时加载调度程序时,它负责加载库的适当实现。以下是伪代码,其实现libtest_dispatch.so可能如下所示:

    #include <dlfcn.h>
    

    // the attribute ensures that this function is called when the library is loaded
    attribute((constructor)) void init()
    {
    // manually load the appropriate shared library based upon what the CPU supports
    // at runtime
    if (avx_is_available) dlopen(“libtest_avx.so”, RTLD_NOW | RTLD_GLOBAL);
    else if (sse2_is_available) dlopen(“libtest_sse2.so”, RTLD_NOW | RTLD_GLOBAL);
    else dlopen(“libtest.so”, RTLD_NOW | RTLD_GLOBAL);
    // NOTE: this is just an example; you should check the return values from
    // dlopen() above and handle errors accordingly
    }

  • 将应用程序与您的库链接时,请将其与“ vanilla”链接libtest.so,该文件已DT_SONAME被覆盖以指向调度程序库。这使得分派对于使用您的库的所有应用程序作者基本上都是透明的。

这应该如上所述在Linux上工作。在Mac OS上,共享库的“安装名称”类似于DT_SONAMEELF共享库中使用的“安装名称”
,因此可以改用与上述过程非常相似的过程。我不确定Windows是否可以使用类似的东西。

注意:上面
有一个重要的假设:库的各种实现之间的ABI兼容性。也就是说,您的库的设计应使其在链接时可以安全地链接到最通用的版本,而libtest_avx.so在运行时使用优化的版本(例如)。



 类似资料:
  • 我已经在Ubuntu 14.04上安装了tensorflow的GPU版本。 我在一个GPU服务器上,在那里Tenorflow可以访问可用的GPU。 我想在CPU上运行tenorflow。 通常我可以使用env CUDA\u VISIBLE\u DEVICES=0在0号GPU上运行。 如何在CPU之间进行选择? 我对用tf重写代码不感兴趣。设备(“/cpu:0”):

  • 问题内容: 我有一个Flask虚拟主机,无法访问命令。 我如何每小时执行一些Python函数? 问题答案: 您可以从APScheduler软件包(v3.5.3)中使用: 请注意,当Flask处于调试模式时,将启动其中两个调度程序。有关更多信息,请查看此问题。

  • 问题内容: 对于具有Java背景的开发人员,我也有兴趣探索使用ASP.NET工具/平台进行软件开发。 Java Web应用程序(.jsp和servlet)可以在许多服务器平台上运行。 问题 :.NET Web应用程序能否在基于Linux的服务器上运行?考虑到无法使用Windows服务器托管Web应用程序的情况。 问题答案: 这取决于您使用的是哪种特定的.NET技术。该Mono项目提供运行ASP.N

  • 问题内容: 我正在尝试在运行mako内核的Nexus 4的所有cpus上设置性能监视器用户模式启用寄存器。 现在,我在可加载模块中设置寄存器: 问题是on_each_cpu仅在Online cpus上运行该功能,如printk语句所示: 当我调用on_each_cpu时,只有四个在线。所以我的问题是,如何强制cpu联机,或者如何强制某个cpu执行代码?谢谢 问题答案: 你并不需要运行在每个CPU的

  • 问题内容: 我有一个Flask虚拟主机,无法访问命令。我如何每小时执行一些Python函数? 问题答案: 你可以从APScheduler软件包(v3.5.3)中使用: 请注意,当Flask处于调试模式时,将启动其中两个调度程序。

  • 问题内容: 我正在开发php / javascript聊天。 用户登录时,其用户名将插入名为的MySQL表中。此插入返回将存储在称为 当用户关闭页面时,我需要删除MySQL表行。 我尝试了以下方法,但没有成功: js文件 chat.php 有什么办法吗? 问题答案: 您触发ajax异步(jQuery的默认设置-ajax)。但是浏览器不会等待任何卸载。 尝试在ajax 设置中进行设置。但是,您永远无