Подтвердить что ты не робот

Методы оптимизации на С++

Есть ли сайт, который предоставляет отличный список общих методов оптимизации на С++?

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

4b9b3361

Ответ 1

Два способа написания лучших программ:

Лучше всего использовать язык

  • Код Завершить Стив Макконнелл
  • Эффективный С++
  • Исключительный С++

профиль вашего приложения

  • Определите, какие области кода занимают сколько времени
  • Посмотрите, можете ли вы использовать лучшие структуры данных/алгоритмы, чтобы ускорить работу.

Существует не так много языковой оптимизации, которую можно сделать - она ​​ограничена использованием языковых конструкций (учитесь на # 1). Основное преимущество исходит от № 2 выше.

Ответ 2

Я повторю то, что сказали другие: лучший алгоритм будет выигрывать с точки зрения повышения производительности.

Тем не менее, я работаю в обработке изображений, которые, как проблемный, могут быть более стильными. Например, много лет назад у меня был кусок кода, который выглядел так:

void FlipBuffer(unsigned char *start, unsigned char *end)
{
    unsigned char temp;

    while (start <= end) {
        temp = _bitRev[*start];
        *start++ = _bitRev[*end];
        *end-- = temp;
    }
 }

который вращает 1-битный буфер кадра на 180 градусов. _bitRev - таблица с 256 байтами обратных бит. Этот код примерно такой же жесткий, как вы можете его получить. Он работал на 8-мегагерцовом контроллере лазерного принтера 68 тыс. И занимал примерно 2,5 секунды для бумаги с ограниченным размером бумаги. Чтобы избавить вас от деталей, клиент не мог выдержать 2,5 секунды. Решение было таким же алгоритмом. Разница заключалась в том, что

  • Я использовал таблицу 128K и использовал слова вместо байтов (68K намного счастливее слов)
  • Я использовал устройство Duff для разворачивания цикла так же, как и в короткой ветки.
  • Я включил оптимизацию, чтобы пропустить пустые слова
  • Я, наконец, переписал его в сборке, чтобы воспользоваться инструкцией sobgtr (вычесть один и разветкить на большее) и иметь "свободное" приращение и пред-декременты в нужном месте.

Итак, 5x: нет изменения алгоритма.

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

Ответ 3

Не забывайте о нескольких вещах:
- "Мы должны забыть о небольшой эффективности, скажем, около 97% времени: преждевременная оптимизация - корень всего зла". (c) Дональд Кнут
- Мы могли бы получить больше, если мы будем оптимизировать алгоритмы, а не код.
- Мы оптимизируем только медленные части существующего кода, который будет обнаружен профилировщиком или другим специальным инструментом.

Ответ 4

Agner Fog проделал отличную работу, анализируя вывод нескольких компиляторов относительно конструкций С++. Здесь вы найдете его работу: http://www.agner.org/optimize/.

Intel предлагает отличный документ - "Справочное руководство по оптимизации архитектуры Intel® 64 и IA-32", которое вы найдете в http://www.intel.com/products/processor/manuals/index.htm. Хотя он в основном предназначен для архитектур IA-32, он содержит общие рекомендации, которые могут применяться на большинстве платформ. Очевидно, что это и гид Agner Fog немного пересекаются.

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

Ответ 6

У меня нет сайта с головы, но книга "Исключительный С++" от Sutter превосходна для разработки C/С++. Я настоятельно рекомендую, чтобы каждый программист на С++ читал эту книгу, так как он дает представление о не только оптимизации, но и умном использовании языка, чтобы вы действительно программировали действительно.

Ответ 7

В других инженерных дисциплинах принято указывать бюджеты компонентам системы. Например, двигатели самолета VTOL предназначены для обеспечения определенного уровня подъема, поэтому вес должен быть в пределах лимита. На высоком уровне каждой части самолета предоставляется часть бюджета веса, с которой он должен соответствовать.

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

Классическим примером программного обеспечения является SGI Indy Irix 5.1, отчасти из-за чего у пользователей с интенсивной графикой теперь есть компьютеры Mac и Windows, а не SGI коробки.

"Самое страшное в производительности 5.1 - то, что никто точно не знает, куда именно. Если вы начинаете спрашивать, вы получаете множество указаний пальцев и теорий, но мало фактов. В майском докладе я предложил" 5 % theory ", в которой говорится, что каждая добавленная вещь (Motif, интернационализация, перетаскивание, DSO, несколько шрифтов и т.д.) стоит примерно 5% от машины. После 15 или 20 из них большая часть производительность ушла".

Часто при обсуждении производительности 5% считается незначительным, и советуем подождать, пока возникнет проблема, а затем найдите одно узкое место. Для большой системы, ожидая, пока у вас возникнут проблемы, вы можете просто потерять свой основной бизнес.

Ответ 8

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

for ( int i ( 0); i < x; i++)

всегда писать

for ( int i ( 0); i < x; ++i)

Ответ 9

Вы попросили сайты/источники, содержащие оптимизацию.

Некоторые хорошие были предложены.

Я бы добавил, что почти все говорят, что профилирование - лучший, если не единственный способ найти проблемы с производительностью.

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

ДОБАВЛЕНО:

Верно, что "неправильный алгоритм" может убить производительность, но это, конечно, не единственный способ.

Я очень много настраиваю. На большом программном обеспечении, что обычно убивает производительность, слишком много структуры данных и слишком много слоев абстракции.

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

Это проблема с "общей мудростью". Это часто противоположно мудрости.

Ответ 10

Большинство методов зависят от компилятора, поскольку разные компиляторы оптимизируют по-разному.

Если вы хотите, чтобы некоторые советы по оптимизации были агностически компиляторами, вот два для вас:

  • Не делай этого.
  • (только для экспертов!): Не делайте этого еще.

(извинения Майкл А. Джексон)

Ответ 11

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

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

Единственный оптимизационный совет по С++, о котором я могу думать, - это "понять, что означает ваш код". Поймите, когда С++ копирует временные ряды вокруг, понимает, какие конструкторы и деструкторы вызываются, когда.

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

И, конечно же, не пытайтесь оптимизировать, пока вы не профилировали и не установили, что 1) необходима оптимизация и 2) что нужно оптимизировать.

