21 May 2022

О производительности современных процессоров

Ясное дело, что все это сейчас совершенно не важно, но...
Но сейчас, в перерывах между рытьем окопов и пробежками в ближайшее бомбоубежище, порою хочется найти какое-то чуть менее деструктивное занятие, чем бесконечный doomscrolling. 

Тотальный апгрейд домашнего ПК я сделал еще в январе, с той поры активно его использовал, бенчмаркал и всячески экспериментировал, что в итоге позволило накопить ряд интересных наблюдений. Ну и, помимо всего прочего, переезжал я с i5-6600K на i5-12600K, т.е. процессоры одного класса из разных поколений, а это позволяет ретроспективно оценить успехи процессоростроения компании Intel на интервале в шесть лет.    


Многопоточная производительность

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

В случае 12600K тема многоядерности усложняется фактором гетерогенности, в этом процессоре реализовали аж целых три вида ядер: полноценные высокопроизводительные (P-cores), паразитирующие на них hyper-threading ядра и плюс ядра энергоэффективные (E-cores).

На мой взгляд, тему hyper-threading'а интересно обсуждать и сегодня, спустя 20 лет после рождения этой технологии. Интересно потому, что эффект от HT лежит в широком диапазоне: от прироста производительности в полтора раза, до случаев, когда HT вообще ее заметно снижает. 

Приведу очень наглядный пример поведения этой технологии в трех поколениях i7 процессоров Intel:
i7-8086K   -- 6 ядер, 12 потоков
i7-9700K   -- 8 ядер (без HT)
i7-10700K -- 8 ядер, 16 потоков. 

Типичная производительность этих процессоров (в данном случае, на задачах обработки цифровых фото) выглядят вот так:


Правильная и понятная картина: новое поколение чуть быстрее предыдущего и честные 8 ядер оказываются быстрее, чем 6, удвоенные с помощью hyper-threading'а. 

Но меняем характер нагрузки на задачу по распознаванию текста, и -- бум! -- результаты меняется принципиальным образом:


Внезапно самый старый 8086K обгоняет процессор следующего поколения, а добавление 8 HT ядер в 10-е поколение позволяет получить какие-то совершенно умопомрачительные результаты. Короче, HT тема большая и тут есть чего поисследовать. 

В качестве основного инструмента для своих экспериментов я выбрал хорошо известный Cinebench.
Во-первых, потому что он не супер синтетический и выполняет вполне понятную работу (визуализирует 3D сцену).
Во-вторых, потому что он действительно очень хорошо масштабируется в плане многоядерности.
И, в-третьих, потому что в нем, не смотря на общий аскетизм, все-таки есть возможность задавать количество потоков для генерации нагрузки. Было бы, конечно, идеально, если бы можно было бы задавать маску для используемых ядер процессора, но, при большом желании, это можно делать вне приложения... Причем Cinebench сбрасывает процессорную маску в начале каждой итерации рендринга, а значит прогон на фиксированном наборе ядер требует неотрывного сидения рядом и даже определенной ловкости рук.

Мой подход к экспериментам был простой -- грузить ядра определенного типа и оценивать их вклад в общее дело. Например, включив нагрузку в 4 потока, можно заставить использовать четыре полноценных P-cores (без HT), в следующем эксперименте оставить только E-cores и, в итоге, получить относительное сравнение их производительности. Или можно, например, двухпоточную нагрузку привязать к двум полноценным P-cores, а потом к одному ядру и его HT потоку, а значит получить оценку эффективности HT. И так далее. 

К каким выводам я пришел в результате. 

Первое -- Cinebench невероятно эффективно масштабируется по ядрам. Т.е. цифры полученные при прогонах на ограниченном количестве ядер, по итогу, почти без потерь переходят в результат при полном использовании процессора.   

Второе -- виртуальное HT ядро дает примерно одну треть производительности от ядра настоящего. Т.е. 6 HT ядер показывают результат как два полноценных P-cores ядра. Весьма не плохо, с учетом того, что добавление HT в ядро обычно "стоит" не более 5% его транзисторов. Мои наблюдения за HT в других сценариях говорят о том, что обычно это прибавка на уровне 30-40% и Cinebench тут не является приятным исключением. 

Третье -- E-core действительно примерно соответствует производительности ядра времен Skylake. Если сравнивать в лоб с 6600K, то они медленнее в пределах 10%. Если же сравнивать их против P-core, то разница будет в два раза. Т.е. четыре E-cores это как два ядра P-cores. 

Четвертое -- интегральное сравнение в Cinebench против 6600K дает прирост баллов в 4.3 раза. 

Ну и самый, пожалуй, интересный вывод, это эмпирическая формула процессора.
В многозадачных приложениях 12600K представляет собой как бы процессор с 10 P-cores: 6 настоящих + 2 от HT + 2 от E-cores. Причем, что интересно, эта формула работает с достаточно высокой точностью и в других бенчмарках, например, в бенчмарке CPU-Z. 


Производительность в играх

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

