Исследование оптимизаций и многопоточного выполнения приложений на CPU. Теория и практика.

для раздела Блоги

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


Создана тема по сбору статистики в играх!!

Хотелось бы предупредить, что я не программист или разработчик, а потому могу ошибаться в деталях. Но в целом, я уверен, что все понял и описал правильно. Уверен, что на конечный вывод мои мелкие ошибки или заблуждения существенно не повлияют. Все мысли и выводы, изложенные в этой статье, являются сугубо моим личным мнением, составленным по материалам из сети. Если вам показалось, что я где-то кого-то в чем-то обвинил, то это следует считать моим личным, субьективным, мнением.
Поехали… :wink:
Конфигурация:
Монитор: Plasma TV 42" Panasonic, 1280x720, HDMI
Процессор: AMD Phenom II X4 925 (TPD 95W) 2.8 ГГц @ 3.5 ГГц при 1.48v.
Материнская плата: Asus M4N72-E Socket AM2+ / AM3 ( nForce 750a SLI )
Охлаждение: CM Hyper 212+ PWM
Оперативная память: 4x2Gb DDR2-800@833 при 1.9v (5-5-5-23)
Видеокарта: MSI 460 GTX HAWK 1GB 780/3600 @ 900/4000 x 2 в SLI 8х+8х
HDD:Crucial M4 128Gb + WD 500Gb + WD1500Gb
Блок питания: Chieftec APS-850C
Корпус:Corsair Carbide Series 200R
 
Все началось с желания апгрейда. Большой мальчик закапризничал и захотел новую игрушку, хотя и старая не плохая.
Голос из зала: «Детей тебе делать и растить надо, а не играть в эти твои компьютеры».
Изучая множество тестов, выбор ГПУ особого труда не занял — SLI 660/660ti, в зависимости от уровня финансов в период совершения покупки.
Вопрос с ЦПУ и платформой оказался сложнее. Осложняла его в основном «жаба». :wink:
Intel выходил дороже и заметно. Как раз на разницу SLI 660 vs SLI 660ti.
Желание поддержать AMD сталкивалось с печалью от получения меньшего FPS и его просадок в играх. С AMD я терял часть производительности будущей, довольно мощной SLI системы (разумеется в сравнении с имеющейся SLI).
В поисках решения куда же идти и что делать, я начал проверять как обстоят дела у игр с многопотоком.
 
Суровые реалии...
 
Мне нужен многоядерный AMD или скорострельный, словно специально «запиленный» для «кривого» софта, Intel?
Решая этот вопрос, «выкуривая» тесты и играясь с бенчмарками, я вдруг получил такую картину:

(увеличенное изображение)
Это бенчмарк Heaven 4, запущенный под OpenGL при минимальных настройках, в окне 800х600.
Как видите FPS составляет ~113 кадров. Казалось бы, бенчмарк это синтетика, должна уметь ВСЕ выжимать из ПК.
Но обратите внимание, что загрузка ЦПУ около 50%, причем заняты все ядра.
MSI Afterburner показывает, что видеокарты загружены на ~40%.
ЦПУ простаивает, ГПУ простаивает… где мои 100500 FPS?
Окай. Снижаю частоту ЦПУ множителем до 2000 МГц с помощью TurboV от вендора матплаты, прямо в рантайме — получаю падение FPS до 90 и падение нагрузки на GPU до 30%. Загрузка ЦПУ в процентах не изменилась вообще! Какого черта?
Возвращаю 3500 МГц и отбираю у процесса бенчмарка одно ядро — FPS почти без изменений.
Отбираю еще одно ядро, остается ему два ядра, — падение до 5-10 FPS, загрузка двух ядер ЦПУ 100%, ГПУ разгрузилось до 1-2%.
Скриншоты к сожалению делал не все, а остался только один. Но суть и так ясна.
А ясно то, что ничего не ясно — ЦПУ простаивает, ГПУ простаивает, а FPS падает, да и вообще его должно зашкаливать в таких разрешениях и при таком качестве.
В поисках ответов я отправился в google, форумы, jabber`ы.
 
Спустя пару дней вечернего чтения и экспериментов виновные были найдены. Их оказалось двое.
1. Windows.
2. Разработчик приложения.
Да, да, внезапно, но Windows опять виноват. Нет, это не кривая установка, поломанная ОСь или что-то подобное.
Это «бага», которая даже не «бага», а вовсе даже «фича».
Здесь банальное введение пользователя в заблуждение диспетчером задач и планировщиком процессов.
Сейчас расскажу и покажу, что происходит на самом деле. Разберем ситуацию на примере бенчмарка Heaven.
Что такое многопоточное приложение?
Это приложение, процесс, который может инициировать несколько потоков обработки данных. Эти потоки называются thread (нить, поток).
Потоки эти не из параллельного мира и их вполне можно пощупать и увидеть с помощью специальных инструментов.
Нам понадобится:

Process Explorer

Запускаем вашу игру/приложение/бенчмарк обязательно в окне.
Открываем Process Explorer.
Жмем пункт Options на верхней панели и ставим галку Always on Top. (Это важно чтобы видеть результат, а игра, будучи неактивным окном, работает не верно, с половиной нагрузки. Попросту ей система урежет приоритет в ресурсах.)
Находим наш процесс по имени в списке, правый клик на нем, далее Propeties, вкладка Threads.
Теперь кликаем на наше окно с бенчмарком, чтобы он получил все ресурсы ПК, а Process Explorer останется поверх.
Смотрим пример:

(увеличенное изображение)
Как оказалось бенчмарк Heaven — однопоточный. Внезапно, да?
Heaven генерирует основной thread в 25% и один мелкий в 7%.
Процент этот не простой. Это процент от общей мощности всех 4 ядер CPU.
Thread может одновременно исполняться только на одном ядре ЦПУ, но одно ядро может выполнять сразу несколько thread. Даже без HT. Так как наш thread потребляет 25%, что составляет 1/4 от всех ядер ЦПУ или 1 ядро, то ясно, что больше FPS нам просто не выжать — цпу перегружено. Нам исправить это нельзя. Только разработчику приложения, а в данном случае возможно даже разработчику движка Unreal.
Так а почему же мы видим частичную загрузку всех ядер в диспетчере задач, а не одного ядра?
Предположу такой механизм — планировщик постоянно перебрасывает этот thread с ядра на ядро. Получается в какой-то момент времени мы имеем 100% загрузку ядра, но так как показания снимаются 1 раз в 1 секунду, то мы похоже видим некую аппроксимацию, усреднение, загрузки каждого ядра.
Именно по этой причине кажется, что CPU простаивает, ГПУ простаивает, но в итоге у нас FPS мало.
А выходит, что ЦПУ то молотит во весь опор! И да, такие броски thread по ядрам, возможно, «бесплатно» не обходятся.
В то же время, некоторые приложения могут «усаживаться» на конкретное ядро и планировщик их не гоняет по ядрам. Видимо этот момент можно регулировать при написании программы.
Есть мнения, что для полной эффективности исполнения приложения, количество его потоков должно превышать количество ядер в два раза, ну или хотя бы ему соответствовать.
В чем же виноват разработчик? В том, что он не провел оптимизацию под многоядерные процессоры.
Да, это труд большой, затратный и т.п.
Плохой Heaven? Да нет, отличный бенчмарк, красивый. Мне он нравится. У меня есть все бенчи от этого разработчика. Мощности современных ЦПУ от 2х ядер вполне достаточно, чтобы протестировать в нем видеокарту. А вот как тест ЦПУ он годится разве что для теста мощности отдельных ядер у ЦПУ. То есть — моделирование ленивого/жадного/низкоквалифицированного разработчика игры, а ведь в игре, в сравнении с бенчмарком, еще обсчитывается игровая обстановка, ИИ и т.п. Почему же «лагал» Heaven на двух ядрах? Загадка, но возможно ОС сходила с ума от того, что ядер 4, а приложению дали два. Скорее всего на двухядерном ЦПУ будет все окай.
Что же касается конкретных игр, то я проверил Crysis 3 и Battlefield 3 тем же способом.
Обе они генерировали ТРИ основных потока по ~20-23% времени ЦПУ, чем съедали около 65-70% его ресурсов, и два-три мелких потока по 2-5%. Последние за потоки можно было бы и не считать, но три потока по 5% это 15%, а на ядро у нас приходится 25%. В итоге можно сказать, что Crysis 3 и Battlefield 3 хорошо оптимизированы для 4х ядер и способных с хорошей эффективностью их нагрузить, а вот большее количество ядер им поможет слабо.Темп прироста FPS от количества ядер свыше 4 — будет снижен. Собственно тесты Core 2gen/3gen vs FX Vishera это и показывают.
 
Спасибо, что дочитали до конца. Удачи Вам.
 
Update (10.05.2013):
Изучая далее поведение Crysis 3, были получены вот такие результаты.
Локация: Добро пожаловать в джунгли.
Это место — начало уровня, после короткой пробежки и диалога с Психом, нам продемонстрируют в действии оружейные башни, их видно на радаре, а Псих скажет: «чтобы там они (башни) не нашли — оно уже мертво», пролетят вертолеты. Стою на месте в полуразрушенном доме, никуда не ходил еще.
1024x768, High, noAA, 16AF, Vsync ON
Смотрим в небо.

(увеличенное изображение)
 
Смотрим на траву.

(увеличенное изображение)
1024x768, High, noAA, 16AF, Vsync OFF
Смотрим в небо.

(увеличенное изображение)
 
Смотрим на траву.

(увеличенное изображение)
Я написал апдейт статьи только из-за последнего скрина.
На нем видно, что процесс Crysis 3 инициировал 7 потоков обработки и почти на ~100% загрузил все 4 ядра ЦПУ.
Ранее он такое поведение не обнаруживал.
Таким образом,  вывод об оптимизации в статье следует сделать несколько иной:
Crysis 3 способен загрузить работой как минимум 6 ядер ЦПУ, а, учитывая мелкие треды, скорее всего работы хватит и 8 ядрам. Единственное что — такие броски и нагрузки случаются не всегда и в этой игре встречаются только в местах с травой. В корридорах нагрузка на ЦПУ слабая.
Недавно Лаборатория провела тест ЦПУ и ГПУ  как раз в этой же локации.
Как видим Vishera ее 8 ядер не сильно и помогли. Она может тягаться только на равных с i5 без индекса К.
А когда i5 с индексом К соревнуется с ней на равной частоте, то i5 уходит в заметный отрыв.
Phenom II x4 частотой 3.5 ГГц не достаточно для комфортной игры потому, что нагрузка на ЦПУ запредельная, а в случае игрового «замеса» в этой локации ФПС упадет еще сильнее, ниже 20. Можно немного снизить зависимость от ЦПУ, если выставить дальность анимации травы через консоль — e_MergedMeshesInstanceDist 2 (по-умолчанию 4.5 / 8 ). Это поднимет FPS на десяток кадров.
ps. На скришотах OSD информация в игре о ЦПУ и ГПУ получена с помощью Play Claw 4.
Создана тема по сбору статистики в играх!!

UPD 16.07.2015: Из статьи была удалена информация и домыслы о компиляторах.
Оценитe материал
рейтинг: 2.0 из 5
голосов: 4

Возможно вас заинтересует

Популярные новости

Сейчас обсуждают