Должны ли мы все еще оптимизировать «в малом»? - PullRequest
16 голосов
/ 18 апреля 2009

Я изменял свой цикл for на инкремент, используя ++i вместо i++, и подумал, действительно ли это необходимо? Конечно, современные компиляторы делают эту оптимизацию самостоятельно.

В этой статье http://leto.net/docs/C-optimization.php, от 1997 года Майкл Ли занимается другими оптимизациями, такими как встраивание, разворачивание петли, заклинивание петли, инверсия петли, снижение прочности и многие другие. Они все еще актуальны?

Какие низкоуровневые оптимизации кода мы должны делать и какие оптимизации мы можем игнорировать?

Редактировать: Это не имеет никакого отношения к преждевременной оптимизации. Решение по оптимизации уже принято. Теперь вопрос в том, какой из них наиболее эффективен.

анекдот: однажды я просмотрел спецификацию требований, в которой говорилось: «Программист должен оставить сдвиг на единицу вместо умножения на 2».

Ответы [ 22 ]

2 голосов
/ 18 апреля 2009

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

2 голосов
/ 18 апреля 2009

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

2 голосов
/ 21 апреля 2009

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

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

2 голосов
/ 18 апреля 2009

В прошлый раз, когда я тестировал ++ it и it ++ на компиляторе Microsoft C ++ для итераторов STL, ++ выдавал меньше кода, поэтому, если вы находитесь в большом цикле, вы можете получить небольшой выигрыш в производительности, используя ++ it.

Для целых чисел и т. Д. Компилятор выдаст идентичный код.

2 голосов
/ 18 апреля 2009

Сделайте это правильно, затем сделайте это быстро - на основе измерения производительности.

Хорошо выбирайте алгоритмы и реализуйте их НАИБОЛЕЕ ЧИТАЕМЫМ способом. Поменяйте удобочитаемость на производительность только тогда, когда вы ДОЛЖНЫ - то есть когда ваш пользователь скажет, что производительность недопустима ни словами, ни своими действиями.

Как сказал Дональд Кнут / Тони Хоар, «преждевременная оптимизация - корень всего зла» - все еще верно и сейчас, 30 лет спустя ...

1 голос
/ 18 апреля 2009
  • Обычно я не оптимизирую ниже, чем сложность O (f (n)), если я не пишу на встроенном устройстве.

  • Для типичной работы g ++ / Visual Studio я предполагаю, что основные оптимизации будут выполнены надежно (по крайней мере, когда будет запрошена оптимизация). Для менее зрелых компиляторов это предположение предположительно неверно.

  • Если бы я выполнял сложную математическую работу с потоками данных, я бы проверил способность компилятора выдавать SIMD-инструкции.

  • Я бы лучше настроил свой код на разные алгоритмы, чем на конкретную версию конкретного компилятора. Алгоритмы выдержат испытание нескольких процессоров / компиляторов, в то время как если вы настроитесь на версию 2008 Visual C ++ (первый выпуск), ваши оптимизации могут даже не сработать в следующем году.

  • Некоторые приемы оптимизации, которые очень разумны на старых компьютерах, сегодня имеют проблемы. Например, операторы ++ / ++ были разработаны вокруг более старой архитектуры, в которой была инструкция приращения, которая была очень быстрой. Сегодня, если вы делаете что-то вроде

    for(int i = 0; i < top; i+=1)

    Я бы предположил, что компилятор оптимизирует i+=1 в inc инструкцию (если бы она была у CPU).

  • Классический совет - оптимизировать сверху вниз.

1 голос
/ 18 апреля 2009

Я хотел кое-что добавить. Эта «преждевременная оптимизация плоха» является своего рода мусором. Что вы делаете, когда выбираете алгоритм? Вероятно, вы выберете тот, который имеет лучшую временную сложность - преждевременная оптимизация OMG. Все же, кажется, все в порядке с этим. Таким образом, похоже, что реальная позиция такова: «преждевременная оптимизация плоха - если вы не сделаете это по-моему» В конце дня сделайте все, что вам нужно, чтобы создать приложение, которое вам нужно сделать.

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

1 голос
/ 18 апреля 2009

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

Что-то вроде ++ i, компромисс между временем и читаемостью настолько незначителен, что, возможно, стоит выработать привычку, если это действительно приведет к улучшению.

1 голос
/ 18 апреля 2009

Как уже говорили другие, ++ я могу быть более эффективным, чем i ++, если я являюсь экземпляром некоторого объекта. Эта разница может иметь или не иметь существенного значения для вас.

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

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

1 голос
/ 18 апреля 2009

Только если вы точно знаете, что они актуальны. Это означает, что либо вы уже исследовали эту проблему на вашем конкретном компиляторе, либо уже сделали следующее:

  1. выдан функциональный код
  2. профилировал этот код
  3. выявленные узкие места
  4. упрощенная конструкция для устранения узких мест
  5. выбранные алгоритмы, минимизирующие вызовы в узкие места

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...