Оптимизация косвенного обслуживания внутреннего цикла CPU

StackOverflow https://stackoverflow.com/questions/3487937

  •  28-09-2019
  •  | 
  •  

Вопрос

От http://www.boost.org/community/implementation_variations.html.

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

Я пытаюсь понять «даже во внутренней петле». В частности, какие механизмы реализуются процессорами для выполнения двух кодов (виртуальных против виртуальных или дополнительных уровней косвенности) в том же количестве тактовых циклов? Я знаю о инструкции по трубопроводу и кэшированию, но как можно провести виртуальный вызов в том же количестве тактовых циклов как не виртуальный звонок? Как находится подражание «потеряно»?

Это было полезно?

Решение

Кэширование (например, Кэширование целевой ветки), Параллельные нагрузки (часть трубопроводов, но и такие вещи, как «ударил при промах», которые не столь трубопровод), а также Выполнение вне заказа могут помочь преобразовать load-load-branch в то, что ближе к фиксированному branch. Отказ Инструкция складной / ликвидация (какой правильный срок для этого?) В этапе прогнозирования декодирования или отраслевого прогнозирования трубопровода также могут внести свой вклад.

Все это зависит от многих разных вещей, хотя: сколько различных целей ветви есть (например, сколько различных виртуальных перегрузок вы, вероятно, срабатывают), сколько вещей, которые вы включите (это целевой кэш целевой ветки »? Как насчет ICACHE / DCACHACH?), как виртуальные таблицы или косвенные таблицы вкладываются в память (являются ли они дружественными в кэш, или каждая новая нагрузка VTable, возможно, выселение старого VTable?), является ли кэш-память недействительным из-за неоднократных Multicore Ping-Gonging и т. Д. ...

(Отказ от ответственности: я определенно не являюсь экспертом здесь, и многие из моих знаний происходит от изучения встроенных процессоров в заказах, поэтому некоторые из этого являются экстраполяция. Если у вас есть исправления, не стесняйтесь комментировать!)

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


Редактировать:

Как падающие указывают на вышеуказанный комментарий Оптимизация косвенного обслуживания внутреннего цикла CPU, Ключ к получению этих двух вещей, чтобы принять то же количество времени, - это способность эффективно «уйти в отставку» более чем одну инструкцию на цикл. Устранение инструкции может помочь с этим, но Superscalar Design Вероятно, более важно (ударить при мисс - очень маленький и конкретный пример, полностью избыточные нагрузки могут быть лучшего).

Давайте возьмем идеальную ситуацию, и предположим, что прямая ветвь - это всего лишь одна инструкция:

branch dest

... И непрямая ветвь три (может быть, вы можете получить его в два, но это больше, чем один):

load vtable from this
load dest from vtable
branch dest

Давайте предположим абсолютно идеальную ситуацию: * Это и весь vtable находятся в кэше L1, кэш L1 достаточно быстро, чтобы поддерживать амортизированный один цикл на затраты на обучение для двух нагрузок. (Вы даже можете предположить, что процессор переупорядочил нагрузки и сжимал их с более ранними инструкциями, чтобы они могли выполнить время для их завершения перед веткой; это не имеет значения для этого примера.) Также предположим, что кэш целевой целевой силы является горячий, и нет трубопровода Затраты на промывку для филиала, и инструкция филиала допускается до одного цикла (амортизированного).

То Теоретический минимум Следовательно, время для первого примера является 1 цикл (амортизирован).

Теоретический минимум для второго примера, отсутствующие устранения инструкций или избыточных функциональных единиц или что-то, что позволит уйти в отставку более чем одной инструкции на цикл, составляет 3 цикла (есть 3 инструкции)!

Косвенная нагрузка всегда будет медленнее, потому что есть больше инструкций, пока вы не достигнете к чему-то вроде SuperScalar Design, что позволяет уйти на пенсию более одной инструкции на цикл.

Как только у вас есть, минимум для обоих примеров становится чем-то между 0 и 1 циклами, снова при условии, что все остальное идеально. Возможно, вы должны иметь более идеальные обстоятельства для второго примера, чтобы на самом деле достичь этого теоретического минимума, чем для первого примера, но теперь это возможно.

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

... Это то, где приходит профилирование, что, как правило, хорошая идея в любом случае.

Ты могу Просто поддерживать небольшую паранойю о виртуальных виртуалах в первую очередь. Видеть Статья Noel Llopis о ориентированном на данных дизайн, отлично Ловушки объектно-ориентированных программированных слайдов, и Майк Агон с грудимии. Отказ Теперь вы вдруг переехали в узоры, что ЦП уже может быть доволен, если вы обрабатываете много данных.

Особенности языка высокого уровня, такие как виртуальные, обычно представляют собой компромисс между выразительностью и контролем. Хотя я, честно говоря, хотя, просто увеличивая вашу осведомленность о том, что на самом деле делает виртуальный (не боишься прочитать вид разборки время от времени и определенно заглядывать в руководствах архитектуры вашего ЦП), вы будете иметь тенденцию использовать его Когда это имеет смысл, а не когда это не так, и профилировщик может охватить остальные при необходимости.

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

Другие советы

Трубопроводы является основным способом.

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

Что происходит, я думаю, что процессор имеет специальный кэш, который содержит местоположения и цели ветвей и косвенных прыжков. Если косвенный прыжок встречается на 12345678 годах на 12345678 глину, и в последний раз его столкнулись, он пошел на решение $ 12348765, процессор может начать спекулятивное исполнение инструкций по адресу $ 12348765, даже до того, как он разрешит адрес филиала. Во многих случаях, в пределах внутреннего цикла функции, определенный косвенный прыжок всегда будет прыгать на тот же адрес в течение всего продолжительности цикла. Таким образом, кэш непрямой прыжка может избежать разветвленных штрафов.

Современные процессоры используют метод прогнозирования адаптивной ветви, который может предсказать множество косвенных прыжков, таких как вы получаете с помощью VTable реализации виртуальных функций. Видеть http://en.wikipedia.org/wiki/branch_prediction_prediction_of_indirect_jumps

Если CPU уже имеет адрес памяти в кэше, то выполнение инструкции нагрузки тривиально, если это.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top