На каждом языке программирования есть наборы кодов операций, которые рекомендуются над другими. Я попытался перечислить их здесь, в порядке скорости.
- побитовое
- Целочисленное сложение / вычитание
- Целочисленное умножение / деление
- сравнение
- Контроль потока
- Поплавок сложение / вычитание
- Умножение поплавков / деление
Там, где вам нужен высокопроизводительный код, C ++ можно оптимизировать вручную при сборке, использовать SIMD-инструкции или более эффективный поток управления, типы данных и т. Д. Поэтому я пытаюсь понять, является ли тип данных (int32 / float32 / float64) или операция используется ( *
, +
, &
) влияет на производительность на уровне процессора.
- Является ли одиночное умножение на процессоре медленнее, чем сложение?
- В теории MCU вы узнаете, что скорость кодов операций определяется количеством циклов ЦП, которое требуется для выполнения. Значит ли это, что умножение занимает 4 цикла, а сложение - 2?
- Каковы скоростные характеристики основных математических и управляющих кодов потока?
- Если два кода операции выполняют одинаковое количество циклов, то оба могут использоваться взаимозаменяемо без какого-либо увеличения / потери производительности?
- Любые другие технические детали, которые вы можете поделиться относительно производительности процессора x86, приветствуются
c++
performance
optimization
Robinicks
источник
источник
Ответы:
Руководства по оптимизации Agner Fog превосходны. У него есть руководства, таблицы сроков выполнения инструкций и документы по микроархитектуре всех последних моделей процессоров x86 (начиная с Intel Pentium). Смотрите также некоторые другие ресурсы, связанные с /programming//tags/x86/info
Ради интереса я отвечу на некоторые вопросы (цифры из последних процессоров Intel). Выбор операций не является основным фактором в оптимизации кода (если вы не можете избежать разделения).
Да (если только не степенью 2). (Задержка в 3-4 раза при пропускной способности Intel на уровне тактовых импульсов только одна). Однако не пытайтесь избежать этого, так как он добавляет 2 или 3.
Обратитесь к таблицам инструкций Agner Fog и руководству по микроархитектуре, если вы хотите точно знать : P. Будьте осторожны с условными прыжками. Безусловные переходы (например, вызовы функций) имеют небольшие накладные расходы, но не очень.
Нет, они могут конкурировать за тот же порт выполнения, что и другие, или нет. Это зависит от того, над какими другими цепочками зависимостей процессор может работать параллельно. (На практике обычно не принимается никакого полезного решения. Иногда возникает необходимость использовать векторное смещение или векторное перемешивание, которые выполняются на разных портах на процессорах Intel. Но смещением байтов всего регистра (
PSLLDQ
и т. д.) работает в тасовщике.)Документы по микроарху Agner Fog описывают конвейеры процессоров Intel и AMD достаточно подробно, чтобы точно определить, сколько циклов должно пройти цикл на одну итерацию, и является ли узким местом пропускная способность uop, цепочка зависимостей или конкуренция за один порт выполнения. Посмотрите некоторые мои ответы на StackOverflow, например, этот или этот .
Кроме того, http://www.realworldtech.com/haswell-cpu/ (и аналогично для более ранних версий) интересно читать, если вам нравится дизайн процессора.
Вот ваш список, отсортированный для процессора Haswell, основанный на моих лучших оценках. Это не очень полезный способ думать о вещах для чего-либо, кроме настройки asm-цикла. Эффекты предсказания кэша / ветвления обычно преобладают, поэтому пишите свой код, чтобы иметь хорошие шаблоны. Числа очень непостоянны и пытаются учесть высокую задержку, даже если пропускная способность не является проблемой, или для генерации большего количества мопов, которые засоряют канал для других событий, происходящих параллельно. Особенно номера кеша / веток очень скомпонованы. Задержка имеет значение для зависимостей, переносимых циклами, пропускная способность имеет значение, когда каждая итерация независима.
TL: DR, эти числа составлены на основе того, что я представляю для «типичного» варианта использования, в качестве компромисса между задержкой, узкими местами порта выполнения и пропускной способностью внешнего интерфейса (или останавливается для таких вещей, как пропущенные переходы ). Пожалуйста, не используйте эти цифры для какого-либо серьезного анализа .
сдвиг и вращение (счетчик времени компиляции) /
векторные версии всех этих (от 1 до 4 на пропускную способность цикла, задержка 1 цикла)
tmp += 7
цикла вместоtmp = i*7
)sum
переменной. (Я мог бы взвесить это и fp mul до 1 или до 5 в зависимости от варианта использования)._mm_insert_epi8
и т. Д.)y = x ? a : b
, илиy = x >= 0
) (test / setcc
илиcmov
)%
по константе времени компиляции (не степень 2).PHADD
добавление значений внутри вектора)Я полностью сделал это на основе догадок . Если что-то выглядит неправильно, это либо потому, что я думал о другом сценарии использования, либо об ошибке редактирования.
Относительная стоимость вещей на процессорах AMD будет одинаковой, за исключением того, что они имеют более быстрые целочисленные сдвиги, когда число сдвигов является переменным. Процессоры семейства AMD Bulldozer, разумеется, работают медленнее в большинстве программ по ряду причин. (Ryzen довольно хорош во многих вещах).
Имейте в виду, что на самом деле невозможно свести вещи к одномерной стоимости . Помимо пропусков кэша и неправильных предсказаний ветвлений, узким местом в блоке кода может быть задержка, общая пропускная способность UOP (внешний интерфейс) или пропускная способность определенного порта (порта выполнения).
«Медленная» операция, такая как деление на FP, может быть очень дешевой, если окружающий код заставляет процессор загружаться другой работой . (вектор FP или sqrt равен 1 моп каждый, у них просто плохая задержка и пропускная способность. Они блокируют только блок деления, а не весь порт выполнения, на котором он находится. Целочисленный div - это несколько моп.) Так что, если у вас только один делитель FP на каждые ~ 20 муль и сложение, и для ЦП есть другая работа (например, независимая итерация цикла), тогда «стоимость» div FP может быть примерно такой же, как муль FP. Вероятно, это лучший пример чего-то, что имеет низкую пропускную способность, когда все, что вы делаете, но очень хорошо сочетается с другим кодом (когда задержка не имеет значения), из-за низкого общего числа мопов.
Обратите внимание, что целочисленное деление не так дружелюбно по отношению к окружающему коду: в Haswell это 9 моп, с пропускной способностью 8-11c и задержкой 22-29c. (64-битное деление намного медленнее, даже на Skylake.) Таким образом, задержки и числа пропускной способности несколько похожи на FP div, но FP div - это всего лишь один шаг.
Для примеров анализа короткой последовательности insns для пропускной способности, задержки и общего числа мопов см. Некоторые из моих ответов SO:
sum += x[i] * y[i]
в развертывании с несколькими векторными аккумуляторами, чтобы скрыть задержку FMA. Он довольно технический и низкоуровневый, но показывает тип вывода на ассемблере, который вы хотите получить от компилятора, и почему это важно.IDK, если другие люди пишут SO ответы, включая этот вид анализа. Мне гораздо легче найти свою собственную, потому что я знаю, что часто вхожу в эту деталь, и я помню, что я написал.
источник
Это зависит от рассматриваемого процессора, но для современного процессора список выглядит примерно так:
В зависимости от ЦП может быть значительная плата за работу с 64-битными типами данных.
Ваши вопросы:
if
тем, что вы можете разумно делать с арифметикой.И, наконец, если вы создаете игру, не беспокойтесь обо всем этом, лучше сконцентрируйтесь на создании хорошей игры, чем прерывая циклы процессора.
источник
Я сделал тест на целочисленные операции, которые зациклились миллион раз на x64_64, и пришел к краткому выводу, как показано ниже:
добавить --- 116 микросекунд
суб ---- 116 микросекунд
мул ---- 1036 микросекунд
Div ---- 13037 микросекунд
приведенные выше данные уже уменьшили накладные расходы, вызванные циклом,
источник
Руководства для процессоров Intel можно бесплатно загрузить с их веб-сайта. Они довольно большие, но технически могут ответить на ваш вопрос. В частности, вам нужно руководство по оптимизации, но в руководстве также есть время и задержки для большинства основных линий ЦП для команд simd, поскольку они варьируются от чипа к чипу.
В общем, я бы рассматривал полные ветви, а также погоню за указателями (обход списков ссылок, вызов виртуальных функций) на вершине списка убийц серверов, но процессоры x86 / x64 очень хороши в обоих случаях по сравнению с другими архитектурами. Если вы когда-нибудь портируете на другую платформу, вы увидите, насколько серьезной может быть проблема, если вы пишете высокопроизводительный код.
источник