LINUX.ORG.RU
ФорумTalks

[ELF? FatELF?] Один бинарник на несколько похожих процессоров


0

0

Ряд программ умеют работать на простейшем из процессоров семейства, но использовать команды более новых процессоров, если появляется такая возможность. Пример: можно так собрать mplayer/mencoder, что он будет нормально работать на 386-ом, но если тот же файл запустить на Athlon 64 или Core, то задействуются возможности новых процессоров: MMX, SSE, SSE3 и т.д.

(Далее для простоты я рассматриваю программы в формате ELF, написанные на Си. Если не рассматривать бинарники в байткоде, принципиальных отличий не будет. А из наборов команд сверх минимального возьму только SSE.)

Насколько я понимаю, при запуске такой программы она проверяет возможности процессора и далее выбирает, какие версии функций вызывать: использующие SSE или не использующие. Правильно ли я понимаю, что не существует единого стандарта написания таких универсальных программ, и каждый разработчик изобретает что-то своё?

Нельзя ли поступить следующим образом?

  • Если функцию выгодно собрать с поддержкой SSE, пускай компилятор скомпилирует 2 её варианта: быстрый с SSE и медленный без.
  • Далее пускай в ELF слинкуются оба варианта.
  • Перед запуском получившегося ELFа ОС должна проверить тип процессора, определить оптимальный из 2 вариантов функции и подставить его для каждого вызова этой функции.

Я правильно понимаю, что стандартный ELF такого не позволяет?

Получится нечто вроде FatELF. Но насколько я понял, FatELF — просто несколько склеенных бинарников. И Гордон (icculus) предлагал его для использования на несовместимых процессорах, вроде x86 и PPC, а не для односторонне совместимых, как Pentium и Pentium 3. В этом случае будет не склейка целых бинарников, а, скажем, одного варианта main(), одного варианта read_file() и двух вариантов decomperss().

Имеет ли это смысл? Пытался ли кто-либо так сделать? Планируется ли сделать подобное в FatELF?

В некоторых дистрибутивах в разные директории ставится несколько версий библиотеки: /usr/lib/i386/, /usr/lib/i686/cmov/, /usr/lib/i686/sse2/cmov/... А система при каждом запуске программы сканирует все эти директории и использует библиотеку, лучше всего соответствующую текущей конфигурации. Может, имеет смысл сделать всего один файл с несколькими вариантами критичных функций?

Если кто-то скажет, что такая проблема отомрёт с 32-разрядными x86, отвечу, что она уже назревает для x86_64. Та же Убунту сейчас собирает пакеты под «generic x86_64», что соответствует первым 64-разрядным Атлонам и Пентиумам. Авторы программ, желающие полнее использовать возможности новых процессоров, выкручиваются, кто во что горазд. Именно недавнее сравнение сорцовых и бинарных дистрибутивов вызвало данный вопрос.

P.S. С летним вас временем.

★★★★★

Ответ на: комментарий от eugene2k

> глиб ... я тебя не понял ... проверка при каждом вызове функции

Я имел в виду проверку при каждом вызове функции. Как я понял, именно её shimon назвал «тупой».

FatELF лучше ... по варианту библиотеки на каждый набор команд

FatELF критикуют помимо прочего за большой объём. С десятками библиотек — аналогично. Но львиная доля производительности выигрывается или теряется на очень небольшом числе блоков программы. Как правило, сравнительно небольшого объёма. В этом и был смысл исходного предложения — дублировать только то, что даст заметный выигрыш в скорости.

question4 ★★★★★
() автор топика
Ответ на: комментарий от eugene2k

> что значит «очень уж тупо» и что значит «автор знал, что делает»?

Это когда автор знал, что его поделие будет запускаться на процессорах А, Б и Ц, и сам заготовил оптимизированные процедурки.

А тупо потому, что каждый раз проверять тип процессора — копипаст на ровном месте.

shimon ★★★★★
()
Ответ на: комментарий от question4

> Сейчас это сделано, но именно с опросом cpuid при каждом вызове.

Не понял. То есть, если я поставил себе libc-i686, то вместо того, чтобы предположить, что у меня таки i686, оно все равно будет спрашивать, а не запускаю ли я его часом на i486? Офигеть логика.

shimon ★★★★★
()
Ответ на: комментарий от shimon

> если я поставил себе libc-i686, то вместо того, чтобы предположить, что у меня таки i686, оно все равно будет спрашивать, а не запускаю ли я его часом на i486?

