Есть две области для оптимизации скорости:
- Где тратится больше всего времени
- Код, который называется наиболее
Какое место лучше всего начать оптимизировать?
Часто код, который вызывается наиболее часто, уже имеет низкое время выполнения. Оптимизируете ли вы медленные, менее называемые области или проводите время за оптимизацией более быстрых и интенсивно используемых областей?
optimization
profiling
Майкл К
источник
источник
Ответы:
Вы должны игнорировать малую эффективность в 95% случаев. Сначала заставьте это работать правильно , затем проанализируйте ...
Твой дизайн.
Ваш выбор высокоуровневых алгоритмов может оказать огромное влияние на общую производительность вашего программного обеспечения, причем один, казалось бы, тривиальный выбор может означать разницу между ожиданием запуска программы в течение 20 минут и быстрым, отзывчивым пользовательским интерфейсом.
Например, в трехмерной игре: если вы начнете с простого плоского списка объектов для графа сцены, вы увидите крайне низкую производительность для относительно небольшого числа объектов; но если вместо этого вы реализуете иерархию томов (например, октре или BVH) и отбираете части дерева во время рисования, вы увидите значительное повышение производительности.
Когда ваш дизайн кажется правильным, тогда вы можете перейти к ...
Низкоуровневая логика.
Алгоритмы более низкого уровня также могут оказать существенное влияние. Например, при обработке изображения, если вы читаете изображение в неправильном порядке, вы столкнетесь с огромным замедлением, когда столкнетесь с постоянными потерями в кэше L2; изменение порядка операций может привести к десятикратному увеличению производительности.
На этом этапе запишите профиль и найдите место, где проводится большая часть времени программы, и найдите способ его устранить.
источник
Во-первых, запустите профилировщик, чтобы узнать, где ваш код тратит свое время.
Затем посмотрите на те места, чтобы увидеть, какие из них выглядят легко оптимизировать.
Ищите самые простые исправления, которые сначала принесут наибольшую прибыль (перейдите к низко висящим фруктам). Не волнуйтесь слишком сильно о том, насколько это важно, точно. Если это легко, исправьте это. Это сложит. 25 простых исправлений могут быть быстрее, чем 1 большое исправление, а их совокупный эффект может быть больше. Если это сложно, сделайте заметку или подайте отчет об ошибке, чтобы вы могли расставить приоритеты позже. На данный момент не беспокойтесь о «большом» или «маленьком» - просто делайте это, пока не дойдете до функций, которые используют очень мало времени. Как только вы это сделаете, у вас должно получиться более четкое представление о том, какие из других обнаруженных вами проблем могут принести вам наибольшую выгоду при минимальных затратах времени.
Не забудьте выполнить профилирование после исправлений в качестве своего рода регрессионного теста, чтобы убедиться, что изменения в производительности дали ожидаемые результаты. Кроме того, не забудьте запустить свой набор регрессий, чтобы убедиться, что ни одна функциональность не была нарушена. Иногда плохая производительность указывает на обходные пути, и попытка исправить производительность нарушает функциональность.
Небольшие функции, которые нельзя оптимизировать, но которые используют много времени, могут все же быть подсказками о том, где оптимизировать. Почему эта функция вызывается так часто? Есть ли функция, вызывающая эту маленькую функцию, которая не нуждается в ее частом использовании? Дублируется ли работа или выполняется ненужная работа? Посмотрите в стеке, сколько раз он вызывается, пока не убедитесь, что его следует вызывать так часто, и посмотрите, не найдете ли вы функцию большего размера с неэффективным алгоритмом.
Отредактировано, чтобы добавить: Поскольку у вас есть определенная функциональность, которая занимает много времени, попробуйте выполнить шаги, описанные выше, только с этой конкретной функцией, выполняемой приблизительно 10 раз
источник
Сложно сказать. Это действительно зависит от того, что делает код. Запустите тест производительности, получите профиль производительности и посмотрите, сколько фактического времени потрачено в различных областях. Ваши обобщения ... обобщения, и это варьируется от проекта к проекту.
Например, код, который вызывается чаще всего, может просто войти в файл или консоль. Нет особого смысла оптимизировать, что, если это уже одна или две строки кода, которые не могут быть упрощены, и может случиться так, что любое усилие по оптимизации чего-то подобного может не стоить затрат на собственное кодирование. Наименее вызываемым кодом может быть какой-то гигантский запрос, используемый в какой-то ужасно сложной функции. Функция может вызываться только 100 раз за весь прогон выполнения (против 10000 для простого оператора ведения журнала), но если для каждого запуска вызова требуется 20 секунд, может быть , именно здесь должна начаться оптимизация? Или это может быть наоборот: большой запрос является наиболее вызываемым, а оператор ведения журнала вызывает только один запрос на каждые 100 запросов ...
Я обычно не беспокоюсь о таких вещах (пока мне не нужно настраивать производительность), если я заранее не знаю, что произойдет.
источник
Ну, «мы» обычно не оптимизируют, пока не возникнет очевидная потребность в оптимизации, когда что-то неприемлемо медленно.
И когда эта потребность проявляется, она обычно дает хорошие подсказки относительно того, что именно требует оптимизации.
Так что ответ обычный: «Это зависит».
источник
Вы должны использовать профилировщик для нескольких типичных прогонов и просматривать общее время, затрачиваемое на каждую часть кода, независимо от того, как и как часто вы туда заходили. Оптимизация этих частей всегда должна давать увеличение скорости.
В зависимости от того, насколько низкоуровневым является ваш язык реализации, вы также должны выяснить, какие части вызывают большинство кеш-пропусков. Консолидация телефонного кода поможет здесь.
источник
Проблема в том, что фраза «где больше всего времени уходит» неоднозначна.
Если это означает «где счетчик программ встречается чаще всего», то я видел программы, в которых наибольшее время было потрачено на функции сравнения строк, выделения памяти и математической библиотеки. Другими словами, функции, которые повседневный программист никогда не должен касаться.
Если это означает «где в коде программиста выполняются операторы, которые занимают большую долю времени», это более полезная концепция.
Проблема с понятием «код, который вызывается чаще всего» состоит в том, что количество времени, которое требуется, является продуктом того, как часто он вызывается и сколько времени требуется на вызов (включая вызываемых абонентов и ввод-вывод). Так как количество времени, которое требуется, может варьироваться в пределах нескольких порядков, количество его вызовов не говорит вам, насколько это серьезная проблема. Функция A может вызываться 10 раз и занимать 0,1 секунды, тогда как функция B может вызываться 1000 раз и занимать микросекунды.
Одна вещь, которая скажет вам, где искать это: всякий раз, когда строка кода тратит время, она находится в стеке . Так, например, если строка кода является горячей точкой, или это вызов функции библиотеки, или если это 20-й вызов в дереве вызовов 30-уровня, если он отвечает за 20% времени тогда это в стеке 20% времени. Случайные выборки стека будут с вероятностью 20% отображать его. Более того, если образцы могут быть взяты во время ввода / вывода, они покажут вам, что объясняет ввод / вывод, что может быть столь же или более расточительным, чем потерянные циклы ЦП.
И это полностью не зависит от того, сколько раз оно вызывается.
источник
Оптимизируйте, где больше всего времени тратится, если только нет особой причины не делать этого (т. Е. Большую часть времени тратится на асинхронную обработку, которую на самом деле не волнует, завершится ли она через 5 или 10 минут). Естественно, код, который вызывается чаще всего, будет занимать относительно большую часть общего истекшего времени просто потому, что даже короткие времена выполнения складываются, когда вы делаете это тысячи раз.
источник
Вы должны работать над кодом, который занимает больше всего времени. Улучшение кода, который занимает всего несколько процентов времени выполнения, может дать вам лишь небольшое улучшение.
Вы провели измерения, чтобы знать, какой код занимает больше всего времени?
источник
Раньше я проводил бенчмаркинг и маркетинг для производителя суперкомпьютеров, поэтому быстрое преодоление конкуренции было не самым важным, а ЕДИНСТВЕННЫМ. Такой результат требовал, чтобы вы использовали комбинацию хорошего алгоритма и структуру данных, которая позволила бы наиболее интенсивно загружаемым процессорам эффективно работать на пике. Это означало, что у вас должно быть достаточно четкое представление о том, какими будут наиболее ресурсоемкие операции и какие типы структур данных позволят им работать быстрее всего. Тогда это было вопросом построения приложения вокруг этих оптимизированных ядер / структур данных.
В более общем смысле типичный после фактического тюнинга. Вы ведете профиль, смотрите на горячие точки, и те горячие точки, которые, как вы думаете, вы можете ускорить, - это те, над которыми вы работаете. Но редко этот подход даст вам что-нибудь близкое к максимально быстрой реализации.
Хотя в более общем смысле (алгоритмические ошибки не выдерживают), для современных машин нужно думать, что производительность определяется тремя факторами: доступ к данным, доступ к данным и доступ к данным! Узнайте об иерархии памяти (регистры, кэши, TLB, страницы и т. Д.) И спроектируйте свои структуры данных, чтобы максимально эффективно использовать их. Как правило, это означает, что вы хотите, чтобы циклы выполнялись в пределах компактной памяти. Если вместо этого вы просто пишете (или получаете) приложение и затем пытаетесь оптимизировать его, вы, как правило, обременены структурами данных, которые плохо используют иерархию памяти, а изменение структур данных, как правило, требует серьезного упражнения по рефакторингу, поэтому часто застрял.
источник
Если вы хотите получить отдачу от ваших усилий по оптимизации, вы должны посмотреть на код, который занимает больше всего времени. Моя общая цель - это то, что занимает как минимум 80% времени. Я обычно нацеливаюсь на увеличение производительности в 10 раз. Иногда это требует серьезных изменений в том, как разработан этот код. Такое изменение дает вам то, что работает примерно в четыре раза быстрее.
Мой лучший прирост производительности за все время - сокращение времени выполнения с 3 дней до 9 минут. Код, который я оптимизировал, занял от 3 дней до 3 минут. Приложение, которое заменило это приложение, сократило это до 9 секунд, но это потребовало смены языка и полного переписывания.
Оптимизация уже быстрого приложения может быть дураком. Я все еще нацелился бы на область, занимающую больше всего времени. Если вы можете взять что-то, используя 10% времени для мгновенного возврата, вам все равно потребуется 90% времени. Вы быстро соблюдаете правило убывающей отдачи.
В зависимости от того, что вы оптимизируете, правило все еще применяется. Ищите основных пользователей ресурса и оптимизируйте их. Если ресурс, который вы оптимизируете, является узким местом системы, вы можете обнаружить, что все, что вы делаете, это заменяете узкое место на другой ресурс.
источник
Как правило, в большинстве случаев это будут более простые функции, а не функции, вызываемые чаще всего миллиард раз в цикле.
Когда вы выполняете профилирование на основе выборок (с помощью инструмента или вручную), часто самые большие горячие точки будут в крошечных листовых вызовах, которые делают простые вещи, например, функцию для сравнения двух целых чисел.
Эта функция часто не выиграет от значительной оптимизации, если она вообще будет. По крайней мере, эти гранулированные горячие точки редко бывают приоритетными. Это функция, вызывающая эту конечную функцию, которая может быть источником проблем, или функция, вызывающая функцию, вызывающую функцию, например алгоритм неоптимальной сортировки. С хорошими инструментами вы можете переходить от вызываемого абонента к вызывающему, а также видеть, кто тратит больше всего времени на вызов вызываемого.
Часто ошибочно зацикливаться на вызываемых и не смотреть на вызывающих абонентов в графе вызовов в сеансе профилирования, если вы не делаете что-то очень неэффективно на микроуровне. В противном случае вы могли бы чрезмерно потеть мелочи и потерять из виду большую картину. Наличие профилировщика в руке не защитит вас от одержимости банальными вещами. Это просто первый шаг в правильном направлении.
Кроме того, вы должны убедиться, что вы профилируете операции, которые соответствуют тем, что пользователи на самом деле хотят делать, иначе быть полностью дисциплинированными и научными в ваших измерениях и тестах не имеет смысла, поскольку это не соответствует тому, что клиенты делают с продуктом. Однажды у меня был коллега, который, черт возьми, отключил алгоритм деления куба на миллиард граней, и он гордился этим .... за исключением того, что пользователи не делят простые 6-полигональные кубы на миллиард фасеты. Все это замедлилось до ползунка, когда он попытался запустить модель производственного автомобиля с более чем 100 000 полигонов для разделения, и в этот момент он даже не смог выполнить 2 или 3 уровня разделения без замедления до сканирования. Проще говоря, он написал код, который был супер оптимизирован для нереально малых входных размеров, которые не
Вы должны оптимизировать реальные варианты использования в соответствии с интересами ваших пользователей, иначе это будет хуже, чем ничего не стоящее, поскольку все эти оптимизации, которые, по крайней мере, в некоторой степени ухудшают удобство сопровождения кода, имеют небольшую выгоду для пользователя и только все эти недостатки для кодовой базы.
источник