Есть ли польза от замены контейнеров / алгоритмов STL на свернутые вручную?
Я бы рассматривал это только как последний вариант. Контейнеры и алгоритмы STL были тщательно протестированы. Создание новых стоит дорого с точки зрения времени разработки.
Аналогичным образом для std :: vectors, чьи необходимые размеры неизвестны, но имеют достаточно малую верхнюю границу, выгодно ли заменять их статически распределенными массивами?
Сначала попробуйте зарезервировать место для векторов. Проверьте метод std::vector::reserve
. Вектор, который продолжает расти или меняться на большие размеры, будет тратить динамическую память и время выполнения. Добавьте некоторый код, чтобы определить правильное значение для верхней границы.
Я обнаружил, что динамическое распределение памяти часто является серьезным узким местом, и устранение этого может привести к значительному ускорению. Как следствие, я заинтересован в компромиссах производительности, связанных с возвратом больших временных структур данных по значению, возвратом по указателю или передачей результата по ссылке. Есть ли способ надежно определить, будет ли компилятор использовать RVO для данного метода (конечно, при условии, что вызывающей стороне не нужно изменять результат)?
В принципе, всегда передавайте большие структуры по ссылке или по указателю. Предпочитаю проходить по постоянной ссылке. Если вы используете указатели, рассмотрите возможность использования умных указателей.
Насколько кеш-ориентированными являются компиляторы? Например, стоит ли переупорядочивать вложенные циклы?
Современные компиляторы очень хорошо осведомлены о кэшах инструкций (конвейерах) и стараются не допускать их перезагрузки. Вы всегда можете помочь вашему компилятору, написав код, который использует меньше ветвей (из if
, switch
, циклических конструкций и вызовов функций ).
Вы можете увидеть более значительный прирост производительности, настроив свою программу для оптимизации кэша data . Найдите в Интернете Data Driven Design . Есть много отличных статей на эту тему.
Учитывая научный характер программы, числа с плавающей запятой используются повсеместно. Существенным узким местом в моем коде были преобразования из числа с плавающей запятой в целые числа: компилятор генерировал код, чтобы сохранить текущий режим округления, изменить его, выполнить преобразование, а затем восстановить старый режим округления - даже если в программе ничего не было когда-либо менял режим округления! Отключение этого поведения значительно ускорило мой код. Есть ли какие-либо похожие ошибки, связанные с плавающей точкой, о которых мне следует знать?
Для точности сохраните все как double
. Отрегулируйте для округления только при необходимости и, возможно, перед отображением. Это подпадает под правило оптимизации, Используйте меньше кода, исключите посторонний или мертвый код .
Также см. Раздел выше о резервировании пространства в контейнерах перед их использованием.
Некоторые процессоры могут загружать и хранить числа с плавающей запятой быстрее или быстрее целых чисел. Это потребует сбора данных профиля перед оптимизацией. Однако, если вы знаете, что существует минимальное разрешение, вы можете использовать целые числа и изменить свою базу на это минимальное разрешение. Например, когда речь идет о деньгах США, целые числа могут использоваться для обозначения 1/100 или 1/1000 доллара.
Одним из следствий компиляции и связывания C ++ по отдельности является то, что компилятор не может выполнить то, что может показаться очень простой оптимизацией, такой как вызовы методов типа strlen () из условий завершения цикла. Есть ли какая-либо оптимизация, подобная этой, на которую мне следует обратить внимание, потому что она не может быть выполнена компилятором и должна выполняться вручную?
Это неверное предположение. Компиляторы могут оптимизировать на основе сигнатуры функции, особенно если параметры правильно используют const
. Мне всегда нравится помогать компилятору, перемещая постоянные вещи вне цикла. Для верхнего предельного значения, такого как длина строки, присвойте его переменной const
перед циклом. Модификатор const
поможет оптимизатору.
Всегда есть оптимизация обратного отсчета в циклах. Для многих процессоров скачок в регистре равен нулю более эффективен, чем , сравните и скачок, если меньше .
С другой стороны, есть ли какие-то методы, которых я должен избегать, потому что они могут мешать компилятору автоматически оптимизировать код?
Я бы избегал «микрооптимизаций». Если у вас есть какие-либо сомнения, распечатайте код сборки, сгенерированный компилятором (для области, которую вы спрашиваете) при максимальных настройках оптимизации. Попробуйте переписать код, чтобы выразить код сборки компилятора. Оптимизируйте этот код, если можете. Все, что нужно, требует инструкций для конкретной платформы.
Идеи и концепции оптимизации
1. Компьютеры предпочитают выполнять последовательные инструкции.
Ветви расстраивают их. Некоторые современные процессоры имеют достаточно кеша команд, чтобы содержать код для маленьких циклов. Если сомневаешься, не вызывай веток.
2. Устранить требования
Меньше кода, больше производительности.
3. Оптимизируйте дизайн перед кодом
Часто производительность можно повысить, изменив дизайн по сравнению с реализацией проекта. Меньше дизайна способствует меньшему количеству кода, создает большую производительность.
4. Рассмотрим организацию данных
Оптимизировать данные.
Организуйте часто используемые поля в substructures
.
Установите размеры данных, чтобы поместиться в строку данных строки кэша .
Удалить постоянные данные из структур данных.
Максимально используйте спецификатор const
.
5. Рассмотрим обмен страниц
Операционные системы заменят вашу программу или задачу другой. Часто в «файл подкачки» на жестком диске. Разделение кода на куски, которые содержат сильно исполняемый код и менее исполняемый код, поможет ОС. Кроме того, сверните интенсивно используемый код в более узкие единицы. Идея состоит в том, чтобы уменьшить обмен кода с жесткого диска (например, выборка «далеких» функций). Если код должен быть заменен, он должен быть как одна единица.
6. Рассмотрим оптимизацию ввода / вывода
(Включает файловый ввод / вывод тоже).
Большинство операций ввода-вывода предпочитают меньшее количество больших порций данных многим маленьким порциям данных. Жесткие диски любят крутиться. Большие пакеты данных имеют меньше служебных данных, чем меньшие пакеты.
Отформатируйте данные в буфер, затем запишите буфер.
7. Ликвидация конкуренции
Избавьтесь от любых программ и задач, которые конкурируют с вашим приложением для процессора (ов). Такие задачи, как сканирование вирусов и проигрывание музыки. Даже драйверы ввода-вывода хотят часть действия (именно поэтому вы хотите уменьшить количество транзакций ввода-вывода).
Это должно вас занять некоторое время. : -)