Изменить: Комментарий прокомментировал о том, что функторы против указателей функций являются встроенными. Вот объяснение:

Функции обычно компилируются по отдельности. Итак, что компилятор знает о функции F, которая принимает указатель на функцию FP в качестве аргумента? Ничего, он должен искать, где вызвано F, и, возможно, там он может найти определенный ключ относительно того, на что указывает FP. Если он сможет определить, что при вызове отсюда FP ВСЕГДА укажет на функцию G, то да, она может сделать встроенную версию F с встроенным внутри нее для этого конкретного сайта вызова. Но он не может просто встраивать G без наложения F, потому что F может быть вызван из других мест, где ему передается другой указатель на функцию. И даже тогда это требует некоторых дорогостоящих глобальных оптимизаций, чтобы определить, что что-то может быть встроено.

Представьте, что вы передаете такой функтор, как это:

struct Ftor {
  void operator()() { ... }
};

поэтому функция F выглядит так:

void F(const FTor& ft) {
  ...
  ft();
  ...
}

теперь компилятор точно знает, какая функция вызывается: строка 2 в функции вызывает функцию Ftor:: operator(). Таким образом, вызов может быть легко сложен.

Конечно, на практике вы обычно настраиваете его, поэтому функцию можно вызвать с любым типом функтора:

template <typename F>
void F(const F& ft) {
  ...
  ft();
  ...
}

Ответ 12

  • Профилируйте свой код, чтобы узнать, что на самом деле занимает больше всего времени.
  • Убедитесь, что вы используете правильный алгоритм
  • Если вы много делаете с хрустом, будьте дружелюбны с вашим кешем и старайтесь делать все возможное на куске данных одновременно, поэтому его не нужно многократно загружать в кеш.

Ответ 13

Извините, у меня нет никаких ссылок для вас, но у меня есть еще один анекдот для добавления в кучу.

У меня была довольно большая std:: map, которую я генерировал с использованием объекта Microsoft CString в качестве ключа. Производительность была неприемлемой. Поскольку все мои строки были одинаковыми по длине, я создал оболочку класса вокруг старомодного массива символов фиксированного размера, чтобы эмулировать интерфейс CString. К сожалению, я не помню точного ускорения, но это было значительным, и итоговая производительность была более чем достаточной.

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

Ответ 14

Meta-Programming может использоваться для перехода от динамического полиморфизма к компиляции временного полиморфизма, создавая безумно оптимальный код в процессе. Alexandrescu Современный дизайн С++ - это хорошая книга, в которой подробно описывается TMP. Не каждая страница посвящена оптимизации, но это часто повторяющееся рассмотрение в проектах программы.

Ответ 15

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

Я имею в виду (как идею), если вы получите 30% -ное улучшение производительности, выбрав немного лучший алгоритм (или класс коллекции/контейнера), улучшение, которое вы можете ожидать от рефакторинга, связанного с С++, будет не более 2%, Улучшение дизайна может дать вам что-то выше 30%.

Если у вас есть конкретное приложение, наилучшей стратегией является измерение и профилирование приложения. Профилирование дает, как правило, самое мгновенное представление о том, какие части относятся к производительности.

Ответ 16

Вот пара поймать все пути для оптимизации.

Нет проблем один для задач оптимизации... они всегда настраиваются вручную на аппаратное/программное обеспечение/системные соображения.


Предполагая, что у вас есть лучший алгоритм:

  • скомпилировать с "show assembly output" и "самую высокую оптимизацию"
  • Посмотрите на сборку
  • идентифицировать неэффективность, которая разрушает оптимизацию компилятора или плохое кэширование
  • Повторите код фрагмента
  • если он все еще плохой цикл возвращается к 2.
  • сделано

Пример здесь: Каков самый быстрый способ обмена значениями в C?


Общие советы:

http://www.ceet.niu.edu/faculty/kuo/exp/exp6/figuree6-1.jpg:

  • Попробуйте сначала с плавающей запятой
  • Попробуйте в секунду с фиксированной точкой
  • Если вы действительно несоизмеримы и имеете много времени и денег, попробуйте его в сборке

http://www.asc.edu/seminars/optimization/fig1.gif:

  • Проверьте, не является ли это памятью или I/O или CPU связаны
  • Атака, которая когда-либо является ограничивающим фактором

Ответ 17

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