По крайней мере, я понял ассемблер выше именно так.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

> По крайней мере, я понял ассемблер выше именно так.

За такое хорошо бы убить.

Например, у меня Core 2 Quad и я точно знаю, что не буду перетаскивать глибц куда-то там на рухлядь. Еще я верю в способности компилятора. А Дреппер как бы говорит мне: лососни тунца со своим c2q, сына.

shimon ★★★★★
()
Ответ на: комментарий от question4

>Я имел в виду проверку при каждом вызове функции. Как я понял, именно её shimon назвал «тупой»
Ну, ты в своей программе волен сделать с указателями на функции :)

FatELF критикуют помимо прочего за большой объём

Эээ... а включение кода для (помимо прочего) MMX, SSE, 3D NOW, SSE2 не сделает бинарник большим что ли?

eugene2k
()

>SSE

<fat>SSE появилось в pentium3, так что собирать вариант без SSE сейчас бессмысленно</fat>

annulen ★★★★★
()

>Может, имеет смысл сделать всего один файл с несколькими вариантами критичных функций?

Есть такие библиотеки, как BLAS, LAPACK, которые выпускаются производителями процов (Intel, AMD) и позволяю выжать все из имеющихся инструкций для каждого проца

annulen ★★★★★
()
Ответ на: комментарий от shimon

Ты бы, перед тем как жаловаться, посмотрел бы сам исходники libc-i686 - оно как бы своим названием намекает на минимальные требования к процессору и ставить постфикс i686 к коду для i486 как минимум нелогично.

eugene2k
()
Ответ на: комментарий от annulen

<diet>
http://ru.wikipedia.org/wiki/Geode
</diet>

несмотря на то что на википедии написано что сабж SSE поддерживает, самих регистров там _нет_ и поддерживаются только те инструкции, которые не используют регистры SSE

Sylvia ★★★★★
()
Ответ на: комментарий от Sylvia

хм. никогда не видел эту звершку, но если кто-то пользуется, то пусть будет. да и от SSE1 проку не так уж много, там только float векторизоваться могут, а double нет

annulen ★★★★★
()
Ответ на: комментарий от annulen

я тоже, но недавно (месяц или два назад) кто-то на ЛОР интересовался по поводу нее.

с SSE да, там не особенно интересно, имеет смысл широко использовать SSE2 и выше

Sylvia ★★★★★
()
Ответ на: комментарий от Sylvia

У меня есть (pcengines.ch). Только я вот никак сервер не возьмусь себе собрать.

eugene2k
()
Ответ на: комментарий от annulen

> от SSE1 проку не так уж много,

Я его выбрал только как пример набора инструкций, который есть не везде. И до сих пор кое-где работают Пентиумы-1 и K6.

question4 ★★★★★
() автор топика
Ответ на: комментарий от eugene2k

> Ну, ты в своей программе волен сделать с указателями на функции :)

А автоматизировать это? :)

а включение кода для (помимо прочего) MMX, SSE, 3D NOW, SSE2 не сделает бинарник большим что ли?

Конечно, сделает. Но на размер дублируемых функций, а не на размер всего кода в файле.

question4 ★★★★★
() автор топика

question4 , а теперь давайте не будем ограничиваться только -march= и набором инструкций, но еще будем теперь учитывать, что есть такая штука как планировщик инструкций ( задается -mtune= )

486 - планировщика нет
586 - «in order execution», размер кеша L1 8Kb
686 - «out of order» , требуют выравнивания инструкций ( align ), для чего компилятор генерирует всякий мусор в виде NOP например

pentium4 aka netburst - про особенности архитектуры можно найти достаточно интересного, особенно важны моменты предсказания ветвлений.
P4 и выше не требуют выравнивания инструкций, но имеют самые различные размеры кешей L1 , L2 что имеет значения для оптимизации ( inline, loop unroll )

особняком стоит достаточно популярный сейчас Atom, имеет достаточно короткий L1 кеш и... «in order execution»

а теперь как это все реализовывать в 1 бинарник ?)

Sylvia ★★★★★
()
Ответ на: комментарий от Sylvia

можно я подскажу решение?

не нужно пытаться оптимизировать все и вся, для кода общего назначения прирост производительности в пределах 10-15% не будет столь ощутим как прирост размеров бинарников, для кода требующего высокую оптимизацию часто пишутся asm вставки, примеры - glibc, liboil, кодеки