Насколько время выполнения этого самого нехорошего однопоточного куска кода влияет на частоту кадров в игре? Digital Foundry взяли демку для одного из самых современных игровых движков, Unreal Engine 5, взяли Intel i9 10900K и посмотрели как влияет на fps отключение половины ядер процессора или снижение его частоты в два раза. Так вот, отключение половины ядер (т.е. отключение 5 физических ядер из 10) приводит к потере 10% fps. А вот снижение частоты с 5 ГГц до 2.5 ГГц просаживает fps ровно в два раза, т.е. прямо пропорционально частоте.

Причем вроде как скромный прирост от перехода с 5 до 10 физических ядер в UE5 можно считать еще и выдающимся, ибо абсолютное большинство других игр показывают намного более скромные результаты. Вот, к примеру, картина по RDR2:

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

Еще один момент, про который категорически нельзя забывать, исследуя CPU в контексте игр -- сдерживающий фактор в лице видеокарты. Вообще, в абсолютном большинстве существующих тестов, упор обычно делает на практическом аспекте: мол, нет никакого смысла тестировать GeForce 3080 в разрешении 1080p да еще и с низкими настройками графики лишь для того, чтобы посмотреть, как себя в таком искусственном сценарии сможет раскрыть центральный процессор. Согласен, это очень странно, вывалить безумные деньги за топовый видик, чтобы потом играть в 1080p на минималках, но! Во-первых, мониторы с частотой 240 Гц давно перестали быть какой-то экзотикой. А, во-вторых, условно синтетические тесты интересы сами по себе и зачастую дают понять результаты тестов строго прагматических. 

В качестве основного инструмента для тестирования я выбрал Forza Horizon 5. Игру современную, построенную на бесконечно популярной нынче концепции большого открытого мира, поддерживающую DirectX 12, отлично оптимизированную и имеющую хорошо продуманный встроенный бенчмарк. Кстати, одним из удобств этого бенчмарка является то, что производительность разложена на три компоненты и, помимо классического fps вывода картинки на экран, есть возможность посмотреть как CPU справляется отдельно с физикой и отдельного с кодом рендеринга. Эти результаты тоже представлены в виде fps и позволяют ответить на вопрос "а сколько кадров в секунду у меня было, если бы моя видеокарта не являлась бы бутылочным горлышком" без необходимости тестировать в связке с GeForce 3090 или задействовать 720p и низкие детали... 

Я проделал большое количество экспериментов с этим бенчмарком, не ленясь бегать в BIOS и там играться с конфигурацией ядер процессора. Наверное, самый главный результат, который я получил, говорит о том, что 6 P ядер (без HT) дают столько же fps рендеринга, сколько и процессор в своей полной конфигурации (т.е. + 6 HT ядер и + 4 E-Cores). 148.6 fps, цифра совпала до знака после запятой. 

Как этот результат соотносится с результатом моего старенького 6600K? Мой предыдущей процессор обсчитывал рендер со скоростью 78.2 fps, т.е. апгрейд дал прирост по этому параметру на 90%. 
Много это или мало? Ну, если сравнивать 6600K и 12600K в однопотоке, то разница будет примерно +80% (это прирост за счет частоты и архитектурных улучшений за шесть лет), т.е. игра стала работать быстрее примерно настолько же, насколько процессор стал быстрее выполнять однопоточный код. А то, что при этом появилась возможность задействовать еще +12 ядер и HT потоков на финальном результате практически никак не сказалось...  


График нагрузки CPU и GPU для бенчмарка из Assassin’s Creed Origins. Красной рамкой выделен прогон при 720p + very low details + 50% resolution scale. Видим недогруз и CPU и GPU. 

Разнообразия ради я решил еще посмотреть на результаты намного более старой Assassin’s Creed Origins. Тут, правда, таки пришлось включать 720p и низкие детали, для того, чтобы исключить фактор видеокарты, но картина, по итогу, получилась практически аналогичной FH5. Правда, переход от 6 P ядер без HT к полной конфигурации процессора все-таки дал 9% прироста, но тесты в том же Cinebench и "формула" процессора, показывают насколько ничтожна эта цифра.


Вместо заключения

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

Вот вам иллюстрация на тему того, как с прогрессом обстояли дела во второй половине 90-х:

Бенчмарк игры Quake, смотрим Pentium 200 МГц MMX и PIII 800 МГц. За каких-то три с половиной года Intel смогла поднять частоту процессора в четыре (!!) раза и получила практически пропорциональный прирост производительности. Если бы с той поры частота удваивалась хотя бы раз в три года, то сегодня у нас в компьютерах стояли бы процессоры с частотой в 100 ГГц и сами понимаете с какой однопоточной производительностью...

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

Ну и никуда не пропавший спрос на максимальную однопоточную производительность (хотя бы ради тех же игр), все-таки порождает некоторое изменение производительности в пересчете на 1 герц (т.н. IPC). Та же AMD за 8 лет, с 2012 по 2020-й год, смогла получить прирост в IPC практически в два с половиной раза. Безусловно, смешная цифра по мерках 90-х, но в наше время перебирать харчами не приходится. 

Оценка производительности процессоров AMD и Intel, все процессоры для теста запускались на одинаковых частотах

На этом на сегодня все...

 
Украине -- победы и мирного неба над головой! Очень надеюсь, что еще свидимся, да в более веселые времена. 



No comments:

Post a Comment