| 13.08.2009 13:00 | |
Воспользуйтесь преимуществами двухъядерных процессоров Intel® при разработке игр и узнайте, как оптимизировать код с помощью компиляторов Intel®.
Введение
Несмотря на очевидные преимущества технологии Hyper-Threading, многопоточность в игровых приложениях не реализована из-за своей потенциальной сложности. Сейчас, когда в распоряжении пользователей есть двухъядерные процессоры Intel® Pentium® D и Intel® Pentium® 4 Extreme Edition (который к тому же поддерживает технологию Hyper-Threading), количество логических процессоров может быть увеличено до четырех. Осталось воспользоваться этим и увеличить производительность игр как минимум вдвое. Конечно, для этого в них необходимо организовать поточную обработку.
Учитывая все сложности организации многопоточности, понятно настороженное отношение к ней со стороны разработчиков. Однако те из них, кто занимался разработкой ПО для серверных систем, уже знакомы с поточными вычислениями и вполне могут заняться их реализацией в ПО для настольных ПК. Реализация многопоточности в игровых приложениях затруднена из-за того, что в своей основе они имеют сложные структуры данных, которые к тому же функционально зависимы. А основной причиной сложности реализации поточных вычислений в игровых и других приложениях для настольных ПК является то, что возможность использования приложений в многопроцессорных системах не учитывается в процессе их разработки.
Данная статья предназначена специально для архитекторов и разработчиков игровых приложений, которых автор пытается убедить в необходимости реализовывать многопоточность непосредственно в ходе разработки приложений. Таким образом, игры будут использовать все преимущества двух (или даже четырех) процессоров в системах на базе платформ Intel®. Придет время, когда количество ядер в процессорах увеличится еще более, а требования к многопоточности игровых приложений возрастут. Разумеется, это позволит достичь очевидного прироста производительности.
Что такое многопоточность?
Под многопоточностью понимается одновременная обработка различных разделов программного кода двумя и более процессорами. На рис. 1 иллюстрируется разница между однопоточной и двухпоточной обработкой данных. При однопоточной обработке происходит последовательное выполнение программного кода, а при многопоточной – одновременная обработка нескольких потоков. Очевидно, что при параллельной обработке кода на его выполнение требуется меньше времени.
На рис. 1 отмечен интервал, в течение которого продолжается обработка одного потока, в то время как другой уже обработан. Такая ситуация возникает, когда потокам требуется обработать разное количество данных. Теперь понятно, почему для игровых приложений очень важно правильно организовать потоки?
На рисунке также отмечено время завершения обработки последнего потока (другие потоки могут быть в состоянии ожидания, что пагубно влияет на производительность), и начало последовательной обработки (в нашем примере для нее требуются результаты параллельной обработки).
Модели параллельных вычислений
Параллельные вычисления бывают двух видов: с разделением по данным и по функциям. В качестве примера обработки с разделением по данным можно привести одновременные вычисления одной и той же функции с разными аргументами; при разделении по функциям происходит одновременная обработка различных функциональных сегментов кода в разных потоках, что позволяет повысить производительность системы.
Далее в статье будет рассмотрено только разделение по функциям, так как, во-первых, оно подходит для большинства игровых приложений по сравнению с разделением по данным, а во-вторых, его сложнее реализовать. Подробнее о моделях параллельных вычислений вы сможете узнать из источников, указанных в разделе "Дополнительные ресурсы".
Правильная организация потоков
Перед тем как реализовывать многопоточность в своем игровом приложении, выполните следующие действия, которые обеспечат оптимальную обработку вашего кода. Эти действия необходимы при организации параллельных вычислений с разделением по функциям.
Определите функциональные блоки
Сначала найдите в своем программном коде различные функциональные блоки (это будет нетрудно, так как структура игрового приложения чаще всего содержит файл с их описанием). Затем определите связи между функциональными блоками и порядок, в котором они должны обрабатываться. В результате вы должны получить блок-схему своего кода.
Вероятнее всего ее позже придется отредактировать по результатам выполнения действий, описанных в двух следующих разделах, то есть при разработке и реализации вашего проекта.
Определите зависимость между функциональными блоками
После составления блок-схемы необходимо определить, какие зависимости по данным существуют между функциональными блоками. Зависимость поможет понять, какие данные стоит продублировать, а к каким лучше обеспечить синхронизированный доступ. Размер данных влияет в основном на то, будут ли они продублированы в последовательном сегменте программы, либо для них будет организован синхронизированный доступ в параллельном сегменте кода.
Разделите код на потоки
При организации потоков необходимо учитывать зависимость по данным между блоками кода и использование этими блоками ресурсов процессора. Разумеется, потоки должны нести примерно одинаковую нагрузку, поэтому по возможности распределяйте функции таким образом, чтобы обработка потоков заканчивалась одновременно. Таким образом вы не потеряете время, в течение которого один поток должен будет ждать окончания обработки другого.
Еще одной задачей при организации потоков является выбор действий с данными, совместно используемыми различными функциями, то есть дублирование данных или синхронизация доступа к ним. Старайтесь объединять в один поток функции, обращающиеся к одним и тем же данным, тогда они будут выполняться последовательно, и пропадет необходимость синхронизации доступа. Безусловно, необходимо правильно оценить ситуацию, и в случае если доступ к данным последователен, а процессору выгоднее было бы обрабатывать функции в разных потоках, желательно организовать доступ с синхронизацией.
К сожалению, не существует универсального алгоритма определения метода доступа к данным. Не бойтесь экспериментировать и проверять свои действия, помните – даже если реализация поточных вычислений не идеальна, она все же лучше, чем работа процессора вхолостую.
Еще один важный момент: при распределении вычислительных мощностей между несколькими процессорами не нужно привязываться к их конкретному количеству в системе. И если уж вы оптимизируете код под многопоточность, предусмотрите возможность его корректного выполнения с любым количеством процессоров. В настоящее время ведется разработка процессоров, некоторые из которых имеют десятки ядер – кто знает, сколько процессоров будет в системе, которая будет выполнять именно ваш код. Поэтому организуйте многопоточность таким образом, чтобы в случае недоступности процессора формировалась очередь функций, которые будут выполняться, когда процессор освободится. Таким образом, ваш код будет корректно работать в системах с количеством процессоров от одного до n, где n – количество задач кода, предназначенных для параллельной обработки.
Многопоточность в игровых приложениях
Определив, какие блоки кода будут обрабатываться параллельно, вы вплотную подошли к созданию потоков. Это можно сделать несколькими способами. Например, можно воспользоваться прикладным программным интерфейсом операционной системы, для которой предназначено ваше приложение, или универсальным прикладным программным интерфейсом. Еще можно использовать библиотеку OpenMP*, компилятор которой имеет встроенную поддержку организации поточной обработки. Учитывая, что OpenMP содержит средства и для создания, и для синхронизации потоков, предпочтительнее и проще выбрать именно ее. С библиотекой OpenMP могут работать несколько компиляторов, например, компилятор Intel® C++ Compiler.
Разделы кода OpenMP
С помощью указателей разделов OpenMP легко организуются потоки различных функциональных блоков. На рис. 4 представлен раздел кода, в котором для параллельного выполнения четырех разных функций организовано два потока. Как видно из рисунка, для этого потребовалось всего лишь три строчки кода (не считая строк со скобками).
Несмотря на удобство организации поточных вычислений с помощью OpenMP, существует и обратная сторона медали: количество потоков получается не больше количества заданных разделов кода или количества процессоров (в зависимости от того, что меньше). То есть, если код из примера будет выполняться в системе с четырьмя процессорами, то только два из них будут задействованы. И наоборот: если количество разделов в коде больше количества процессоров, то OpenMP самостоятельно будет определять порядок обработки функциональных блоков кода, что может оказаться неоптимальным.
На рис. 4 отмечена строка кода, до которой приложение ждет, пока закончится обработка всех потоков.
Необходимо отметить, что даже использование OpenMP не гарантирует абсолютной надежности вашего кода, поэтому не стоит пренебрегать проверкой условий организации потоков.
Организация очереди задач с помощью компилятора Intel®
Компилятор Intel C++ compiler содержит дополнение к OpenMP, с помощью которого можно создавать очереди задач внутри пула потоков. Таким образом, для выполнения кода будут использованы все процессоры системы (если, конечно, в вашем коде количество параллельных функций не меньше количества процессоров).
На рис. 5 приведен пример организации очереди задач при разделении функций на потоки. Указатели на каждую задачу определяют порядок функций в очереди, согласно которой они выполняются процессором.
При такой организации код будет оптимизирован под любое количество процессоров. Однако, с учетом того, что количество процессоров в системе неизвестно, вам необходимо будет организовать оптимальное формирование очереди функций. С помощью описанного метода, для выполнения кода, разделенного на потоки с использованием OpemMP, будут задействованы все процессоры системы.
Выводы
Организация многопоточности в игровых приложениях – непростая задача, но многих потенциальных трудностей можно избежать, если предусмотреть ее в начале разработки. По мере развития настольных систем и увеличением в них количества процессоров, организация многопоточности выходит на передний план. Разрабатывайте код с учетом использования вычислительных мощностей двух и более процессоров, и ваши игровые приложения будут использовать все преимущества многопоточных вычислений.
Дополнительные ресурсы
Подробнее о реализации многопоточности в механизмах игровых приложений и о поточной обработке в целом вы сможете узнать из статей, размещенных на сайте собщества разработчиков параллельного ПО.
Инструменты для параллельного программирования, представленные ниже, можно также найти на сайте сообщества Intel® Software Network и страницах программной продукции.
- Компилятор Intel® C++
- Intel® VTune™ Performance Analyzer и Intel® Thread Profiler
- Intel® Thread Checker
Об авторе
Джефф Эндрюс – проектировщик приложений в корпорации Intel, специализируется на оптимизации кода для независимых поставщиков ПО. Он также занимается исследованиями в области программных технологий, повышающих производительность приложений при работе с процессорами Intel.
Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.
Комментарии (3) 
| 27.10.2010 06:26
neduser |
Так или иначе трёхмерные проекты - будь то компьютерная игра, виртуальная реконструкция разрабатывается или на основании открытого программного кода SDK, или уже скомпилированным программным обеспечением созданным для разработки трёхмерных приложений. Возьмите к примеру 3d engines - Unreal Tournament, Cry Engine, GameBryo Element, Unity 3D, Torque Game Engine, 3DVia (Virtual tools), 3D Game Stugio, Shiva, Ogre и др. программы движки. Самостоятельно движок создать весьма сложно, кто то пишет на Direct X или Open GL, создавать надо движки такие мощностью Unreal Tournament, Cry Engine есть ли смысл тратить много времени, чтобы научиться писать самостоятельно на открытом программном коде свой движок, собственный 3d редактор, на котором нужно будет сделать после проект и ожидать после, что он получит популярность. Есть в графике отстанет, получиться следующее: потратил много времени, проект 3d никакой, 3d программа для разработки трёхмерных приложений не пользуется спросом. Такая история случилась с трёхмерным движком Panda, который забросили сами разработчики за ненадобностью. Основы разработки многопоточных игровых приложений дело не плохое, но не плохо если бы кто нибудь начал читать курс по 3d engines Anyway dimensional projects - whether a computer game, virtual reconstruction is developed or based on open source code SDK, or have already compiled the software created for the development of three-dimensional applications. Take for example 3d engines - Unreal Tournament, Cry Engine, GameBryo Element, Unity 3D, Torque Game Engine, 3DVia (Virtual tools), 3D Game Studia, Shiva, Ogre, etc. program. Own it's very difficult to create 3d engine, someone wrote on the Direct X or Open GL, i think now needs to creating engines have such power Unreal Tournament, Cry Engine is there any sense to spend much time learning how to write their own open code its own engine, own 3d editor, in which need to be made after the draft and expect after he gained popularity. There is a lag behind schedule, get the following: spent a lot of time, the project is no 3d, 3d program for designing three-dimensional applications are not in demand. Such a thing happened with three-dimensional engine Panda, who scored the developers themselves as useless. Basics of developing multi-threaded gaming is not bad, but not bad if somebody started reading course on 3d engines . Thanks. Sorry for my English |
| 26.11.2010 21:57
Виталий |
Я с Вами не согласен, есть смысл, дело в том что зачастую в данных движках можно легко только создавать те игры для которой данный движок был написан ну или того же жанра. Хотя на перечислимых Вами движках можно создавать игры любого жанра, но возникнут большие сложности написать гонки на движке который изначально писался для РПГ и тому подобное, Вам придётся изучить все классы данного движка для того чтобы понять его работу изнутри, и много Вам совершенно не понадобится, хотя сейчас стараются делать движки по технологии ООП, всё рано перебирать чужой код на много сложнее чем написать свой такой какой вам нужен, который вы будите знать как своего ребёнка, я к чему виду вы можете потратить больше времени на изучение чужого движка чем написать свой. I with You not agree, there is sense, matter of fact that зачастую in data slider possible easy only to create that plays for which given slider was written well or same genre. Though on enumerated by You slider possible to create the plays of any genre, but is appeared greater difficulties to write racing on slider which изначально was written for RPG and the like, You to come to study all classes given slider to understand his(its) functioning изнутри, and much You absolutely will not be necessary though presently try to do the slider on technologies OOP, all early sort the someone else code on much сложнее than write its such what you need, which you wake to know as its child, I to that type you may spend more time for study of the someone else slider than write its. |


Равиль