В игровом программировании, каковы определенный C++ или функции STL, который вызывает пожирателей ресурсов производительности? [закрытый]

5
задан gokoon 28 June 2010 в 16:34
поделиться

11 ответов

1) Отладочные сборки. Значительно замедляют работу многих контейнеров stl из-за чрезмерной проверки ошибок. По крайней мере, на компиляторах Microsoft.
2) Чрезмерное выделение динамической памяти. Если у вас есть подпрограмма, содержащая std :: vector внутри нее, И если вы вызовете ее несколько тысяч раз за кадр, она будет очень медленной, и узкое место будет где-то внутри оператора new или другой подпрограммы выделения памяти. Если вы превратите этот вектор в какой-то статический буфер (чтобы вам не приходилось каждый раз воссоздавать его заново), это будет намного быстрее. Выделение памяти происходит медленно. Если у вас есть буфер, обычно лучше использовать его повторно, а не создавать новый при каждом вызове.
3) Использование неэффективных алгоритмов. Например, использование линейного поиска вместо двоичного поиска с использованием неправильных алгоритмов сортировки (например, быстрая сортировка, сортировка в куче быстрее, чем пузырьковая сортировка для несортированных данных, но сортировка вставкой может быть быстрее, чем быстрая сортировка для частично отсортированных данных). Поиск вместо использования std :: map и т. Д.
4) Использование неправильного типа контейнера. Например, std :: vector не подходит для вставки элементов в случайные места. std :: deque, хотя и сравним с std :: vector (произвольный доступ), допускает быстрые push_front и push_back, может быть в 10 раз медленнее, чем std :: vector, если вы вычесть два итератора (снова в MSVC).

7
ответ дан 18 December 2019 в 05:54
поделиться

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

Используйте профилировщик, чтобы увидеть, где у вас есть проблемы.

Даже там, где C++ STL может работать хуже, его код, скорее всего, будет менее подвержен ошибкам. Поэтому пишите код, только если профилировщик показывает наличие проблемы

9
ответ дан 18 December 2019 в 05:54
поделиться

Если вы не создадите весь движок с нуля, вы не заметите разницы в использовании или неиспользовании классов C ++ или STL. В общем, большую часть времени ЦП будет выполнять код, который в любом случае даже не написан вами. Кроме того, накладные расходы, накладываемые любыми языками сценариев, которые вы реализуете (Lua, Python и т. Д.), Затмевают любое небольшое снижение производительности, которое вы можете понести при использовании C ++ / STL.

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

6
ответ дан 18 December 2019 в 05:54
поделиться

Фактически, вы можете использовать классы повсюду, и при этом получить такую ​​же производительность, как у C (и часто лучшую производительность, чем у типичного C).

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

2
ответ дан 18 December 2019 в 05:54
поделиться

Все остальные ответы верны: проблемы с STL и программированием игр в основном связаны с неправильным использованием.

Мой общий подход таков: 1. Напишите его с помощью STL и внимательно выберите подходящий алгоритм, контейнер и т. Д. 2. Профиль для узких мест. 3. Если проблема связана с STL, замените его.

Слишком ранняя оптимизация может действительно замедлить вас и вызвать новые проблемы позже.

Конечно, это зависит и от платформы. Иногда вам приходится писать все самостоятельно, потому что вы просто не можете позволить себе дополнительные накладные расходы на ЦП / ОЗУ, связанные с STL.

1
ответ дан 18 December 2019 в 05:54
поделиться

Вот, на мой взгляд, ключевые моменты для написания производительного кода C ++ / STL:

  • Узнайте, какие стратегии распределения памяти существуют для каждого контейнера STL,
  • Узнайте, какие алгоритмы работают лучше всего с какими категориями итераторов,
  • Изучите полиморфизм времени выполнения и полиморфизм времени компиляции.

Хорошими отправными точками являются:

