Как статически ссылаться на TBB?
Как я могу статически связать библиотеки Intel TBB с моим приложением? Я знаю все предупреждения, такие как несправедливое распределение нагрузки планировщика, но мне не нужен планировщик, только контейнеры, так что все в порядке.
В любом случае, я знаю, что это можно сделать, хотя это недокументировано, однако я просто не могу найти способ сделать это прямо сейчас (хотя я видел это где-то раньше).
Так кто-нибудь знает или имеет какие-либо подсказки?
Спасибо
7 ответов
Это настоятельно не рекомендуется:
Существует ли версия TBB, которая предоставляет статически связанные библиотеки?
TBB не предоставляется как статически связанная библиотека по следующим причинам *:
Большинство библиотек работают локально. Например, Intel(R) MKL FFT преобразует массив. Не имеет значения, сколько существует копий БПФ. Несколько копий и версий могут сосуществовать без труда. Но некоторые библиотеки управляют ресурсами всей программы, такими как память и процессоры. Например, сборщики мусора управляют распределением памяти между программами. Аналогично, TBB контролирует планирование задач в рамках программы. Чтобы эффективно выполнять свою работу, каждый из них должен быть одиночным; то есть иметь единственный экземпляр, который может координировать действия по всей программе. Если разрешить k экземпляров планировщика TBB в одной программе, программных потоков будет в k раз больше, чем аппаратных потоков. Программа будет работать неэффективно, потому что машина будет переподписана с коэффициентом k, что приведет к большему переключению контекста, кэш-памяти и потреблению памяти. Кроме того, эффективная поддержка TBB для вложенного параллелизма будет сведена на нет, если вложенный параллелизм возникнет из-за вложенных вызовов различных планировщиков.
Наиболее практичным решением для создания синглтона всей программы является динамическая разделяемая библиотека, которая содержит синглтон. Конечно, если бы планировщики могли сотрудничать, нам не нужен был бы синглтон. Но это сотрудничество требует централизованного агента для общения; то есть синглтон!
На наше решение об исключении статически связываемой версии TBB сильно повлиял наш опыт OpenMP. Как и TBB, OpenMP также пытается составить расписание для всей программы. Однажды была предоставлена статическая версия среды выполнения OpenMP, и она была постоянным источником проблем, возникающих из-за дублирующих планировщиков. Мы считаем, что лучше не повторять эту историю. В качестве косвенного доказательства обоснованности этих соображений можно указать на тот факт, что Microsoft Visual C++ обеспечивает поддержку OpenMP только через динамические библиотеки.
РЕДАКТИРОВАТЬ - Изменено для использования 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>
Запуск нескольких программ TBB на узел
Если вы запускаете многопроцессорное приложение, например, с использованием MPI, вам может понадобиться явно инициализировать планировщик TBB с соответствующим количеством потоков, чтобы избежать переподписки.
Пример этого в большом приложении может быть найден в https://github.com/m-a-d-n-e-s-s/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, возможно создать собственную статически связанную версию 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:
- Вызовите g++ с помощью
-static
переключатель - Ссылка против ТББ (
-ltbb
) и pthread (-lpthread
)
В моем тесте мне также нужно было явно сослаться на все .o
файлы из версии TBB, созданной вручную. В зависимости от вашего проекта, вам также может понадобиться пройти -pthread
в GCC.
Я создал игрушечный пример для документирования всех шагов в этом репозитории Github:
Он также содержит тестовый код, чтобы убедиться, что сгенерированный двоичный файл переносим в других дистрибутивах Linux.
К сожалению, это не представляется возможным: с сайта TBB.,
Одним из предложений на форуме Intel было скомпилировать его вручную, если вам действительно нужна статическая связь: с форума Intel.
Просто свяжите файлы, я просто сделал это и работает. Вот файл 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')