Почему я не должен перехватывать исключение Undefined Instruction вместо использования CPUID? - PullRequest
2 голосов
/ 26 апреля 2020

Предположим, я хочу использовать инструкцию, которая может быть недоступна. И эта инструкция не относится к тем прозрачным запасным вариантам, это неопределенная инструкция, когда она недоступна. Скажем, это popcnt, например.

Могу ли я вместо cpuid просто попробовать и позвонить?

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

Конечно, будет снижение производительности, но только один раз. Есть ли дополнительные недостатки у этого подхода?

1 Ответ

1 голос
/ 26 апреля 2020

Одной из основных трудностей является правильное выполнение первого вызова.

После того, как вы решите это, выяснив, какая инструкция не выполнена, и эмулировав ее, и изменив сохраненное состояние задачи, проблема становится производительностью всего oop содержащий popcnt, который выполняет 1 миллион итераций после оптимистической отправки в popcnt версию этого l oop.

Если весь ваш код был написан в asm (или компиляторы могли бы сделать этот код для вас) , возможно правдоподобно , но обработчику сигнала трудно собрать все необходимое состояние и возобновить выполнение в другой версии таких al oop.

(обработчики сигналов GNU / Linux получают нестандартный с сохраненным состоянием регистра потока, в котором они работают, так что теоретически вы можете сделать это там.)

Предположительно, это относится только к преждевременной компиляции; если вы используете JIT, вы должны просто проверять CPUID заранее, а не создавать пути обработки исключений.


Возможность эффективной диспетчеризации означает, что ваш код, вероятно, уже написан с помощью указателей на функции для функций с несколькими версиями .

Таким образом, единственное сохранение здесь - это одна простая функция инициализации, которую ваша программа запускает один раз, которая запускает CPUID пару раз и устанавливает все указатели функций. Выполнение этого позже, по мере необходимости, означает больше пропусков кэша, если большая часть указателей на функции go не используется. например, large-program --help.

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


Вам также необходимо знать, какая инструкция не выполнена, если ваша программа имеет несколько функций ЦП, которые она использует.

Если вы Вы эмулируете или что-то в этом роде, вам нужно проверить это, чтобы убедиться, что это одна из ваших ожидаемых инструкций, которая может выдавать сигналы #UD execptions / SIGILL. например, проверяя машинный код по адресу ошибки.

Но если вместо этого у вас есть функции, отслеживающие, какую оптимистическую c отправку они только что сделали (чтобы они могли обнаружить, если она не работает), вы необходимо установить переменную перед каждой отправкой, так что это на самом деле дополнительные издержки.

...