Программирование на "С/C++" и не только

Previous Entry Share Next Entry
о методах оптимизации и работы с памятью в C++
filoxsee wrote in ru_cpp
Хочу поделиться своим опытом по программированию и работе с памятью. Уже давно пришел к выводу, что для того, чтобы написать эффективный код (который будет быстро работать) нужно учитывать в первую очередь размещение объектов в памяти. Особенно это проявляется в методе программирования Data oriented designЭто метод, при котором в первую очередь проектирование новой системы начинают с решения, как будут в памяти размещаться ее элементы.

Современные CPU работают очень быстро и эффективность алгоритмов в значительной мере зависит не от самого алгоритма, а от того, как эти алгоритмы работают с памятью (тут речь идет не про фундаментальные алгоритмы сортировки, поиска и т.п. а прикладные алгоритмы реальных программ).
Вот базовые рекомендации при проектировании системы и написании кода, которые я выработал для себя:
1. Минимизируйте количество выделений памяти
2. Используйте хранилища данных
3. Храните одинаковые данные вместе
4. Работайте не с объектами а с коллекциями объектов
5. Поблочное выделение памяти
6. Учитывайте выравнивание
7. Знайте размер типов
Все это, с примерами, и деталями реализации и объяснениями и описал в своей статье: http://itw66.ru/blog/c_plus_plus/491.html

  • 1
Самый лучший метод "оптимизации" - отказаться от с++ и перейти на нечто человеческое, например, Common Lisp или OCaml,

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

Однако, если основным параметром будет скорость работы программы, то С++ будет лучшим выбором. Если нужно переносить между разными платформами, то так же понадобится С++.

Я занимаюсь разработкой игр. Мне важно именно скорость работы игры, а так же то, чтобы я мог запустить ее под: windows, MacOsX, iPhone/iPad, Android, PS3, XBox360, wii. Боюсь предложенные Вами языки будут плохи для моей задачи.

И вот тогда станут крайне актуальными те методы, которые я описывал в статье.

а я - серверных и embeded приложений, в которых производительность также не на последнем месте)

Разработчики игр как-то всё больше предпочитают опять таки что-то более человекообразное, например, ЯП для CLR/CLI. Для которой даже сборщик мусора изначально написан на LISPe.

Переносимость у управляемых сред как бы полная.

Ну а методы, которые Вы сформулировали, должны в идеале волновать исключительно узко специализированных спецов по компиляторам и линковщикам.

Заказали мне на кафедре физики маленькую програмку моделирования частиц в определенной среде. Это не компилятор и не линковщик, но все эти методы были крайне необходимы. В несколько раз увеличивали скорость работы. Кстати программа использовала библиотеку CUDA, т.е. выполнялась не на CPU а на GPU, что еще в 1000 раз увеличивало скорость работы. То же относится к обработке изображения, где я использовал пиксельные шейдеры DirectX.

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

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

Хотя согласен, что заморачиваться этим нужно только при необходимости и преждевременная оптимизация - зло.

Не, я ни разу не сомневаюсь, что корректно написанное и целиком вручную оптимизированное нативное приложение без ошибок, использующее специальные методики управления памятью, будет быстрее, чем аналогичное в управляемой среде. Но кто сказал, что ваша програмка, будучи переписанной на функциональном яп, не заработала бы ещё быстрее? В 90% случаев сишно-сиплюсплюсный код менее производителен тупо из-за фрагментированности кучи.

Ну и прекрасно, пусть себе матрица хранится в контейнере с произвольным О(n) доступом. Не уловил суть примера. Или с++ позволяет создавать структуры данных, недоступные в Lisp?

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

Смысл методов как раз не использовать фрагментированную кучу вообще.

Нет суть примера не в этом. Суть в том, что в зависимости от того, как хранить эту матрицу (по строкам или по столбцам, или еще как то, и соотносить это с алгоритмами, как эта матрица будет обрабатываться) будет зависеть скорость работы. Методы которые я описывал в статье относятся не к оптимизации C++. Они относятся к такому расположению данных в памяти, чтобы все быстрее работало (для других языков эти методы так же сгодятся). Я же не про С++ писал, а про Data oriented design.

Про 2.5 не понял. Хотите сказать, что рост производительности в 2 с половиной раза - это мало? Поиграйте в игру с 16 кадрами в секунду... А потом сравните ощущения с игрой в 40 кадров в секунду. Усилия на оптимизацию явно не будут напрасными!

  • 1
?

Log in