Tw-city.info

IT Новости
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Оптимизация программного кода это

10 слов об оптимизации кода

Немного о грустном: вся наша жизнь – это борьба с тормозами. И вечно так продолжаться не может. Необходимо оптимизировать всё – начиная от своего рабочего места до времени. В этой статье я привёл примеры оптимизации кода на языке программирования Delphi, но поверь, эти советы могут пригодиться тебе и в реальной жизни, если подумать.

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

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

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

4. Старайтесь поменьше использовать вычисления с плавающей запятой. Любые операции с целыми числами выполняются на порядок быстрее. Операции умножения или деления также выполняются достаточно долго. Вместо умножения лучше использовать сложение, а деление можно заменить сдвигом. Сдвиг работает намного быстрее и умножения, и деления. Это связано с тем, что все числа хранятся в двоичной системе. Если перевести число из десятичной системы счисления в двоичную и сдвинуть число вправо на одну позицию, то можно заметить, что данная операция аналогична делению на 2. При сдвиге влево происходит деление числа на 2. Хоть эти операции и аналогичны, но сдвиг работает в несколько раз быстрее.

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

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

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

8. Если ты пишешь достаточно большую и громоздкую программу, добавляй в неё комментарии. Компилятор их всё равно игнорирует. И если вдруг тебе захочется продать исходные коды своих программ, комментарии повысят им цену, да и самому будет легче в них ориентироваться.

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

10. Старайся делать в программах стандартный интерфейс. Ну не надо делать треугольные кнопочки, нестандартные меню и прочие графические навороты. Всё это очень сильно тормозит программу, расходует большое количество ресурсов компьютера и требует дополнительного времени на разработку. К примеру, настоящий UNIX – это вообще обычный shell – строка для ввода команд.

Вот вроде и всё. Желаю, удачи в написании своих программ, просто следуй этим советам, и всё у тебя получиться.

Оптимизация кода

Определение и свойства

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

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

Виды оптимизации

Оптимизация кода может проводиться как и вручную, программистом, так и автоматизированно. В последнем случае оптимизатор может быть как отдельным программным средством, так и быть встроенным в компилятор (т.н. оптимизирующий компилятор). Кроме того, следует отметить, что современные процессоры могут оптимизировать порядок выполнения инструкций кода.

Существуют такие понятия как высокоуровневая и низкоуровневая оптимизация. Высокоуровневые оптимизации в большинстве проводятся программистом, который, оперируя абстрактными сущностями (функциями, процедурами, классами и т.д.) и представляя себе общую модель решения задачи, может оптимизировать дизайн системы. Оптимизации на уровне элементарных структурных блоков исходного кода (циклов, ветвлений и т.д.) тоже обычно относят к высокому уровню; некоторые выделяют их в отдельный («средний») уровень (Н. Вирт?). Низкоуровневая оптимизация производится на этапе превращения исходного кода в набор машинных команд, и зачастую именно этот этап подвергается автоматизации. Впрочем, программисты на ассемблере считают, что никакая машина не превзойдет в этом хорошего программиста (при этом все согласны, что плохой программист сделает еще хуже и машины).

Выбор оптимизируемого участка

При оптимизации кода вручную существует еще одна проблема: нужно знать не только, каким образом проводить оптимизацию, но и в каком месте её применить. Обычно из-за разных факторов (медленные операции ввода, разница в скорости работы человека-оператора и машины и т.д.) лишь 10% кода занимают целых 90% времени выполнения (конечно, утверждение довольно умозрительно, и имеет сомнительное основание в виде закона Парето, однако выглядит довольно убедительно у Э. Таненбаума). Так как на оптимизацию придется расходовать дополнительное время, поэтому вместо попыток оптимизации всей программы лучше будет оптимизировать эти «критичные» ко времени выполнения 10%. Такой фрагмент кода называют узким местом или бутылочным горлышком (bottleneck), и для его определения используют специальные программы — профайлеры, которые позволяют замерять время работы различных частей программы.