Для тех же, кому нужно максимально подогнать код под процессор и существуют source-based дистрибутивы (а еще там можно ненужные зависимости повыкидывать)

Просто наверное не надо заниматься сильным усложнением того, что итак достаточно сложно, сейчас еще и OpenCL вставки будут, как со всем этим жить ?)

Sylvia ★★★★★
()
Ответ на: комментарий от Sylvia

> можно я подскажу решение?

не нужно пытаться оптимизировать все и вся, для кода общего назначения прирост производительности в пределах 10-15% не будет столь ощутим как прирост размеров бинарников,

В смысле? Не применять к коду общего назначения -mtune ? Об этом я и говорю с самого начала: оптимизировать до предела только отдельные блоки. И их иметь в нескольких вариантах.

Просто наверное не надо заниматься сильным усложнением того, что итак достаточно сложно,

Пока я просто пытаюсь понять, что есть, чего можно добиться, и чего стоит добиваться. Понять настолько, чтобы уметь довести мысль до других. А там видно будет.

сейчас еще и OpenCL вставки будут, как со всем этим жить ?)

С этим-то как раз просто. Как добавить ещё 1 семейство процессоров :)

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

>Не применять к коду общего назначения -mtune
а куда вы его денете? есть -mtune=generic что соответствует некоему наиболее популярному на рынке процессору, может это не совсем и плохой выбор по умолчанию, но Atom например в него не очень влезает....

Sylvia ★★★★★
()
Ответ на: комментарий от question4

>А автоматизировать это? :)
makefile

Конечно, сделает. Но на размер дублируемых функций, а не на размер всего кода в файле.

Хочешь гибридный подход - выдели весь нужный код в динамические библиотеки и подключай их в зависимости от поддерживаемых расширений. И ничего менять не надо. А вообще смысла в гибридном подходе лично я вижу немного: если ты хочешь, чтобы твоя программа выжимала из процессора все что можно, то оптимизировать лучше сразу все. Или ты думаешь, что от того, что дублируются только некоторые функции, разработчики с большей охотой примут это нововведение чем FatELF? Если так, то ты ошибаешься. FatELF не нужен не потому что он толстый, а потому что он дублирует функции пакетного менеджера. Это единственная область его применения.

eugene2k
()
Ответ на: комментарий от Sylvia

> а куда вы его денете? есть -mtune=generic

Его и имел в виду. Да, это проигрыш где-то. Ради универсальности.

question4 ★★★★★
() автор топика
Ответ на: комментарий от eugene2k

> makefile

Хочешь гибридный подход - выдели весь нужный код в динамические библиотеки и подключай их в зависимости от поддерживаемых расширений.

Так делают. А можно ли сделать так: одни файлы исходников компилятся всего один раз; другие — в нескольких вариантах, с заменой имён функций; из этого статически собирается программа, в котором функции выбираются в зависимости от поддерживаемых расширений?

Через мейкфайл гибридный подход сделать можно. Судя по всеобщему непониманию, никто не пытался это реализовать через какие-нибудь универсальные макросы. Чтобы кодер просто добавлял к прототипу функции нужный параметр, и функция компилировалась в несколько вариантов, а в инициализации программы добавлялся блок для выбора нужного варианта.

А вообще смысла в гибридном подходе лично я вижу немного: если ты хочешь, чтобы твоя программа выжимала из процессора все что можно, то оптимизировать лучше сразу все.

И оптимизированный вариант не попадёт ни в Дебиан, ни в Убунту, ни в любой другой дистрибутив, делающий все программы совместимыми с i386 или i586. А то, что попадёт, будет проигрывать гибридам.

Или ты думаешь, что от того, что дублируются только некоторые функции, разработчики с большей охотой примут это нововведение чем FatELF?

Нет. Если не требует менять формат ELF, это много лет применяется :)

FatELF не нужен не потому что он толстый, а потому что он дублирует функции пакетного менеджера.

Хороший вопрос. Пакетные менеджеры решают одни проблемы и порождают другие. Сошёлся ли на них свет клином? Или есть грань, за которой стоит от них отказаться? Где? :)

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

>А можно ли сделать так: одни файлы исходников компилятся всего один раз; другие — в нескольких вариантах, с заменой имён функций; из этого статически собирается программа, в котором функции выбираются в зависимости от поддерживаемых расширений?
Если среда сборки позволяет, то вроде ничего не мешает.

Или есть грань, за которой стоит от них отказаться? Где?

В винде //К.О.

eugene2k
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.