предъявляются жесткие требования по производительности и/или энергопотреблению. Обычно имеются ограничения и на размер кода. В таких условиях оправдано применение достаточно сложных и трудоемких средств компиляции, позволяющих приблизить генерируемый код по указанным характеристикам к программам, написанным на языке ассемблера. К числу таких средств относится метод адаптивного подбора оптимизирующих последовательностей, позволяющий при помощи какой-либо стратегии перебора сопоставить каждому участку программы некоторую последовательность оптимизаций (из фиксированного набора) так, чтобы получить достаточно хороший по заданным характеристикам код. Поскольку пространство перебора слишком велико, обычно не ставится задача полного перебора для нахождения точного оптимума; как правило, применяют алгоритмы генетического перебора, «жадные» алгоритмы или перебор «по градиенту» и ограничивают время поиска решения. В качестве участков адаптивной компиляции могут выступать базовые блоки, функции, циклы или гнезда циклов. Как правило, среда адаптивной компиляции предоставляет интерактивную оболочку, позволяющую пользователю управлять процессом компиляции.
Реализации этого подхода различаются наборами адаптивно применяемых оптимизирующих преобразований и некоторыми другими характеристиками. В адаптивной компиляции используется широкий набор оптимизаций, включающий все их виды, реализованные в базовом компиляторе, в том числе оптимизации циклов (см.: K.D. Cooper, A. Grosul, T.J. Harvey, S. Reeves, Devika Subramanian, Linda Torc-zon and Todd Waterman. ACME: Adaptive Compilation Made Efficient. 2005). В ряде работ применяются относительно узкие множества оптимизаций, например, только преобразования нижнего уровня, ориентированные на специфику целевого процессора, или только оптимизации циклов. Для оценки эффективности сгенерированного кода программа выполняется на
целевом процессоре с замером числа выполненных инструкций.
Хотя адаптивная компиляция в чистом виде не опирается на данные профилирования, их использование может быть полезным. Так, профиль частоты выполнения базовых блоков используется для экономии времени, затрачиваемого на оценочные прогоны вариантов генерируемого кода. Программа выполняется всего один раз с получением профиля, а эффективность ее вариантов, полученных с применением различных оптимизирующих последовательностей, оценивается на основе данных о частоте выполнения базовых блоков.
Профиль можно было бы также учитывать при выборе множества оптимизаций для различных участков программы, что фактически означает интеграцию обычной оптимизации по профилю с переборной адаптивной компиляцией. Разумно было бы также варьировать интенсивность перебора оптимизирующих последовательностей для различных участков программы с учетом частоты их выполнения.
Данные профилирования - важный источник информации для компилятора при принятии решений о целесообразности и параметрах различных оптимизаций. Повышение эффективности кода в результате применения оптимизаций по профилю может составлять в среднем 10-20 %, а для отдельных программ эффект может быть значительно выше. В настоящее время ведутся активные исследования в области оптимизации по профилю, в частности, по динамической реоптимизации приложений по профилю. В сфере компиляции для встроенных систем развиваются переборные методы адаптивной компиляции, позволяющие подбирать оптимизирующие последовательности индивидуально для различных участков программы. В связи с этим интеграция традиционной оптимизации по профилю с переборными методами адаптивной компиляции представляется интересным направлением исследований.
ОРГАНИЗАЦИЯ ПРОФИЛИРОВАНИЯ В РАМКАХ КОНЦЕПЦИИ КОНТРОЛИРУЕМОГО ВЫПОЛНЕНИЯ СЛОЖНЫХ СИСТЕМ
В.А. Галатенко, д.ф.-м.н., К.А. Костюхин, к.ф.-м.н., А.С. Малиновский (Москва)
Специализированные распределенные программно-аппаратные системы, предназначенные для решения ответственных задач, таких как обработка радиолокационных сигналов в реальном времени, в общем случае строятся из множества разнородных компонентов.
В качестве основных характеристик рассматриваемых систем можно выделить: разнородность, наличие узлов, работающих в реальном масштабе времени; часто меняющуюся конфигурацию; внешнюю изолированность и удаленность от разработчика в режиме функционирования.
Ввиду важности решаемых системами задач большое значение приобретает качество их функ-
ционирования, однако сложность систем делает решение этой задачи проблематичным.
Сложные системы создаются для решения определенных задач, достижения заданных целей. Для краткости будем говорить, что у каждой системы есть миссия.
Термин контролируемое выполнение обозначает процесс функционирования сложной системы, при котором она имеет возможность выполнить свою миссию, несмотря на возможное проявление ошибок, атаки и отказы (см.: В.А. Галатенко, К.А. Костюхин. Отладка и мониторинг распределенных разнородных систем. // Программирование. 2002. № 1). Концепция контролируемого выполнения реализована в разра-
ботанном в НИИ системных исследований РАН (НИИСИ РАН) инструментальном комплексе «Система отладки/мониторинга» - СОМ (см.: Н.И. Вьюко-ва, В.А. Галатенко, К.А. Костюхин, Н.В. Шмырев. Организация отладочного комплекса для целевых систем со сложной архитектурой. М.: НИИСИ РАН. 2004).
Факторами, способными привести к некорректному функционированию и/или понизить доступность систем ниже минимально допустимых пределов и тем самым помешать выполнению миссии, в частности, являются аппаратные и программные ошибки; сбои и отказы аппаратуры, ошибки пользователей и обслуживающего персонала, нарушение эксплуатационных требований и регламентов, злоумышленные действия и т.д.
Средства управления информационными системами, применяемые на этапе эксплуатации, ориентированы на такие крупные сущности, как сети, узлы сетей, хосты, устройства, приложения. Концепция контролируемого выполнения предполагает более гибкое и детальное управление системами, включая уровень таких программных объектов, как функции, переменные, выражения.
К инструментам контролируемого выполнения относятся, в частности, средства управления информационными системами, интерактивная отладка, мониторинг, самоконтроль, профилирование, детерминированное воспроизведение предыдущих сеансов выполнения распределенных систем.
Традиционно большинство из перечисленных средств относят к этапам разработки, тестирования и отладки систем. Контролируемое выполнение предполагает распространение механизмов отладки и на этап эксплуатации, что возможно благодаря широкому распространению программного обеспечения (ПО) с открытыми исходными текстами.
Для сложных, ответственных систем целесообразно постоянно контролировать характер их функционирования, по возможности выявляя и ликвидируя проблемы на ранних стадиях их проявления. Поведение таких систем определяется не только программными компонентами, но и темпом поступления внешних событий, наличием ресурсов и т.п. Если не располагать регистрационной информацией, то на практике не удастся воспроизвести ситуацию, приведшую к ошибке и организовать отладку.
Воспроизведение предыдущих сеансов работы комплексов - необходимый компонент контролируемого выполнения для распределенных программно-аппаратных комплексов с недетерминированным поведением, использующий накопленную регистрационную информацию. Эффективная отладка возможна только при наличии гипотез о причинах и местах ошибок. Воспроизведение с различными уровнями детализации помогает выдвигать такие гипотезы, а интерактивная отладка и анализ трассировочной информации проверять их.
Применение средств самоконтроля программ можно рассматривать как распространение объектно-ориентированного подхода на контролируемое выполнение комплексов. Программы в таком случае трактуются не как пассивные объекты, к которым
внешним образом применяются отладочные и управляющие действия с внешней же интерпретацией семантики выполнения, а как активные сущности, самостоятельно контролирующие корректность своего функционирования.
Средства самоконтроля можно рассматривать и как один из инструментов отладки, и как инструмент защиты от атак на доступность, трактуя их как средства самозащиты систем.
Роль профилирования в среде контролируемого выполнения определяется тем, что к распределенным и встраиваемым системам, имеющим узлы, которые работают в реальном масштабе времени, обычно предъявляются жесткие требования по производительности. Для удовлетворения этих требований необходимо обеспечить, с одной стороны, достаточный уровень производительности процессов и потоков, работающих на отдельных узлах, с другой - организовать сбалансированную, эффективную работу системы в целом.
В реализации средств профилирования инструментального комплекса СОМ, учтены основополагающие требования концепции контролируемого выполнения: минимизация воздействия на целевую систему, которая важна с точки зрения отладки, поскольку грубые воздействия могут исказить картину выполнения системы, и следование стандартам при реализации средств контролируемого выполнения, ненобходимое при взаимозаменяемости компонентов инструментального комплекса и для простоты переноса приложений на различные целевые аппаратные платформы.
Прикладной программный интерфейс
для измерения производительности (PAPI)
Современные процессоры, например, семейства x86, IA-64, Power, MIPS, поддерживают профилирование программ посредством использования аппаратных счетчиков - специальных регистров, фиксирующих аппаратные события определенного типа.
В качестве примера аппаратных событий можно привести общее число процессорных тактов, общее число выполненных команд, число выполненных операций с плавающей точкой, число промахов при обращении к виртуальной и кэш-памяти и др.
Целью проекта PAPI (Perfomance Application Programming Interface) является разработка, стандартизация и реализация переносимого и эффективного прикладного программного интерфейса для доступа к аппаратным счетчикам (см.: http://icl.cs.utk.edu/pro-jects/papi/). Проект PAPI поддерживается консорциумом Parallel Tools Consortium (http://www ptools. org). PAPI, по сути, является стандартом для разработчиков ПО, осуществляющего профилирование кода.
В PAPI выделяется два основных уровня: плат-формо-зависимый, функции которого могут использовать расширения ядра, функции целевой операционной системы или непосредственно язык ассемблера, и платформо-независимый, скрывающий от пользователя детали реализации доступа к аппаратным счетчикам конкретного процессора.
На платформо-независимом уровне пользователям PAPI предоставляются интерфейсы верхнего и нижнего уровней, различающиеся сложностью настройки и использования. В настоящее время существуют реализации интерфейсов для языков высокого уровня Си и Фортран.
В проекте PAPI впервые предложено стандартизованное, переносимое решение для профилирования кода посредством управления аппаратными счетчиками событий. Существуют реализации PAPI в виде библиотек для многих современных платформ. Следует отметить также хорошую документированность проекта и простоту использования предлагаемых интерфейсов.
Таким образом, применение PAPI для организации профилирования сложных систем позволяет унифицировать интерфейс к средствам профилирования, а также минимизировать воздействие на целевую систему за счет использования аппаратных счетчиков.
Реализация профилирования в инструментальном комплексе СОМ
В рамках инструментального комплекса СОМ создана библиотека профилирования (БП), представляющая собой программную библиотеку, функции которой предназначены для получения информации о времени выполнения отдельных участков кода прикладных программ программируемых процессоров сигналов (ППС). ППС представляет собой многопроцессорную ЭВМ, состоящую из отдельных плат - модулей обработки сигналов (МОС). На каждом МОС располагается 4 или 8 процессоров цифровой обработки сигналов (ЦПОС), имеющих как локальную память, так и разделяемую с остальными процессорами модуля. Собранная информация может затем быть обработана независимыми программами-профилировщиками.
БП реализует дополненный вариант стандарта PAPI. А именно, кроме функций интерфейса верхнего уровня PAPI реализованы функции настройки параметров профилирования и управления сбором событий в среде ППС. Такой подход позволяет комбинировать программные средства с имеющимися аппаратными возможностями целевой платформы (см.: Eric Chi, A. Michael Salem, R. Iris Bahar Combining Software and Hardware Monitoring for Improved Power and Perfomance Tuning. 2003).
Для включения БП в программный проект необходимо включить заголовочный файл PAPI.h (для программ на языке Си) или PAPI.h96 (для программ на языке ассемблера). Поскольку цифровые процессоры обработки сигналов, используемые в ППС, не имеют аппаратных счетчиков событий, для работы с которыми служит стандарт PAPI, то счетчик событий эмулируется на прерывании от таймера.
Использование БП предполагает ручную инструментовку профилируемой программы. В начале программы надо вставить вызов функции PAPI_li-brary_init, указав в качестве параметра значение PAPIjVERjCURRENT, определенное в заголовочном файле. Эта функция инициализирует таймер и созда-
ет кольцевой буфер, в который будет сохраняться информация о событиях профилирования. В случае успеха функция возвращает PAP1_VER_CURRENT.
Кольцевой буфер создается в локальной памяти процессора, позволяя осуществлять профилирование разных процессоров на одном модуле обработки сигналов. Для управления параметрами буфера (размер и адрес) предназначены функции PAPl_set_ buffer_size, PAPI_get_buffer_size, PAPI_set_buffer_ addr и PAPI_get_buffer_addr.
Рассмотрим пример применения БП для следующей задачи.
На ППС функционирует распределенное приложение, состоящее из компонентов на процессорах двух МОС и процессоре данных (ПД). Компоненты на процессорах первого и второго МОС независимо друг от друга обрабатывают данные, полученные с ПД. Компонент на ПД, получив сигнал о том, что и первый, и второй МОС обработку завершили, забирает данные и посылает новое задание.
Механизм синхронизации межпроцессорного взаимодействия построен на аппаратных событиях. Проблема состоит в том, что компоненты на разных МОС обрабатывают свои данные с разной скоростью (для определенности, первый МОС успевает обработать данные быстрее второго, хотя размеры пачек данных изначально одинаковы). Необходимо так настроить работу приложения, чтобы минимизировать время простоя компонентов на первом МОС в ожидании очередной пачки данных.
Для решения поставленной задачи средствами профилирования необходимо выполнить инструментовку исходного кода компонентов МОС1 и МОС2. А именно, вставить в код вызовы функций PAPI_event_create перед кодом и после него, реализующего ожидание события, извещающего об отправке данных с ПД, а также перед кодом и после него, реализующего обработку данных.
На листинге 1 показан фрагмент инструментованного исходного кода приложения, выполняющегося на МОС1 и МОС2. Здесь интервал между событиями типа 1 соответствует времени ожидания данных с ПД. Интервал между событиями типа 2 соответствует времени обработки данных. Листинг 1.
if (PAPI_library_init (PAPI_VER_CURRENT) !=
! = PAPI_VER_CURRENT) {
exit (1);
}
/* ... */
PAPI_event_create (1, 0); /* Событие с номером 1
соответствует времени ожидания данных с ПД */
ge_wait (EV_READY); PAPI_event_create (1, 0);
PAPI_event_create (2, 0); /* Событие с номером 2
соответствует времени обработки данных */
do_calcs ();
PAPI_event_create (2, 0) ; ge_set (EV_FINISHED); /* ... */
После сборки и запуска инструментованного приложения в локальной памяти каждого процессора, производящего вычисления, будет сохранена информация о событиях профилирования.
На листинге 2 представлена информация о событиях, созданных при помощи функции PAPl_event_ create на МОС1. В первом столбце указаны адреса в локальной памяти ЦПОС. Во втором - информация о событии, то есть номер события, время его наступления в процессорных тиках (временная метка события) и ассоциированные данные (в данном случае дополнительных данных нет, поэтому - ноль). Из листинга видно, первое событие с номером 1 наступает в момент времени 2. Второе событие с номером 1 наступает в момент времени 34698. Первое и второе события с номером 2 наступают в моменты времени соответственно 34699 и 145045.
Листинг 2. Дамп памяти процессора ППС с сохраненной информацией о событиях профилирования
----- Area ----- 2-SP:A y:10070000..c
y:10070000 12 0
y:10070003 1 34698 0 y:10070006 2 34699 0 y:10070009 2 145045 0
Теперь есть вся информация для оптимизации работы приложения. Вычислим среднюю скорость vi обработки данных на первом модуле, поделив размер пачки данных на среднее значение времени обработки (разность значений временных меток события 2). Аналогичным образом из данных о событиях на втором модуле вычисляется его скорость обработки данных v2. Отношение скоростей (v2/v1) и будет коэффициентом, на который необходимо умножать размер пачки для МОС2, чтобы минимизировать время простоя приложения на МОС 1.
Наряду с БП в инструментальном комплексе СОМ реализован графический компонент профилирования, осуществляющий стохастический анализ работы программ.
Через заранее выбранный интервал времени производится остановка целевой программы и счи-тываются значения счетчика команд. Затем приложение опять запускается. В результате получается профиль выполнения программы, из которого видно, какие фрагменты кода выполнялись наиболее часто. Если ранее с помощью инструмента загрузки модулей в систему была загружена символьная (отладочная) информация о пользовательской программе, инструмент профилирования отобразит для каждого адреса также имя функции, в которой программа находилась, и номер строки исходного текста. При отсутствии отладочной информации инструмент профилирования выведет имя функции, предположительно содержащей указанный адрес. В этом случае за именем функции будет стоять вопросительный знак, например, «Fge_wait?».
При наличии дополнительной информации из таблицы имен можно отобразить профиль не только в виде конкретных значений счетчика команд, но и в виде наиболее часто вызываемых функций.
Профилирование является важным аспектом контролируемого выполнения сложных систем. Реализованный в рамках инструментального комплекса СОМ компонент профилирования позволяет эффективно осуществлять настройку приложений для максимального использования аппаратных и программных ресурсов целевой платформы. Интеграция профилирования с другими компонентами инструментального комплекса, такими как компоненты мониторинга и интерактивной отладки, облегчает процесс сбора необходимой информации и обеспечивает единое централизованное управление всеми средствами контролируемого выполнения, входящими в состав инструментального комплекса.
ФОРМУЛИРОВКА ЗАДАЧИ ПЛАНИРОВАНИЯ ЛИНЕЙНЫХ И ЦИКЛИЧЕСКИХ УЧАСТКОВ КОДА
С.В. Самборский (Москва)
Программная конвейеризация циклов представляет собой эффективный метод оптимизации циклов, который позволяет использовать параллелизм операций, относящихся к разным итерациям цикла (см.: Lam M.S. Software pipelining: An effective scheduling technique for VLIW machines. Proc. ACM SIGPLAN 1988 Conf. on Programming Language Design and Implementation. 1988.). Идея конвейеризации состоит в построении такого расписания, при котором последовательные итерации запускаются с постоянным интервалом, и в сведении к минимуму этого интервала за счет совмещения выполнения команд из нескольких соседних итераций. Этот интервал называют основным интервалом (Initiation Interval - II).
Задача планирования может быть сведена к некоторой трудной математической проблеме, например, она может быть сформулирована в виде задачи целочисленного линейного программирования (ЦЛП).
Задачей ЦЛП является нахождение целочисленного оптимума в задаче линейного программирования. Это хорошо изученная №-полная задача (см.: Х. Па-падимитриу, К. Стайглиц. Комбинаторная оптимизация. Алгоритмы и сложность. М. 1985). Рассматривают также смешанные ЦЛП-задачи, в которых требуется целочисленность определенных переменных, не обязательно всех; такие проблемы также относят к ЦЛП. Для практического решения ЦЛП-задач разработаны пакеты программ - солверы, среди которых есть как коммерческие, так и свободно доступные в исходных текстах.
Как правило, в работах, где рассматриваются ЦЛП-формулировки проблемы конвейеризации циклов, ставится задача нахождения расписания, требующего минимального числа регистров, среди расписаний с минимальным II. В данной работе рассмотрена задача нахождения расписания цикла с ми-