Читать еще:  Программа для оптимизации игр торрент

На самом деле, на практике оптимизация зачастую проводится после этапа «хаотического» программирование (включающего такие вещи, как «копипаст», «потом разберемся», «и так сойдет»), поэтому представляет собой смесь из собственно оптимизации, рефакторинга и исправления ошибок: упрощение «причудливых» конструкций – вроде strlen(path.c_str()), логических условий (a.x != 0 && a.x != 0) и т.п. Для таких оптимизаций профайлеры вряд ли пригодны. Однако для обнаружения таких мест можно использовать программы статического анализа — средства поиска семантических ошибок на основе глубоко анализа исходного кода — ведь, как видно из второго примера, неэффективный код может быть следствием ошибок (как, например, опечатки в данном примере — скорее всего, имелось ввиду a.x != 0 && a.y != 0). Хороший статический анализатор обнаружит подобный код, и выведет предупреждающее сообщение.

Вред и польза оптимизаций

Практически ко всему в программировании надо относиться рационально, и оптимизации — не исключение. Считается, что неопытный программист на ассемблере обычно пишет код, который в 3-5 раз медленнее, чем код, сгенерированный компилятором (Зубков). Широко известно выражение по поводу ранних, довольно низкоуровневых (вроде борьбы за лишний оператор или переменную) оптимизаций, сформулированное Кнутом: «Преждевременная оптимизация — это корень всех бед».

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

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

Например, рассмотрим язык Си++ и т.н. Return-Value Optimization, суть которой в том, что компилятор может не создавать копии возвращаемого функцией временного объекта. Так как в этом случае компилятор «пропускает» копирование, этот прием также называется «Copy elision». Итак, следующий код:

может иметь несколько вариантов вывода:

Как ни странно, все три варианта являются законными, так как в стандарте языка позволяется пропускать вызов копирующего конструктора в данном случае, даже если у конструктора есть побочные эффекты (§12.8 Копирование объектов класса, пункт 15).

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

PVS-Studio

В статическом анализаторе PVS-Studio реализован набор диагностик, позволяющих обнаруживать некоторые ситуации, когда код может быть оптимизирован. Однако PVS-Studio, как и любой статический анализатор, не может выступать в качестве замены инструментов профилирования. Выявить узкие места могут только динамические анализаторы программ. Статические анализаторы не знают, какие входные данные получают программы и как часто выполняется тот или иной участок кода. Поэтому мы и говорим, что анализатор предлагает выполнить некоторые «микро оптимизации» кода, которые вовсе не гарантируют прироста производительности.

Несмотря на рассмотренный недостаток, анализатор PVS-Studio может выступать хорошим дополнением к инструментам профилирования. Более того, при работе с предупреждениями PVS-Studio, касающимися оптимизации, код часто становится проще и короче. Более подробно этот эффект рассмотрен в статье «Поговорим о микрооптимизациях на примере кода Tizen».

Тема 2.8. Оптимизация программ. Оптимизирующие компиляторы

Понятие оптимизации программ

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

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

Основная цель профилировки – это исследование характера поведения приложения во всех его точках. В зависимости от степени детализации в качестве «точки» рассматривается как отдельная машинная команда, так и целая конструкция высокого языка — функция, цикл, процедура. Сложная программа состоит из большого числа функций. Нет смысла оптимизировать их все – трудоемкость такого подхода будет выше выгод, полученных от оптимизации программы целиком. Для начала необходимо локализовать участки кода с максимальной вычислительной трудоемкостью. Участки программы, которые в наибольшей степени влияют на ее производительность, в силу наиболее частого выполнения или своей ресурсоемкости называются критическим кодом. В поиске критического кода программы используют профайлеры (профилировщики) – специальные программы, которые измеряют временные затраты на выполнение участков кода программы. Профилировщики представляют возможности для оптимизации программ. К таким программам относятся Intel VTune, AMD Code Analyst, profile.exe и множество других. Наиболее мощным из них на сегодняшний день является пакет от Intel. Эта программа позволяет измерить время обработки каждой команды и вывести полную статистику о состоянии процессора при выполнении каждой команды.

