$ make clean; make CFLAGS=-p
то результирующая программа будет выполняться с профилированием. После выполнения программы остается файл
mon.out
, который интерпретируется программой профилировщиком prof
.Для иллюстрации изложенного мы протестировали
hoc6
на приведенной выше программе Фибоначчи:$ hoc6
Запуск теста$ prof hoc6 | sed 15q
Анализname %time cumsec #call ms/call
_pop 15.6 0.85 32182 0.03
_push 14.3 1.63 32182 0.02
mcount 11.3 2.25
csv 10.1 2.80
cret 8.8 3.28
_assign 8.2 3.73 5050 0.09
_eval 8.2 4.18 8218 0.05
_execute 6.0 4.51 3567 0.09
_varpush 5.9 4.83 13268 0.02
_lt 2.7 4.98 1783 0.08
_constpu 2.0 5.09 497 0.22
_add 1.7 5.18 1683 0.05
_getarg 1.5 5.26 1683 0.05
_yyparse 0.6 5.30 3 11.11
$
Результаты, полученные с помощью профилировщика, также подвержены случайным вариациям, как и те, что получены с помощью функции
time
, поэтому их следует считать лишь указанием настоящих значений, а не принимать за абсолютную истину. Тем не менее при необходимости приведенные значения могут помочь повысить быстродействие программы hoc
. Приблизительно третья часть времени тратится на запись и чтение из стека. Накладные расходы еще более возрастут, если мы будем учитывать время выполнения функций связи csv
и cret
между программами Си (функция mcount
представляет собой часть программы с профилированием, полученную с помощью команды ее -р
.). Замена вызовов функций на макрообращения даст заметную разницу во времени выполнения.Для проверки этого предположения мы изменили
code.c
, заменив вызовы push
и pop
на макрокоманды, управляющие стеком:#define push(d) *stackp++ = (d)
#define popm() *--stackp = pop() /* функция все-таки нужна */
(Функция
pop
все-таки нужна в качестве кода операции нашей машины, поэтому нельзя заменить все обращения к ней.) Новая версия выполняется на 35% быстрее; время в табл. 8.1 сокращается от 5.5 до 3.7 с и от 5.0 до 3.1 с.Упражнение 8.22В макрокомандах
push
и popm
не предусмотрен контроль ошибок. Прокомментируйте разумность такого решения. Как бы вы обеспечили контроль ошибок, производимый в версии с функциями, не снижая быстродействия макрокоманд?8.8 Заключение
Ознакомившись с материалом этой главы, мы можем сделать важные выводы. Во-первых, средства для развития языков очень нужны, так как позволяют сконцентрировать внимание на интересной работе проектировании языка (с ним легко экспериментировать). Грамматика является организующей структурой при реализации: программы привязываются к грамматике и вызываются в подходящий момент в процессе разбора.
Во-вторых, и это уже философский аспект, ценна сама постановка задачи речь идет о разработке языка, а не просто о написании программы. Построение программы как языкового процессора обеспечивает регулярность синтаксиса (т.е. взаимодействие с пользователем), делает более структурированной реализацию. Кроме того, мы получаем гарантию, что новые средства будут хорошо согласовываться с уже реализованными. Под "языками", конечно, следует понимать не только традиционные языки программирования, но и уже упоминавшиеся выше в примерах языки
eqn
и pick
, а также yacc
, lex
, и make
.Рассмотрены здесь и вопросы использования программных средств. В частности, показана роль программы
make
, которая предотвращает целый класс ошибок (например, вы забыли перетранслировать какую-то подпрограмму). Она позволяет избавиться от лишней работы и предоставляет удобный способ сгруппировать в одном файле большое число связанных и, возможно, зависимых операций.С помощью файлов макроопределений вы можете координировать описания данных, доступных более чем в одном файле. Проводя централизацию информации, они исключают ошибки, вызванные несогласованностью применяемых версий, особенно если действуют совместно с программой
make
. Весьма важно разбить данные и подпрограммы на файлы таким образом, чтобы они не были видимы, если в этом нет необходимости.Хотелось бы отметить, что из-за ограниченного объема книги мы мало внимания уделили тем средствам UNIX, которые применяются при разработке семейства программ
hoc
. Каждая версия программы находится в отдельном каталоге, для идентичных файлов используются связи; постоянно вызываются команды ls
и du
, чтобы следить за тем, какие файлы где находятся. На многие вопросы ответы дают сами программы. Например, на вопрос: "Где описана данная переменная?" отвечает программа grep
. "Как мы внесли изменения в данную версию?" отвечает idiff
. "Насколько велик файл?" отвечает wc
. Пора делать копию файла обратитесь к команде cp
. Нужно скопировать только те файлы, которые изменились со времени последнего копирования? Вам поможет в этом деле программа make
.Такой общий подход типичен для повседневной разработки программ в системе UNIX: множество небольших программных средств, каждое в отдельности или их различные сочетания, позволяет автоматизировать работу, которую иначе пришлось бы выполнять вручную.
Историческая и библиографическая справкаПрограмма
yacc
создана С. Джонсоном. Класс языков, для которых yacc может создавать программу разбора, называется LALR-(1): разбор здесь ведется слева направо и входной поток просматривается не более чем на одну лексему вперед. Понятие раздельных описаний для задания приоритетов и разрешения неоднозначностей в грамматике появилось вместе с yacc
. Этот вопрос рассматривается в статье А. В. Ахо, С. К. Джонсона и Д. Д. Ульмана "Deterministic parsing of ambiguous grammars" (CACM, August, 1975). Там же приведены новые алгоритмы и структуры данных для создания и хранения таблиц разбора.Основы теории, на базе которой построены
yacc
и другие программы анализаторы, излагаются в книге А. В. Ахо и Д. Д. Ульмана "Principles of Compiler Design" (Addison Wesley, 1977). Сама программа yacc
описана в справочном руководстве по UNIX (том 2B). В этом разделе также представлен калькулятор, сравнимый с hoc2
: для вас такое сравнение может оказаться полезным.Программа
lex
первоначально было написана М. Леском. Теория lex освещена в книге Ахо и Ульмана, а сам язык lex
описан в справочном руководстве по UNIX.Программы
yacc
и в меньшей степени lex
использовались для реализации многих языковых процессоров, включая переносимый компилятор Си, процессоры на Паскале, Фортране 77, Ратфоре, awk
, be
, egn
и pick
.Программа
make
создана С. Фельдманом и описана в статье "MAKE a program for maintaining computer programs" (Software-Practice & Experience, April, 1979).В книге Д. Бентли "Writing Efficient Programs" (Prentice-Hall, 1982) обсуждается техника ускорения выполнения программ. Акцент в ней делается на создание подходящего алгоритма, а также на улучшение кода, если в этом есть необходимость.
Глава 9Подготовка документации
Средства редактирования и форматирования документации стали одним из ранних приложений системы UNIX. Администрация Bell Labs, приобретая первую установку PDP-11, хотела иметь систему подготовки документации, а не операционную систему. (К счастью, заказчики получили больше, чем ожидали.)