Я работаю над библиотекой C, которая компилирует / ссылается на файл .a
, который пользователи могут статически связывать в своем коде.Производительность библиотеки очень важна, поэтому я пишу критические для производительности подпрограммы в сборке x86-64 для оптимизации производительности.
Для некоторых подпрограмм я могу получить значительно лучшую производительность, если использую инструкции BMI2, чем если я буду придерживаться«стандартный» набор команд x86-64.Проблема в том, что BMI2 появился совсем недавно, и некоторые из моих пользователей используют процессоры, которые не поддерживают эти инструкции.
Итак, я написал оптимизированные подпрограммы дважды , один раз с использованием инструкций BMI2 иодин раз, не используя их.В моей текущей установке я бы распространял две версии файла .a
: «быстрая», которая требует поддержки инструкций BMI2, и «медленная», которая не требует поддержки инструкций BMI2.
Я спрашиваю, есть ли способ упростить это, распространяя один файл .a
, который будет динамически выбирать правильную реализацию в зависимости от того, поддерживает ли процессор , на котором выполняется конечное приложение, , инструкции BMI2.
В отличие от похожих вопросов по StackOverflow, здесь есть две особенности:
- Техника для выбора функции должна иметь особенно низкие издержки на критическом пути.Рассматриваемые подпрограммы после оптимизации сборки выполняются за ~ 10 нс, поэтому даже один оператор
if
может быть значительным. - Функция, которую необходимо выбрать «динамически», выбирается один раз в начале, а затем остается фиксированным на протяжении всей программы.Я надеюсь, что это предложит более быстрое решение, чем предложенное в этом вопросе: Выбор реализации метода во время выполнения
Самое быстрое решение, которое я придумал до сих порсделать следующее:
- Проверить, поддерживает ли процессор инструкции BMI2, с помощью инструкции
cpuid
. - Установить глобальную переменную
true
или false
в зависимости от результата. - Ответвление значения этой глобальной переменной при каждом вызове функции.
Я не удовлетворен этим подходом, поскольку у него есть два недостатка:
- Я не уверен, как можно автоматически запустить
cpuid
и установить глобальную переменную в начале программы, учитывая, что я распространяю файл .a
и не имею контролянад функцией main
в конечном двоичном файле. Я рад использовать C ++ здесь, если он предлагает лучшее решение, если окончательная библиотека все еще может быть связана с программой C и вызываться из нее. - Это приводит к дополнительным расходам каждый вызов функции, когда в идеале единственные издержки были бы при запуске программы.
Существуют ли какие-либо решения, которые более эффективны, чем те, которые я описал выше?