Читать еще:  Какие программы лучше для оптимизации компьютера

Большинство современных профилировщиков поддерживают следующий набор базовых операций:

• определение общего времени исполнения каждой точки программы;

• определение удельного времени исполнения каждой точки программы;

• определение причины и/или источника конфликтов;

• определение количества вызовов той или иной точки программы;

• определение степени покрытия программы.

Основные правила оптимизации:

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

2. Основной прирост оптимизации дает не учет особенностей системы, а алгоритмическая оптимизация.

3. Обнаружив профилировщиком узкие места необходимо произвести оптимизацию в рамках языка высокого уровня.

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

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

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

1. Производительность программы признана удовлетворяющей;

2. В программе отсутствуют «горячие точки», то есть количество инструкций равномерно распределено по все программе, и дальнейшая оптимизация потребует переписывания большого количества кода;

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

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

Ко всем методам оптимизации алгоритма предъявляются следующие требования:

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

2. оптимизация не должна увеличивать трудоемкость разработки (в том числе тестирования) приложения более чем на 10-15%.

3. оптимизирующий алгоритм должен давать выигрыш не менее чем на 20-25% в скорости выполнения.

4. оптимизация не должна допускать безболезненное внесение изменений.

Алгоритмические приемы оптимизации

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

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

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

На практике используется весьма широкий набор машинно-независимых оптимизирующих преобразований, что связано с большим разнообразием неоптимальностей. К ним относятся:

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

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

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

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

• реализация действий — это способ повышения быстродействия программы за счет выполнения определенных ее вычислений на этапе трансляции.

• сокращение программы и другие методы.

Машинно-зависимые приемы оптимизации

Машинно-зависимые используют особенности устройства и работы конкретной системы. Ярким примером машинно-зависимой оптимизации является векторизация операций, т.е. использование потоковых расширений процессора, таких как MMX (MultiMedia eXtensions), SSE (Streaming SIMD Extensions) и т.п. Машино-зависимую оптимизацию можно выполнять двумя различными способами. Первый способ основан на понимании работы кодогенератора компилятора, его алгоритма и рекомендуется для приложений, в которых компилятор выбирается в начале проекта и в дальнейшем не меняется. При использовании такого способа преобразуется исходный код программы, написанный на языке высокого уровня. Для тех проектов, в которых заранее не известен компилятор (OpenSource проекты, кроссплатформенные приложения) применятся другой способ, основанный на замещении ресурсоемких участков кода ассемблерными вставками. При такой оптимизации ухудшается переносимость кода на другие платформы. Машинно-зависимые способы оптимизации довольно хорошо автоматизируются и большую часть их выполняют оптимизирующие компиляторы. Однако всегда остаются моменты в программе, которые можно оптимизировать вручную.

Оптимизация программного кода. Основные возможности оптимизации кода программистом и компилятором

Оптимизация программного кода называют изменение корректного кода, направленное на повышение его эффективности. «Оптимизация» подразумевает внесение небольших изменений, затрагивающих один класс, один метод, а чаще всего – несколько строк кода. Крупномасштабные изменения проекта или другие высокоуровневые способы повышения производительности оптимизацией не считаются. Это не самый эффективный способ повышения производительности. Улучшение архитектуры программы, перепроектирование классов и выбор более эффективного алгоритма — приводят к более впечатляющим результатам. Кроме того, оптимизация кода не самый легкий способ повысить производительность: легче купить новое оборудование или компилятор с улучшенным модулем оптимизации. Наконец, это не самый дешевый способ повысить производительность: на оптимизацию кода вручную изначально уходит много времени, а потом оптимизированный код труднее сопровождать.

