Я пытаюсь ускорить схему сжатия целочисленного значения переменной ширины, и я заинтересован в генерации и выполнении кода сборки на лету. В настоящее время много времени тратится на неверно прогнозируемые косвенные отрасли, и генерация кода на основе серии битпотоков, найденных, как представляется, является единственным способом избежать этого штрафа.
Общую технику называют "подпрограммной нитью" (или "вызывать потоки", хотя это имеет и другие определения). Цель состоит в том, чтобы использовать преимущества эффективного прогнозирования call/ret процессоров, чтобы избежать ларьков. Этот подход хорошо описан здесь: http://webdocs.cs.ualberta.ca/~amaral/cascon/CDP05/slides/CDP05-berndl.pdf
Сгенерированный код будет просто серией вызовов, за которыми следует возврат. Если бы было 5 "кусков" ширины [4,8,8,4,16], это выглядело бы так:
call $decode_4
call $decode_8
call $decode_8
call $decode_4
call $decode_16
ret
В реальном использовании это будет более длинная серия вызовов с достаточной длиной, каждая из которых, вероятно, будет уникальной и будет вызываться только один раз. Создание и вызов кода хорошо документировано, как здесь, так и в другом месте. Но я не нашел большого обсуждения эффективности за пределами простого "не делай этого" или хорошо продуманного "дракона". Даже документация Intel говорит главным образом в общих чертах:
8.1.3 Обработка кода самообучения и перекрестной модификации
Действие процессора, записывающего данные в текущий исполняемый код сегмент с целью выполнения этих данных, поскольку код вызывается самомодифицирующийся код. Процессоры IA-32 демонстрируют поведение модели при выполнении саморедактированного кода, в зависимости от того, насколько далеко впереди текущий указатель выполнения, код был изменен.... Самомодифицирующийся код будет выполняться на более низком уровне производительности, чем неавтоматический или нормальный код. Степень производительности ухудшение будет зависеть от частоты модификации и специфические характеристики кода.
11.6 САМО-ИЗМЕНЕНИЕ КОДА
Запись в ячейку памяти в сегменте кода, который в настоящее время кэшированный в процессоре, приводит к тому, что связанная строка (или строки) кэша быть недействительным. Эта проверка основана на физическом адресе инструкция. Кроме того, процессоры семейства P6 и Pentium может ли запись в сегмент кода изменять команду, которая имеет был предварительно выбран для выполнения. Если запись влияет на заранее выбранную команды, очередь предварительной выборки недействительна. Последняя проверка основанный на линейном адресе инструкции. Для Pentium 4 и Процессоры Intel Xeon, запись или snoop инструкции в коде сегмент, где целевая команда уже декодирована и резидентна в кеше трассировки аннулирует весь кеш трассировки. Последний поведение означает, что программы, которые могут самостоятельно модифицировать код, могут ухудшение производительности при работе на Pentium 4 и Intel Xeon процессоры.
Пока есть счетчик производительности, чтобы определить, происходят ли плохие вещи (C3 04 MACHINE_CLEARS.SMC: количество обнаруженных ящиков самомодифицирующего кода). Я хотел бы узнать больше деталей, особенно для Haswell. Мое впечатление состоит в том, что до тех пор, пока я могу написать сгенерированный код достаточно далеко раньше времени, что предварительная выборка команд еще не дошла до этого, и до тех пор, пока я не запускаю детектор SMC, изменяя код на той же странице (четверть- page?) как что-либо в настоящее время выполняется, тогда я должен получить хорошую производительность. Но все детали кажутся крайне неопределенными: насколько близко слишком близко? Насколько далеко?
Попытка сделать их конкретными вопросами:
-
Какое максимальное расстояние перед текущей инструкцией, прецедент Хасуэлла когда-либо бежит?
-
Каково максимальное расстояние позади текущей инструкции, Haswell 'cache cache' может содержать?
-
Каков фактический штраф в циклах для события MACHINE_CLEARS.SMC на Хасуэле?
-
Как я могу запустить цикл generate/execute в прогнозируемом цикле, пока не позволяя префектуру есть собственный хвост?
-
Как я могу организовать поток так, чтобы каждый фрагмент сгенерированного кода всегда "видно впервые" и не наступая на инструкции уже кэширован?