2
ответ дан 18 December 2019 в 05:54
поделиться

Я рекомендую Эффективный STL Скотта Майерса. Самый большой недостаток производительности STL - это его непонимание. Пожалуйста, усвойте это хорошо!

Также см. Оптимизация программного обеспечения на C ++ Агнером Фогом по темам, связанным с производительностью C ++.

1
ответ дан 18 December 2019 в 05:54
поделиться

У меня нет опыта в играх, но Electronic Arts разработала собственную (несовместимую) реализацию STL. Здесь есть обширная статья, объясняющая мотивы и дизайн библиотеки .

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

0
ответ дан 18 December 2019 в 05:54
поделиться

Страуструп в своей книге The C ++ Programming Language рассказывает о конструкции и производительности STL в целом и, в частности, о различных характеристиках производительности различных типов контейнеров. (3-е издание).

0
ответ дан 18 December 2019 в 05:54
поделиться

В этой книге рассматриваются проблемы, с которыми вы сталкиваетесь при использовании C ++ в играх.

0
ответ дан 18 December 2019 в 05:54
поделиться

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

Однако есть некоторые законные опасения по поводу эффективности, если вы все-таки столкнетесь с использованием STL для отображения в качестве точки доступа профилировщика.

vector<ExpensiveElement> v;
// insert a lot of elements to v
v.push_back(ExpensiveElement(...) );

Этот push_back, приведенный непосредственно выше, имеет наихудший сценарий, когда необходимо линейно копировать все вставленные до сих пор ExrivateElements (если мы превысили текущую емкость). В лучшем случае нам все равно придется без надобности один раз скопировать ExrivateElement.

Мы можем смягчить проблему, сделав векторное хранилище shared_ptr, но теперь мы платим за два дополнительных выделения кучи на каждый вставленный ExrivateElement (один для счетчика ссылок в boost :: shared_ptr и один для ExrivateElement) вместе с накладными расходами указателя. косвенное обращение каждый раз, когда мы хотим получить доступ к ExrableElement, хранящемуся в векторе.

Чтобы уменьшить накладные расходы на выделение / освобождение памяти (обычно это скорее горячая точка, чем дополнительный уровень косвенного обращения), мы можем реализовать быстрый распределитель памяти для ExrivateElement. Тем не менее, представьте, если бы std :: vector предоставил метод alloc_back:

new (v.alloc_back()) ExpensiveElement(...);

Это позволило бы избежать накладных расходов на копирование, но это небезопасно и подвержено злоупотреблениям. Тем не менее, именно это я сделал с нашим векторным клоном в ответ на «горячие точки». Обратите внимание, что я работаю с трассировкой лучей, которая является областью, где производительность часто является одним из самых высоких показателей качества (помимо правильности), и мы ежедневно профилируем наш код, поэтому мы не просто внезапно решили, что вектор не был ' t достаточно эффективен для наших целей.

У нас также не было выбора, кроме как реализовать клон вектора, потому что мы предоставляем комплект для разработки программного обеспечения, в котором реализации std :: vector других людей могут быть несовместимы с нашими собственными. Я не хочу дать вам неправильное представление: исследуйте эти виды решений только в том случае, если ваши сеансы профилировщика действительно требуют этого!

Другой распространенный источник неэффективности - использование связанных контейнеров STL, таких как set, multiset, map, multimap и list. Однако это не обязательно их вина, а скорее ошибка используемого по умолчанию std :: allocator. Они выполняют отдельное выделение / освобождение памяти для каждого узла, поэтому распределитель по умолчанию может быть довольно медленным для этих целей, особенно между несколькими потоками (конкуренция потоков, лучше с пулами памяти для каждого потока).Вы действительно можете повысить скорость, написав свой собственный распределитель памяти (хотя это нетривиальная вещь, и не забудьте о выравнивании, если вы это сделаете).

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

0
ответ дан 18 December 2019 в 05:54
поделиться