Читать еще:  Программы для оптимизации ноутбука windows 10

1). Расширить структуру данных добавлением дополнительной информации или изменить представление данных в этой структуре. 2). Вычисление результатов заранее и их хранение, для последующего использования. 3). Применение упаковки данных. 4). Внутренний цикл должен содержать min воз­можное количество проверок, а лучше всего только одну. 5). Удаление безусловных переходов. 6). Логические проверки должны быть располо­жены так, чтобы более быстрые условия, которые чаще оказываются пра­вильными, стояли перед более медленными условиями, которые реже оказываются правильными.7).Логическая функция на небольшом множестве исходных значений может быть заменена таблицей, представляющей это множество.8).Удаление одинаковых выражений. 9).Если два и более одинаковых выражения часто вычисляются подряд, их следует вынести в подпрограмму. 10). Изменение типов данных может оказаться эффективным способом сокращения кода и повышения его быстродействия. 11). Переписывание кода на низкоуровневом языке. При низком быстродействии код следует переписать на языке низкого уровня. Если вы пишите на С++, языком низкого уровня может быть Assembler. Переписывание кода на низкоуровневом языке обычно положительно влияет на быстродействие кода.

Методы оптимизации кода могут применяться на разных уровнях синтаксических конструкций: 1). на уровне оператора — большинство компиляторов выполняют некоторую оптимизацию на этом уровне. 2). на уровне блока – оптимизирующий компилятор выделяет операционную структуру программе путем конструирования ориентированного потокового графа программы, в кот каждая вершина представляет основной блок, а связи м/у вершинами представляют потоки управления. Большинство компиляторов производят оптимизацию на уровне блока. 3). на уровне цикла. 4). на уровне программы — наиболее сложный уровень оптимизации.

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

42. Оформление программ: основные пункты.

1) Описание реализации (язык, среда программирования, тестирования, предполагаемого исполнения):

· размеры в байтах, операциях, строках;

· размеры необходимой памяти под данные;

· требуемые технические ресурсы.

2) Обращение к подпрограмме (число, тип и порядок передачи входных параметров): способ передачи (по ссылке или по значению).

3) Описание возвращаемых параметров:

· параметр, который возвращает сама функция;

· описание входных параметров, которые функция изменяет.

4) Описание исключительных ситуаций и реакция программы на них.

5) Описание сообщений программы, если они есть.

6) Краткое описание алгоритма:

· если известен автор, то указать его имя;

· если имеет название, то указать его;

· назвать источник или где приведен текст программы, откуда был взят алгоритм;

· можно привести блок-схему.

7) Привести автора программы и время написания программы.

8) Описать все входные и выходные файлы и краткое их содержимое.

9) Привести структуры записи всех файлов:

· разбивка по полям записи;

· для каждого поля указать тип, длину смещения от начала записи.

Оптимизация

Оптимизация

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

  • Распространением языков сверхвысокого уровня, языков спецификации и систем проектирования. Как правило, подобные системы порождают программы на некотором языке высокого уровня. В этом случае оптимизация может нейтрализовать избыточность такого порождения, приблизив качество сгенерированной программы к ручному программированию.
  • Необходимостью поддержки и сопровождения готовой программы. Такие требования зачастую приводят к тому, что программисты используют не самые эффективные решения в целях улучшения наглядности или легкости сопровождения программ (очень часто соображения эффективности и сопровождаемости противоречат друг другу). В то же время недостатки эффективности могут быть исправлены оптимизатором при генерации окончательной программы.
  • Усилением контроля семантических ошибок. Такие ошибки требуют специального анализа исходной программы, который может являться побочным результатом действий оптимизатора.

Виды оптимизации

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

В зависимости от уровня представления программы различают следующие виды оптимизации:

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

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

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

Ссылка на основную публикацию
ВсеИнструменты 220 Вольт
Adblock
detector
×
×