如何将英特尔的 TBB 库静态链接到我的应用程序?我知道调度程序的负载分配不公平等所有注意事项,但我不需要调度程序,只需要容器,所以没关系。
无论如何,我知道这是可以做到的,尽管它没有记录,但是我现在似乎找不到这样做的方法(尽管我以前在某个地方见过它)。
那么有人知道或有任何线索吗?
谢谢
如何将英特尔的 TBB 库静态链接到我的应用程序?我知道调度程序的负载分配不公平等所有注意事项,但我不需要调度程序,只需要容器,所以没关系。
无论如何,我知道这是可以做到的,尽管它没有记录,但是我现在似乎找不到这样做的方法(尽管我以前在某个地方见过它)。
那么有人知道或有任何线索吗?
谢谢
强烈不建议这样做:
是否有提供静态链接库的 TBB 版本?
TBB 不作为静态链接库提供,原因如下*:
大多数图书馆在本地运营。例如,英特尔(R) MKL FFT 转换数组。FFT 有多少个副本无关紧要。多个副本和版本可以毫无困难地共存。但是一些库控制程序范围的资源,例如内存和处理器。例如,垃圾收集器控制整个程序的内存分配。类似地,TBB 控制跨程序的任务调度。为了有效地完成工作,这些中的每一个都必须是单例;也就是说,有一个可以协调整个程序的活动的唯一实例。在单个程序中允许 k 个 TBB 调度程序实例将导致软件线程的数量是硬件线程的 k 倍。该程序将低效运行,因为机器将被超额订阅 k 倍,导致更多的上下文切换,缓存争用和内存消耗。此外,当嵌套并行性源自不同调度程序的嵌套调用时,TBB 对嵌套并行性的有效支持将被否定。
创建程序范围的单例最实用的解决方案是包含单例的动态共享库。当然,如果调度程序可以合作,我们就不需要单例了。但是这种合作需要一个集中的代理来进行通信;也就是单例!
我们决定省略 TBB 的静态链接版本的决定很大程度上受到了我们的 OpenMP 经验的影响。与 TBB 一样,OpenMP 也尝试跨程序进行调度。曾经提供过静态版本的 OpenMP 运行时,它一直是重复调度程序引起的问题的源头。我们认为最好不要重蹈覆辙。作为这些考虑的有效性的间接证明,我们可以指出 Microsoft Visual C++ 仅通过动态库提供 OpenMP 支持这一事实。
来源:http ://www.threadingbuildingblocks.org/faq/11#stash.t3BrizFQ.dpuf
编辑- 更改为使用extra_inc
. 谢谢杰夫!
使用以下参数构建:
make extra_inc=big_iron.inc
将构建静态库。请参阅 中的注意事项build/big_iron.inc
。
从https://www.threadingbuildingblocks.org/获取源代码后,像这样构建 TBB:
make extra_inc=big_iron.inc
如果您需要额外的选项,则改为这样构建:
make extra_inc=big_iron.inc <extra options>
如果您运行多处理应用程序,例如使用 MPI,您可能需要使用适当数量的线程显式初始化 TBB 调度程序以避免超额订阅。
可以在https://github.com/madness/madness/blob/master/src/madness/world/thread.cc中找到大型应用程序中的一个示例。
此功能已可用多年(至少从 2013 年开始),尽管由于其他答案中描述的原因未记录在案。
最初开发此功能是因为 IBM Blue Gene 和 Cray 超级计算机不支持共享库,或者由于缺乏本地安装的文件系统而在使用它们时性能不佳。
使用开源版本:
运行“make tbb”后,进入 build/linux_xxxxxxxx_release 文件夹。
然后运行:
ar -r libtbb.a concurrent_hash_map.o concurrent_queue.o concurrent_vector.o
dynamic_link.o itt_notify.o cache_aligned_allocator.o pipeline.o queuing_mutex.o
queuing_rw_mutex.o reader_writer_lock.o spin_rw_mutex.o spin_mutex.o critical_section.o
task.o tbb_misc.o tbb_misc_ex.o mutex.o recursive_mutex.o condition_variable.o
tbb_thread.o concurrent_monitor.o semaphore.o private_server.o rml_tbb.o
task_group_context.o governor.o market.o arena.o scheduler.o observer_proxy.o
tbb_statistics.o tbb_main.o concurrent_vector_v2.o concurrent_queue_v2.o
spin_rw_mutex_v2.o task_v2.o
你应该得到 libtbb.a 作为输出。
请注意,您的程序应同时使用“-ldl”和 libtbb.a 构建
虽然没有得到 TBB 团队的正式认可,但可以使用make extra_inc=big_iron.inc
.
我没有在 Windows 或 MacOS 上测试过它,但在 Linux 上,它可以工作(来源):
wget https://github.com/01org/tbb/archive/2017_U6.tar.gz
tar xzfv 2017_U6.tar.gz
cd tbb-2017_U6
make extra_inc=big_iron.inc
生成的文件在tbb-2017_U6/build/linux*release
.
当您将应用程序链接到静态 TBB 版本时:
-static
使用开关调用 g++-ltbb
) 和 pthread ( -lpthread
)在我的测试中,我还需要明确引用.o
手动构建的 TBB 版本中的所有文件。根据您的项目,您可能还需要传递-pthread
给 gcc。
我创建了一个玩具示例来记录此 Github 存储库中的所有步骤:
它还包含测试代码,以确保生成的二进制文件可在其他 Linux 发行版上移植。
不幸的是,这似乎不可能:来自 TBB 网站。.
英特尔论坛上的一项建议是,如果您确实需要静态链接,请手动编译:来自英特尔论坛。
只需链接文件,我只是做了它并且工作。这是 SConscript 文件。有两件小事,一个在 tbb 和 tbbmalloc 中具有相同名称的符号,我必须防止它被多次定义,并且我阻止了 ITT_NOTIFY 的使用,因为它在两个库中创建了另一个具有相同名称的符号。
Import('g_CONFIGURATION')
import os
import SCutils
import utils
tbb_basedir = os.path.join(
g_CONFIGURATION['basedir'],
'3rd-party/tbb40_233oss/')
#print 'TBB base:', tbb_basedir
#print 'CWD: ', os.getcwd()
ccflags = []
cxxflags = [
'-m64',
'-march=native',
'-I{0}'.format(tbb_basedir),
'-I{0}'.format(os.path.join(tbb_basedir, 'src')),
#'-I{0}'.format(os.path.join(tbb_basedir, 'src/tbb')),
'-I{0}'.format(os.path.join(tbb_basedir, 'src/rml/include')),
'-I{0}'.format(os.path.join(tbb_basedir, 'include')),
]
cppdefines = [
# 'DO_ITT_NOTIFY',
'USE_PTHREAD',
'__TBB_BUILD=1',
]
linkflags = []
if g_CONFIGURATION['build'] == 'debug':
ccflags.extend([
'-O0',
'-g',
'-ggdb2',
])
cppdefines.extend([
'TBB_USE_DEBUG',
])
else:
ccflags.extend([
'-O2',
])
tbbenv = Environment(
platform = 'posix',
CCFLAGS=ccflags,
CXXFLAGS=cxxflags,
CPPDEFINES=cppdefines,
LINKFLAGS=linkflags
)
############################################################################
# Build verbosity
if not SCutils.has_option('verbose'):
SCutils.setup_quiet_build(tbbenv, True if SCutils.has_option('colorblind') else False)
############################################################################
tbbmallocenv = tbbenv.Clone()
tbbmallocenv.Append(CCFLAGS=[
'-fno-rtti',
'-fno-exceptions',
'-fno-schedule-insns2',
])
#tbbenv.Command('version_string.tmp', None, '')
# Write version_string.tmp
with open(os.path.join(os.getcwd(), 'version_string.tmp'), 'wb') as fd:
(out, err, ret) = utils.xcall([
'/bin/bash',
os.path.join(g_CONFIGURATION['basedir'], '3rd-party/tbb40_233oss/build/version_info_linux.sh')
])
if ret:
raise SCons.Errors.StopError('version_info_linux.sh execution failed')
fd.write(out);
#print 'put version_string in', os.path.join(os.getcwd(), 'version_string.tmp')
#print out
fd.close()
result = []
def setup_tbb():
print 'CWD: ', os.getcwd()
tbb_sources = SCutils.find_files(os.path.join(tbb_basedir,'src/tbb'), r'^.*\.cpp$')
tbb_sources.extend([
'src/tbbmalloc/frontend.cpp',
'src/tbbmalloc/backref.cpp',
'src/tbbmalloc/tbbmalloc.cpp',
'src/tbbmalloc/large_objects.cpp',
'src/tbbmalloc/backend.cpp',
'src/rml/client/rml_tbb.cpp',
])
print tbb_sources
result.append(tbbenv.StaticLibrary(target='libtbb', source=tbb_sources))
setup_tbb()
Return('result')