Волкова немного о её семинарах (1119514), страница 2
Текст из файла (страница 2)
Машинно-независимые оптимизирующие преобразования.
1. Удаление недостижимого кода (задача компилятора найти и убрать его).
Пример: if (1) S1; else S2; S1; .
2. Оптимизация линейных участков программы.
В современных системах программирования существует компонента, называемая профилировщиком, который на основе запуска программы выдаёт информацию о том, на какие её линейные участки приходится основное время выполнения, соответственно в первую очередь надо оптимизировать эти участки.
а) Удаление бесполезных присваиваний.
Пример: a=b*c; d=b+c; a=d*c; d=b+c; a=d*c;
Однако, в следующем фрагменте эта операция уже не бесполезна:
p=&a; a=b*c; d=*p+c; a=d*c;
б) Исключение избыточных вычислений.
Пример: d=d+b*c; a=d+b*c; c=d+b*c; t=b*c; d=d+t; a=d+t; c=a;
в) Свертка объектного кода (выполнение во время компиляции тех операций исходной программы, для которых значения операндов уже известны).
Пример: i=2+1; j=6*i+i; i=3; j=21;
г) Перестановка операций (для дальнейшей свертки или оптимизации вычислений).
Пример: a=2*b*3*c; a=(2*3)*(b*c);
a=(b+с)+(d+e); a=(b+(c+(d+e)));
д) Арифметические преобразования (на основе алгебраических и логических тождеств).
Пример: a=b*c+b*d; a=b*(c+d);
a*1 a, a*0 0, a+0 a .
e) Оптимизация вычисления логических выражений.
Пример: a || b || c || d; a, если а есть true.
Но! a || f(b) || g(c) не всегда а (при а=true), может быть побочный эффект.
3. Подстановка кода функции вместо ее вызова в объектный код.
Как правило, этот метод применим к очень простым функциям и процедурам, вызываемым непосредственно по адресу, без применения косвенной адресации через таблицы RТTI (Run Time Type Information). Некоторые компиляторы допускают применять его только к функциям, содержащим последовательные вычисления без циклов. Язык С++ позволяет явно указать (inline), для каких функций желательно использовать inline-подстановку.
4. Оптимизация циклов.
а) Вынесение инвариантных вычислений из циклов.
Пример: for (i=1; i<=10; i++) a[i]=b*c*a[i];
d=b*c; for (i=1; i<=10; i++) a[i]=d*a[i];
б) Замена операций с индуктивными (образующими арифметическую прогрессию) переменными (как правило, умножения на сложение).
Пример: for (i=1; i<=N; i++) a[i]=i*10;
t=10; i=1; while (i<=N) {a[i]=t; t=t+10; i++;}
Пример: s=10; for (i=1; i<=N; i++) { r=r+f(s); s=s+10;}
s=10; m=N*10; while (s<=m) {r=r+f(s); s=s+10;}
(избавились от одной индуктивной переменной).
в) Слияние и развертывание циклов.
Пример: for (i=1; i<=N; i++) for (j=1; j<=M; j++) a[i][j]=0;
k=N*M; for (i=1; i<=k; i++) a[i]=0; (только в объектном коде!)
Развертывание циклов можно выполнить для циклов, кратность выполнения которых известна на этапе компиляции.
Пример: for (i=1; i<=3; i++) a[i]=i;
a[1]=1; a[2]=2; a[3]=3;
Машинно-зависимые оптимизирующие преобразования.
При выполнении машинно-зависимой оптимизации компилятор принимает во внимание те или иные составляющие архитектуры вычислительной системы (особенности аппаратных и программных средств), на которой результирующая программа будет выполняться.
1. Распределение регистров процессора.
Использование регистров общего назначения и специальных регистров (аккумулятор, счетчик цикла, базовый указатель) для хранения значения операндов и результатов вычислений позволяет увеличить быстродействие программы. Доступных регистров всегда ограниченное количество, поэтому перед компилятором встает вопрос их оптимального распределения и использования при выполнении вычислений.
2. Оптимизация передачи параметров в процедуры и функции.
Обычно параметры процедур и функций передаются через стек. При этом всякий раз при вызове процедуры или функции компилятор будет создавать объектный код для размещения ее фактических параметров в стеке, а при выходе из нее - код для освобождения соответствующей памяти. Можно уменьшить код и время выполнения результирующей программы за счет оптимизации передачи параметров в процедуру или функцию, передавая их через регистры процессора.
Реализация данного оптимизирующего преобразования зависит от количества доступных регистров процессора в целевой вычислительной системе и от используемого компилятором алгоритма распределения регистров. Этот метод имеет недостатки. Оптимизированные таким образом процедуры и функции не могут быть использованы в качестве библиотечных, т.к. методы передачи параметров через регистры не стандартизованы и зависят от реализации компилятора. Кроме того, этот метод не может быть использован, если где-либо в функции требуется выполнить операции с адресами параметров. Языки Си и С++ позволяют явно указать (register), какие параметры и локальные переменные желательно разместить в регистрах.
3. Оптимизация кода для процессоров, допускающих распараллеливание вычислений.
При возможности параллельного выполнения нескольких операций компилятор должен порождать объектный код таким образом, чтобы в нем было максимально возможное количество соседних операций, все операнды которых не зависят друг от друга. Для этого надо найти оптимальный порядок выполнения операций для каждого оператора (переставить их).
Пример: a+b+c+d+e+f;
для одного потока обработки данных: ((((a+b)+c)+d)+e)+f;
для двух потоков обработки данных: ((a+b)+c)+((d+e)+f);
для трех потоков обработки данных: (a+b)+(c+d)+(e+f);
Интегрированная среда разработки (ИСР).
Современная ИСР - комплекс программных средств, поддерживающих полный жизненный цикл ПП. Комплекс инструментальных средств, входящих в состав ИСР, иногда называют интегрированным CASE-средством (вспомните первую лекцию).
Продвинутая ИСР объединяет в себе следующие компоненты:
-
репозиторий, являющийся основой ИСР. Он должен обеспечивать хранение версий проекта и его отдельных компонентов, синхронизацию поступления информации от различных разработчиков при групповой разработке, контроль данных о проекте на полноту и непротиворечивость;
-
графические средства анализа и проектирования, обеспечивающие создание и редактирование иерархически связанных диаграмм, образующих модели ПП, а также графический пользовательский интерфейс, обеспечивающий взаимодействие с функциями API (Application Program Interface - прикладного программного интерфейса ОС).
-
средства разработки приложений, включая языки 4GL (языки четвертого поколения - four generation languages) и генераторы кодов; 4GL оперируют графическими образами синтаксических структур языка программирования и элементов интерфейса, при этом проектировать и разрабатывать прикладное программное обеспечение может пользователь, не являющийся квалифицированным программистом, зато имеющий представление о предметной области, на работу в которой ориентирована прикладная программа. Описание программы, построенное на основе языков 4GL, затем транслируется в исходный текст и файл описания интерфейса, представляющие собой обычный текст на соответствующем входном языке высокого уровня. С этим текстом уже может работать профессиональный программист-разработчик - корректировать и дополнять его необходимыми функциями. Такой подход позволяет разделить работу проектировщика, отвечающего за общую концепцию всего проекта, дизайнера, отвечающего за внешний вид интерфейса пользователя, и профессионального программиста, отвечающего непосредственно за создание исходного кода;
-
редактор текстов;
-
средства документирования;
-
средства тестирования и отладки;
-
средства управления проектом;
-
средства реинжиниринга (позволяют восстановить логику и структуру программы по ее исходным текстам, с целью модификации или перенесения на другую платформу).
Простая ИСР объединяет в себе возможности текстовых редакторов исходных текстов программ, отладчиков и командный язык компиляции.
Работая в ИСР, программист может не выполнять всю последовательность действий от порождения исходного кода до его выполнения, он даже может не описывать этот процесс с помощью сценария компиляции и компоновки Makefile. Ему достаточно лишь указать в удобной интерфейсной форме состав необходимых для создания программы исходных модулей, библиотек, а также некоторые ключи, необходимые компилятору и другим техническим средствам.
После этого ИСР сама готовит необходимый сценарий компиляции и компоновки, выполняет его, получает результат и сообщает о возникших ошибках, если они были. Сам текст исходных модулей программист может изменить, не прерывая работу с ИСР, а затем при необходимости повторить весь процесс компиляции.
Примеры ИСР: Turbo Pascal, Delphi, Visual Studio (под ОС Windows); K-develop для K Desktop Environment под ОС LINUX (в приведённой терминологии они будут простыми ИСР).
Редакторы текстов.
В принципе текстовые редакторы появились вне какой-либо связи со средствами разработки ПО. Они решали задачи создания, редактирования, обработки и хранения на внешних носителях любых текстов, которые не обязательно должны были быть исходными текстами программ на языках высокого уровня. Многие редакторы и сейчас успешно выполняют эти функции.
По принципу действия можно выделить несколько разновидностей текстовых редакторов:
-
строковые, позволяющие смотреть и редактировать текст только на одной строке, заканчивающейся признаком "конец строки";
-
потоковые, воспринимающие текст в виде потока символов, признак конца строки также является символом;
-
экранные, позволяющие перемещать по тексту окно, по которому можно перемещать курсор и устанавливать его в нужные позиции; многие экранные редакторы позволяют видеть на экране текст в том виде, в котором он будет напечатан.
Достаточно богатые возможности предоставляют пользователю текстовые редакторы для подготовки текстовых документов, статей, книг. Они позволяют работать с отдельными блоками текстов, форматировать абзацы, расставлять переносы, разбивать текст на страницы, составлять и вставлять в текст сложные рисунки и формулы, поддерживают многие кодировки и управление шрифтами, собирают оглавление, добавляют колонтитулы, составляют предметный указатель.
Наиболее известным и популярным текстовым редактором такого рода является Microsoft Word (компании Microsoft в ОС Windows). Аналогичен ему по возможностям редактор StarOffice (компании Sun Microsystems Inc. в ОС UNIX). Такие мощные системы принято называть текстовыми процессорами.
Возникновение ИСР позволило включить текстовый редактор в состав средств разработки ПО в целом. В современных СП в рамках текстового редактора можно не только подготавливать исходные тексты программ, но и выполнять все интерфейсные и сервисные функции, предоставляемые СП - компилировать, отлаживать, компоновать, загружать и запускать программу на выполнение. И хотя разработчики могут использовать любые средства для подготовки исходных текстов программ, они все же предпочитают пользоваться именно тем текстовым редактором, который включен в состав данной системы программирования.
Основные функции текстового редактора в рамках ИСР программного обеспечения:
-
подготовка текста программы (обычные действия по созданию, редактированию, сохранению файла с текстом программы),
-
многооконный интерфейс с поддержкой режима "буксировки" фрагментов текста мышкой (drag&drop),
-
интеграция с компилятором:
-
визуализация текста с выделением лексем (синтаксическая подсветка элементов языка),
-
дополнение кода, интерактивная подсказка (а. получаем список всех членов класса, f( контекстный список параметров метода f),
-
шаблоны кода (на "горячих" клавишах - часто используемые программные конструкции),
-
всплывающие подсказки об атрибутах идентификаторов, если на них установить курсор, отображение ошибок, обнаруженных на этапе компиляции, в тексте программы,
-
интеграция с отладчиком:
-
отображение контрольных точек останова при отладке,
-
отображение текущего значения объекта, при наведении курсора на идентификатор.
Средства тестирования. Отладчики.
Прежде всего, необходимо осознать, что тестирование – это процесс обнаружения дефектов в программных продуктах. После того как дефект обнаружен, начинается отладка – выявление причины дефекта и ее устранение.