Почему нужно оптимизировать движки для новых процессоров той же архитектуры?

39

Когда выпускается новое поколение процессоров, большинство веб-сайтов сообщают, что игровые движки и программы должны быть оптимизированы для нового оборудования. Я не совсем понимаю, почему. Процессор обычно имеет архитектуру, которая определяет, какой тип набора команд он использует. В настоящее время мы все используем amd_x86_64. Зачем обновлять какую-либо программу или компилятор, если все процессоры используют одну и ту же архитектуру? Конечно, есть функции В конвейере нового процессора, который оптимизирует выполнение машинного кода, но зачем самому машинный код менять, если архитектура этого не делает?

salbeira
источник
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат .
Джош
14
«Потребность» - неправильная формулировка, и больше маркетинга, чем правды, во многом так же, как, например, Windows должна поддерживать определенное поколение нового процессора (или нет, как в случае с Windows 7, который в принципе работал бы отлично). хорошо, например, с Райзеном, за исключением использования на 3-4% больше энергии, чем необходимо). Эта настройка только о попытке выжать немного больше из процессора, приближаясь к максимуму. На самом деле, вы можете получить в общей сложности 1-2% в необдуманных примерах из-за разного планирования и использования нескольких новых инструкций.
Деймон
2
Mehrdad
Смотрите мой связанный вопрос о переполнении стека: как на самом деле работает mtune?
23

Ответы:

54

Потому что разные поколения одной и той же архитектуры могут иметь разные наборы команд .

Например, потоковые SIMD-расширения , вероятно, являются наиболее известным набором команд x86, но, тем не менее, несмотря на то, что существует только одна архитектура x86, существуют SSE, SSE2, SSE3 и SSE4.

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

Поэтому, если игровой движок скомпилирован для архитектуры предыдущего поколения, он не будет поддерживать эти новые инструкции. Точно так же может быть необходимо оптимизировать движок для более новых инструкций; SSE4 , например, имеет поддержку инструкций точечного продукта, которые работают с данными массива структур. Оптимизация, которая могла бы использовать преимущества этих более новых инструкций, состояла бы в том, чтобы изменить макет данных на массив структур.

Максимус Минимус
источник
1
@Panzercrisis - спасибо за предложение по редактированию. Чтобы было ясно: исходный вопрос был не о вашем собственном коде, а о коде движка, поэтому «оптимизировать свой собственный код» не является хорошим предложением для редактирования. Тем не менее, это подчеркивало, что мне нужно было уточнить, что когда я сказал «оптимизировать», я имел в виду «оптимизировать код двигателя», поэтому я отредактировал, чтобы рассмотреть это.
Максимус
37

Максимус ответил правильно, я просто хочу рассказать еще одну часть истории:

Само оборудование меняется так, как вам нужно изменить, как вы кодируете, независимо от вновь введенных инструкций.

  • Увеличенный или уменьшенный объем кэша означает, что вам нужно меньше или больше беспокоиться о том, что проблемы с оптимизацией / аннулированием кэша являются проблемами. Больше кеша означает, что с небольшими данными вы можете меньше сосредоточиться на том, чтобы убедиться, что данные соприкасаются с проблемами производительности. Меньшее количество кеша означает, что это может быть проблемой, а очень маленький кеш означает, что с некоторыми большими структурами данных это не будет иметь никакого значения.

  • Новые уровни кэша означают, что вам нужно больше думать о том, как вы организуете еще большие наборы данных (L1, против L2, против L3 против L4).

  • Больше ядер означает, что вам нужно подумать о том, как вы собираетесь лучше использовать многопоточные приложения и как ваше приложение масштабируется в многопроцессорной среде.

  • Более быстрые часы означают, что вам нужно больше думать о задержке памяти, чем думать о скорости вычислений ЦП как о узком месте вашей системы.

  • Количество FPU в системе больше не может соответствовать количеству целочисленных ALU на ядро ​​(AMD имела / имеет подобные архитектуры).

  • Количество тактов, необходимое для вычисления операции, может быть уменьшено или увеличено.

  • Количество доступных регистров изменилось.

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

WHN
источник
«Увеличенные или уменьшенные уровни кэша означают, что вам нужно меньше беспокоиться о когерентности кэша», - практически любой процессор является когерентным. Вы имеете в виду ложный обмен? Даже чем фактически любая линия CPU $ почти всегда 64 B ...
Maciej Piechotka
1
Мацей просто принимал ваше заявление о когерентности кэша :) Вы, вероятно, имели в виду "оптимизацию кэша" или что-то в этом роде. Когерентность кэша - это способность системы прозрачно поддерживать согласованное представление о памяти для программного обеспечения, даже если имеется N независимых кэшей. Это полностью ортогонально к размеру. TBH утверждение не очень актуально, но ваш ответ (особенно пункты 5 и 6) затрагивает вопрос лучше, чем принятый IMO :) Возможно, подчеркивая разницу между архитектурой и u-архитектурой, вы выделите ее больше.
Маргарет Блум
4
«Подобно умножению, занимающему больше времени, чем сложению, где, как и сегодня на современных Intel и CPUS, это занимает столько же времени». Это еще не все. В конвейерной архитектуре вы должны различать задержку (когда результат готов) и пропускную способность (сколько вы можете сделать за цикл). Кроме того, современные процессоры Intel имеют пропускную способность 4 и задержку 1. Multiply имеет пропускную способность 1 и задержку 3 (или 4). Это вещи, которые меняются с каждой архитектурой и нуждаются в оптимизации. Например, pdepдля Intel требуется 1 цикл, а для Ryzen - 6, поэтому, возможно, вы не захотите использовать его на Ryzen.
Кристоф
2
@ Ясно, я знаю, что мы говорим здесь о процессорах, но вы никогда не программировали для графических процессоров, не так ли? Один и тот же код дает такие сильно отличающиеся результаты в производительности, что вы часто вынуждены учитывать аппаратные возможности в CUDA. Вот откуда я пришел с этим, размер кеша (разделяемая память, управляемый кеш L1) на самом деле должен учитываться при кодировании чего-то в CUDA.
WHN
2
@ Кристоф правильно. Эталонный тест, который вы связываете, предназначен для цикла по массиву c[i] = a[i] OP b[i](то есть 2 загрузки и 1 хранилище на операцию), поэтому во времени преобладает пропускная способность памяти из-за очень низкой вычислительной интенсивности. Размер массива не показан, поэтому IDK, если он умещается в L1D. ( gcc4.9 -Ofastочень вероятно, что эти циклы автоматически векторизованы, так что вы даже не измеряете стоимость обычных скалярных операций как часть сложного целочисленного кода). Первая строка этой страницы ВАЖНА: Полезные отзывы показали, что некоторые из этих мер серьезно ошибочны. Важное обновление уже в пути .
Питер Кордес
2

Даже помимо серьезных изменений, таких как поддержка новых инструкций, производители микропроцессоров постоянно модифицируют свои конструкции для повышения производительности, и каждая новая конструкция может иметь различную относительную производительность для каждой инструкции или техники. Может быть, вы написали некоторый тщательно оптимизированный код без ветвей для Model X, но Модель Y имеет улучшенный предсказатель ветвлений, который уменьшает штраф за неправильное предсказание для версии кода без ветвей (что также освобождает регистр для использования в другом месте) , Возможно, модель Y поддерживает больший параллелизм определенной инструкции с высокой задержкой, так что теперь развернутый цикл этой инструкции обеспечивает лучшую пропускную способность, в то время как в модели X более короткая последовательность была лучше.

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

Hobbs
источник