Предисловие В сборнике представлены статьи сотрудников Института системного программирования, описывающие результаты исследований, которые получены в 2002-2003 гг. В статьях обсуждаются как теоретические вопросы, так и аспекты организации прикладных систем. В статье И.Б. Бурдонова, А.С. Косачева и В.В. Кулямина “Асинхронные автоматы: классификация и тестирование” предлагается теория конечных автоматов, которые отличаются от классических автоматов Мили тем, что смена состояния автомата происходит либо при приеме входного символа, либо при выдаче выходного символа, причем выбор перехода всегда недетерминирован. Вводится понятие асинхронного автомата, в котором допускается смена состояния при отсутствии входного символа. Предлагается классификация асинхронных автоматов, основанная на реализуемой автоматом словарной функции и эквивалентности автоматов с совпадающей словарной функцией. Статья А.В. Чернова “Об одном методе маскировки программ” посвящена обсуждению подхода к защите от возможности восстановления исходного кода программы по ее объектному коду – маскировке (obfuscation) программ. Предлагаемый метод маскировки основан, главным образом, на преобразовании графа потока управления исходной программы. При использовании данного метода не затрагиваются структуры данных исходной программы, но в замаскированную программу вносится большое число несущественных зависимостей по данным. В статье Г.В. Ключникова, А.С. Косачева, Н.В. Пакулина, А.К. Петренко и В.З. Шнитмана “Применение формальных методов для тестирования реализации IPv6” представлен опыт разработки тестового набора для реализации протокола IPv6. Использовался метод разработки тестовых наборов на основе формальных спецификаций UniTesK, разработанный и развиваемый в ИСП РАН. Объектом тестирования была реализация протокола IPv6, выполненная в Microsoft Research. Описываются организация тестового набора и результаты проекта. Исследованию современных подходов, методов и технологии реинжиниринга информационных систем посвящена статья К.В. Ахтырченко и Т.П. Сорокваша “Методы и технологии реинжиринга ИС”. На основе проведенного анализа и вводимой авторами классификации дается оценка текущего состояния данной области. Предметом статьи В.В. Кулямина и О.Л. Петренко “Место тестирования среди методов оценки качества ПО” является оценка места тестирования в современном процессе производства программного обеспечения. Исследуются понятия качества ПО и значимости тестирования при обеспечении и контроле качества. 5
Статья Д.Н. Волкова “Вопросы организации распределенного хранения данных в системах обработки изображений” содержит анализ методов организации хранения данных в современных фотограмметрических системах. Описывается разработанный автором подход к организации распределенного хранилища данных для систем обработки изображений. В статье Л.Г. Новака и С.Д. Кузнецова “Свойства схем данных XML” изучаются свойства XML-схем и методов преобразования схем над моделью данных XML. Предлагается методика, позволяющая упростить алгоритмы управления данными и метаданными XML за счет выделения простых подклассов из множества XML-схем. Статья Д.Р. Ширяева “Автоматическая генерация графических пользовательских интерфейсов доступа к интегрированным данным на основе диаграмм классов UML” посвящена описанию выработанной автором технологии автоматического построения графических пользовательских интерфейсов к системе интеграции данных на основе представления глобальной схемы в виде диаграммы классов UML. Используя одно и то же представление глобальной схемы, оказывается возможным генерировать разные виды GUI – формы и каталоги, а также своеобразный интерфейс с навигацией по классам. Следует отметить, что многие из работ, представленных в сборнике, поддерживались грантами РФФИ и других научных фондов. Член-корреспондент РАН
6
В.П. Иванников
О некоторых задачах анализа и трансформации программ* С.С. Гайсарян, А.В. Чернов, А.А. Белеванцев, О.Р. Маликов, Д.М. Мельник, А.В. Меньшикова Аннотация. В настоящей статье обсуждаются некоторые перспективные направления исследований, проводимые в отделе компиляторных технологий Института системного программирования РАН. Методы анализа и трансформации программ, ранее применявшиеся в основном в оптимизирующих компиляторах, в настоящее время находят применение при решении множества смежных задач, таких как обеспечение безопасности программ, генерация тестов для программ и т. д.
1. Введение В настоящей статье обсуждаются некоторые перспективные направления исследований, проводимые в отделе компиляторных технологий Института системного программирования РАН. Методы анализа и трансформации программ, ранее применявшиеся в основном в оптимизирующих компиляторах, в настоящее время находят применение при решении множества смежных задач, таких как обеспечение безопасности программ, генерация тестов для программ и т. д. В отделе ведётся работа и в традиционной области оптимизации программ. Упор делается на разработку новых методов анализа указателей в программах на языке Си. Также проводятся исследования так называемых «полустатических» (profile-based) методов оптимизации программ. Такие методы заключаются в использовании на стадии оптимизации кода информации, накопленной с предварительных её запусков. Данная работа посвящена рассмотрению трёх направлений. Во-первых, это так называемая маскировка программ, преследующая цель, полностью сохранив пользовательское поведение программы, изменить её текст так, что обратная инженерия или повторное использование ее фрагментов или программы целиком становится сложным. Во-вторых, это задачи автоматической оптимизации программы для работы на многопроцессорных системах с общей памятью путём разбиения её на нити. В-третьих, это задача автоматического выявления уязвимостей в программе. *
Работа поддержана РФФИ, грант 03-01-00880 7
Для поддержки работ по исследованию методов анализа и трансформации программ в отделе разработана интегрированная инструментальная среда (Integrated Research Environment, IRE), которая содержит большое количество различных алгоритмов анализа и трансформации программ и предоставляет удобный интерфейс пользователя. Данная работа имеет следующую структуру: в разделе 2 мы рассматриваем задачу автоматического разбиения программы на нити, в разделе 3 рассматриваются задачи маскировки программ, а в разделе 4 задача автоматического выявления уязвимостей. Далее в разделе 5 кратко описывается интегрированная среда IRE, её состав и внутреннее представление MIF, используемое всеми компонентами IRE. Наконец, в разделе 6 мы формулируем выводы данной работы и даём направления дальнейших исследований.
2. Разбиение программ на нити и повышение локальности В настоящее время широко распространены рабочие станции и персональные компьютеры, содержащие несколько центральных процессоров. Массовые многопроцессорные системы обычно содержат 2, 4 или 8 процессоров, работающих над общей памятью с одинаковым для всех процессоров временем доступа (SMP). Для максимального использования возможностей SMP-систем в вычислительно-интенсивных приложениях необходимо максимально использовать «легковесные» процессы (нити). В этом случае накладные расходы на коммуникацию минимизированы, так как все нити разделяют одно адресное пространство, а синхронизационные операции выполняются проще и быстрее, чем для обычных («тяжелых») процессов. Известно, что большинство программ при работе демонстрируют хорошую локальность, т.е. работают над близко расположенными в памяти данными, или выполняют одни и те же инструкции. На этом наблюдении основана работа процессорных кэшей. Для наиболее полного использования возможностей кэша необходимо улучшать локальность программы. В данном разделе мы представим новый алгоритм для разделения программы на нити, который улучшает локальность программы в целом. Полученные экспериментальные результаты показывают оправданность применения нового алгоритма для разбиения на нити программ без чёткой циклической структуры, которые не могут быть разбиты на нити традиционными методами. Основным выводом работы является то, что соображения локальности должны приниматься во внимание при разделении программы на нити для небольшого числа процессоров. Системы с разделяемой памятью наиболее удобны для программиста параллельных приложений. Более того, часть работы по распараллеливанию последовательного кода может быть выполнена компилятором. Существует много исследований по автоматическому распараллеливанию циклов и 8
рекурсивных процедур на таких системах. Некоторые разработки реализованы в промышленных компиляторах, например, IBM Visual Age C++, Intel C++ Compiler, SGI MIPSPro, REAPAR и других. В последнее время проводятся исследования по автоматическому распараллеливанию любого последовательного кода. Предложено несколько подходов, таких, как управление выполнением нитей (thread-level speculation) [6], коммутативный анализ, динамическое распределение задач на нити (dynamic task scheduling) [5], автоматическое разделение на нити на этапе компиляции. Часть предложенных алгоритмов проверена авторами на эмуляторах, часть реализована в существующих исследовательских компиляторах, например, в компиляторе SUIF Стенфордского университета [7]. Формализация понятия локальности проведена в [8]. Рассматривается два вида событий локальности: Событие временной локальности происходит при повторном доступе к ячейке памяти, уже имеющейся в кэше. Событие пространственной локальности происходит при доступе к ячейке памяти, расположенной в блоке, уже загруженном в кэш при обращении к какой-либо другой ячейке. Для увеличения количества событий локальности в последнее время предложено большое количество оптимизирующих преобразований программы. Основными методами являются: 1) Группировка инструкций, использующих одни и те же данные (locality grouping), для увеличения количества событий временной локальности. 2) Упаковка данных в памяти (data packing) для увеличения количества событий пространственной локальности. 3) Перестановка процедур, базовых блоков и т.п. Целью данной работы является исследование вопроса о том, как может быть проведено разделение программы на потоки для увеличения количества событий локальности программы в целом. Для этого предлагается использовать эвристический алгоритм разделения программы на нити, учитывающий в процессе разделения возникающие события локальности и динамически подстраивающий параметры эвристик.
2.1. Алгоритм разбиения программы на нити В настоящем разделе рассматривается построение промежуточного представления программы, над которым работает алгоритм, а также подробно описывается сам алгоритм разбиения программ на нити. Подробное описание алгоритма можно найти в [3]. Алгоритм состоит из трех частей: Построение ценовой модели, отражающей свойства локальности Разбиение программы на нити Дополнительные оптимизации 9
a = b = с = 1;
int fib(int n) { int a, b, c; a = b = с = 1; for (; n > 1; n--) { c = a + b; a = b; b = c; } return c; }
for (; n > 1; n--) { c = a + b;
a = b;
} b = c;
return c;
Рис. 1. Пример функции и ее DDG.
2.1.1. Граф зависимостей по данным При разделении программы на нити прежде всего нужно учитывать зависимости по данным. Поэтому естественно потребовать, чтобы промежуточное представление программы содержало легкодоступную информацию о зависимостях по данным между различными частями программы. В то же время необходимо максимально отразить сведения о «естественном» параллелизме программы, причем на разных уровнях – от отдельных инструкций, до более крупных программных блоков. Представлением, обладающим всеми необходимыми нам свойствами, является иерархический граф зависимостей по данным, используемый в [9] (data dependence graph, DDG). Узлом такого графа может являться: Простой оператор (сложение, умножение, сравнение, присваивание и т.д.) 10
Более сложный оператор (условный оператор, оператор цикла и т.д.) Граф зависимостей по данным следующего уровня, инкапсулирующий свойства соответствующего программного блока Дуги графа DDG представляют собой зависимости по данным между узлами. Более формально, пусть u и v – узлы DDG, причем в последовательной программе u предшествует v. Дуга (u, v) входит в граф тогда и только тогда, когда между u и v есть зависимость по данным одного из трех типов: «запись-чтение» (в узле v необходимы результаты вычислений узла u), «чтение-запись» (в узле v записывается переменная, значение которой считывается в u), «запись-запись» (оба узла записывают одну и ту же переменную). Наличие одной из указанных зависимостей по данным между узлами говорит о том, что при параллельном выполнении программы для получения результатов, совпадающих с последовательной версией, необходимо выполнить u раньше, чем v. Легко заметить, что граф зависимостей по данным является ориентированным ациклическим графом. Это объясняется тем, что циклы в DDG означают наличие циклических зависимостей по данным, возможных, в свою очередь, только в операторах цикла исходной программы. Но циклы, как и другие сложные операторы, раскрываются на более низком уровне иерархии, обеспечивая разрыв таких зависимостей по данным. Это свойство графа будет использоваться нами в дальнейшем. Пример функции и ее графа зависимостей по данным приведен на Рис. 1. DDG состоит из трех узлов: двух простых узлов и оператора цикла, раскрывающегося в DDG второго уровня. Граф зависимостей по данным строится для каждой функции программы. Алгоритм построения состоит из следующих этапов: Построение графа потока управления программы. Выбор программных блоков, которые будут узлами текущего уровня иерархии DDG. Нахождение зависимостей по данным между этими узлами с помощью алгоритма достигающих определений. Если необходимо, продвинуться на следующий уровень иерархии и достроить граф. Для того, чтобы отразить на графе побочные эффекты работы функции, в графе вводится специальный узел EXIT. Все узлы, генерирующие побочные эффекты (например, осуществляющие запись в глобальную переменную), связаны дугой с узлом EXIT. 11
Все этапы алгоритма разделения на нити, описанные ниже, работают с представлением программы в виде графа зависимостей по данным.
2.1.2. Ценовая модель Нашей целью является построение разбиения программы на нити, максимально использующего возникающие события локальности. Чтобы иметь возможность судить о степени оптимальности того или иного разбиения, необходимо ввести некоторую ценовую модель. Так как мы оптимизируем время выполнения программы, то естественно ввести веса узлов графа зависимости по данным, равные времени выполнения узла в последовательной программе. Время выполнения узла может быть найдено с помощью профилирования программы. Для этого необходимо инструментировать исходный код программы, вставляя вызовы функций из библиотеки поддержки, вычисляющих время выполнения инструкций, и выполнить программу на нескольких наборах типичных входных данных. Для получения более точных результатов можно воспользоваться высокоточными аппаратными счетчиками, имеющимися на большинстве современных архитектур (например, инструкцией RDTSC для Pentium III и выше). Эта оценка времени выполнения точно показывает реальное время выполнения программы, но затрудняет эмуляцию кэша на этапе разделения на нити, так как сложно определить, насколько уменьшится время выполнения узла при попадании в кэш (возможно, при профилировании это попадание уже произошло). Ценовая модель должна также отражать события локальности, происходящие во время выполнения программы. Статических весов для узлов DDG для этой цели недостаточно. Необходима эмуляция кэша в процессе разделения на нити и соответствующая корректировка времени выполнения узла.
2.1.3. Разбиение на нити На этом шаге производится собственно разбиение графа зависимостей по данным на нити. Количество нитей является параметром алгоритма. Так как целью разбиения является получение выигрыша по времени, возникающего изза увеличения количества событий локальности в каждой нити, то необходимо привязать каждую нить к одному конкретному процессору или, точнее, к конкретному кэшу. Поэтому количество нитей, на которые производится разбиение, обычно равно количеству процессоров в системе. Алгоритм разбиения состоит в итерировании списка узлов графа, еще не назначенных конкретной нити, и определения нити для какого-либо из узлов (группы таких алгоритмов обычно называются list scheduling). На каждом шаге такой алгоритм делает локально оптимальный выбор. Это значит, что при выборе очередного узла из списка делается попытка присвоить его каждой из имеющихся нитей, после чего выбирается лучшая.
12
Для того, чтобы иметь возможность оценивать варианты присвоения узла нити, необходимо ввести некоторую оценочную функцию. В нашем случае такая функция содержит время выполнения нити, а также среднеквадратичное отклонение времен выполнения всех нитей. Это следует из того соображения, что в оптимальном разбиении времена выполнения нитей должны быть достаточно близки друг к другу. Возможно включение и других параметров. При включении узла в какую-либо нить необходимо провести пересчет времени выполнения этой нити. Алгоритм пересчета состоит из следующих шагов:
Узел i:
a = 2;
c = a + b
синхронизация
Узел j:
a = 2
Учет времени, необходимого на синхронизацию с другими нитями, если она требуется. Учет возникающих событий локальности.
Рассмотрим более подробно каждый из этих шагов. 2.1.3.1. Учет времени на синхронизацию Обрабатываемый на текущем этапе узел может зависеть по данным от некоторых других. В этом случае необходимо дождаться выполнения каждой нити, которые содержит такие узлы. Порядок обхода узлов в списке должен быть таков, чтобы гарантировалось, что все такие узлы уже были распределены на нити. Для этого можно обходить узлы в естественном порядке, то есть так, как они расположены в последовательной программе, либо выполнить тополо-гическую сортировку графа зависимостей по данным. Еще раз подчеркнем, что иерархичность графа обеспечивает то, что он является ациклическим. Таким образом, к моменту обработки некоторого узла все узлы, от которых он зависит по данным, уже распределены на нити. Если какие-либо из таких узлов находятся в других нитях, то перед выполнением текущего узла необходимо провести синхронизацию со всеми такими нитями. Для того, чтобы осуществить такую синхронизацию, нужно завести по одной общей переменной для каждой нити. Присваивание значения i такой переменной для некоторой нити j означает, что эта нить выполнила узел i. Нить, ждущая результатов вычисления узла i, должна ждать, пока соответствующая общая переменная не примет нужного значения. Пример такой синхронизации показан на Рис. 2. Времена выполнения каждой из нитей, проводящих синхронизацию, должны быть увеличены соответствующим образом. Нить, пишущая в общую переменную о результатах выполнения узла, дополнительно работает время t1. Нить, ждущая данных от нескольких узлов, ожидает последний из выполняющихся узлов, после чего тратит время t2. Эти времена являются параметрами алгоритма.
while (syn_1 != 1);
Нить 1:
c = a + b; Нить 2:
syn_1 = 1;
Рис. 2. Пример синзронизации между нитями. 2.1.3.2. Учет возникающих событий локальности Для учета событий локальности для каждой нити необходимо эмулировать кэш процессора, на котором она выполняется. При распределении текущего узла на какую-либо нить необходимо проверить все переменные, которые читаются либо пишутся узлом, на попадание в кэш. Если попадание произошло, то время выполнения узла должно быть уменьшено на интервал времени t3, также являющийся параметром алгоритма. a
b
c
Линия кэша a = 2;
//35 тактов
b = 4;
//35 тактов
промахи
a = 2;
//35 тактов
b = 4;
//35 – 18 = //17 тактов
c += b; //52 такта c += b; //52 – 18 = //34 такта Всего: 122 такта “пространственное” попадание
Рис. 3. Пример эмулирования кэша 13
Размещение данных в
14
Всего: 86 тактов
“временное” попадание
Для учета событий как временной, так и пространственной локальности необходимо моделирование линий кэша, т.е. помещение в кэш не одной переменной, а некоторого блока памяти, окружающего нужную переменную. Моделирование различных типов кэшей приведет к разным результатам при разделении на нити. Пример моделирования событий локальности изображен на Рис. 3.
2.2. Экспериментальные результаты Мы применили нашу реализацию алгоритма к тестовой функции, решающей алгебраическое уравнение четвертой степени x 4 ax 3 bx 2 cx d 0 . Функция не содержит циклов и не может быть распараллелена традиционными способами. Полученная многопоточная версия функции была реализована с помощью библиотеки pthread под операционной системой Linux. Экспериментальные запуски были проведены на четырехпроцессорном Intel Itanium, на которых установлена ОС RedHat Linux 7; использовались компиляторы GCC 3.3.1 и ICC 8.00b. Программа запускалась 100 раз, время ее выполнения измерялось с помощью высокоточных аппаратных счетчиков. Вычислялось среднее значение времени выполнения и среднеквадратичное отклонение . Все значения времени выполнения, не укладывающиеся в промежуток [ 2 , 2 ] , удалялись из выборки, после чего среднее значение пересчитывалось. Эта величина использовалась для подсчета ускорения. Результаты эксперимента приведены на Рис. 4. 2.4 2.2 2
Ускорение
1.8 1.6 1.4 1.2 1 0.8 1
2
3
4
gcc
1
1.71231681
1.648244185
1.449141278
icc
1
1.872147496
2.012020584
1.936518694
3. Маскирующие преобразования программ Другим направлением, развиваемым в рамках IRE является исследование маскировки (obfuscation) программ. Мы рассматриваем проблему защиты программ от обратной инженерии, проводимой с целью модификации и/или включения фрагментов защищаемой программы во вновь разрабатываемый программный код. Защита в данном случае состоит в том, чтобы затруднить понимание деталей реализации компонент большой программной системы, сделав его настолько дорогим, чтобы дешевле было разработать оригинальное программное обеспечение. Одним из способов такой защиты является маскировка программ, заключающаяся в применении к исходному тексту программы цепочки маскирующих преобразований, то есть преобразований, сохраняющих реализуемую программой функцию (являющихся функционально эквивалентными), но затрудняющих понимание этой функции. Целью нашего исследования является новый метод маскировки программ, удовлетворяющего следующим требованиям: Исходная и замаскированная программа записаны на языке Си. В методе применяются цепочки маскирующих преобразований, элементы которых берутся из некоторого заранее зафиксированного множества параметризованных маскирующих преобра-зований. Все цепочки таких преобразований порождаются автоматически поддерживающими метод инструментальными средствами и являются допустимыми по своим характеристикам, то есть увеличивают размер маскируемой программы и/или уменьшают скорость её работы не более чем в фиксированное количество раз. Метод маскировки устойчив относительно современных методов статического и полустатического анализа программ, развитых для языка Си. Предложена новая методология анализа маскирующих преобразований, которая позволяет давать качественную и количественную характеристику преобразований. Количественная характеристика преобразований позволяет дать их классификацию и выявить среди них наиболее подходящие для использования при маскировке программ. Основываясь на проведённом исследовании нами предложен новый метод маскировки программ, который удовлетворяет всем целям, сформулированным выше.
3.1. Методология анализа маскирующих преобразований программ
потоки
Рис. 4. Ускорение, достигнутое на Itanium
15
Для оценки действия маскирующих преобразований на программу мы используем несколько показателей сложности кода программ. Традиционно, подобного рода показатели называются «метрики», в дальнейшем мы будем придерживаться этого термина и в нашей работе. Метрики сложности кода программы ставят в соответствие любой программе некоторое число, которое 16
тем больше, чем «сложнее» программа. Простейшая метрика LC размера процедуры равна количеству инструкций промежуточного представления MIF в записи процедуры. Метрика YC сложности циклической структуры равна мощности транзитивного замыкания отношения достижимости в графе потока управления процедуры. Метрика DC сложности потока данных определяется как количество дуг в графе зависимостей по данным, строящемся по результатам анализа достигающих определений программы. Метрика UC количества недостижимого кода определяется как количество инструкций в программе, которые не выполняются ни при каких наборах входных данных. Известно, что точное вычисление метрик DC и UC является алгоритмически неразрешимой задачей. Через O(p,e) мы обозначим применение метода маскировки O к программе p. e – это параметр, который позволяет выбрать единственную программу p' = O(p,e) из множества функционально эквивалентных замаскированных программ O(p). В частности, параметр e может быть случайным числом. Множество изменения параметра e обозначим через E. Тогда LC(p) – значение метрики LC до маскировки, а LC(O(p,e)) – после маскировки. Композитная метрика цены TC преобразования O(p,e) вычисляется по метрикам LC и UC следующим образом: LC (O( p, e)) LC (O( p, e)) UC (O( p, e)) . TC ( p) LC ( p) LC ( p) UC ( p) Для конечного множества D программ цена маскирующего преобразования определяется как TC ( D) max TC ( p) . pD ,eE
Метод маскировки называется допустимым для множества D, если TC ( D) TC MAX , где константа TC MAX устанавливается директивно, исходя из эксплуатационных требований к замаскированной программе. Композитная метрика MC усложнения программы вычисляется по метрикам YC и DC следующим образом: YC (O( p )) DC (O( p )) MC ( p) . YC ( p) DC ( p) Для конечного множества D программ усложнение определяется как MC ( D) min MC ( p) . Чем больше метрика усложнения программы, тем pD ,eE
сложнее для понимания становится замаскированная программа в силу увеличения числа информационных и управляющих связей. Для оценки сложности самого маскирующего преобразования вводится оценка OC сложности маскирующего преобразования, которая определяется как требуемая для выполнения данного маскирующего преобразования глубина анализа программы согласно таблице 1.
17
Значение OC 0 1 2 3 4 5 6
Требуемая глубина анализа Лексический анализ Синтаксический анализ Семантический анализ Анализ потока управления Консервативный анализ потока данных Полустатический анализ Точный анализ потока данных
Таблица 1. Шкала оценки сложности маскирующих преобразований Для оценки степени различия текстов программ вводится расстояние ( p1 , p 2 ) между текстами программ p1 и p 2 , которое используется для оценки устойчивости маскирующего преобразования. Введём расстояние C между графами потока управления двух процедур, равное минимальному количеству операций удаления и добавления рёбер и дуг, переводящих один граф в граф, изоморфный другому. Аналогично введём расстояние D между графами зависимостей по данным двух процедур. Обозначим через CD ( f1 , f 2 ) сумму C ( f1 , f 2 ) D ( f1 , f 2 ) . Тогда расстояние ( p1 , p 2 ) вычисляется по формуле
f 2 ) .Здесь f1M 1 f 2M 2 минимум берётся по всевозможным множествам M, состоящим из пар ( f1 , f 2 ) , где f1 – процедура из программы p1 , f 2 – процедура из программы p 2 . Все процедуры f1 и f 2 встречаются в M не более одного раза. Через M 1 обозначено множество процедур программы p1 , отсутствующих в M, а через M 2 – множество процедур программы p 2 , отсутствующих в M. E – это пустой граф.
( p1 , p 2 ) min
CD ( f 1 , M ( f1 , f 2 )M
f2 )
CD ( f 1 , E )
CD ( E ,
Такие подготовительные определения позволяют нам определить понятие устойчивости метода маскировки программ по отношению к заданному набору алгоритмов их анализа и основанным на них методам демаскировки программ следующим образом. Пусть – это множество маскирующих преобразований и необходимых для их выполнения алгоритмов анализа программ. Тогда метод маскировки – это цепочка O . Все алгоритмы {oi1 oim } анализа, необходимые для выполнения маскирующего преобразования oi , находятся в цепочке O перед oi . Пусть { A1 , Am ) – заданный набор демаскирующих преобразований и необходимых для их выполнения алгоритмов анализа программ. Метод демас18
кировки – это цепочка A * . Все алгоритмы {a j1 a jn } анализа,
3.2. Анализ маскирующих преобразований
необходимые для выполнения маскирующего преобразования a j , находятся в
Все маскирующие преобразования делятся на текстуальные преобразования, преобразования управляющей структуры и преобразования структур данных. Преобразования управляющей структуры в свою очередь делятся на две группы: маскирующие преобразования реструктуризации всей программы и маскирующие преобразования над одной процедурой. Преобразования структур данных в рамках данной работы не рассматривались. В группе текстуальных маскирующих преобразований рассматриваются преобразования удаления комментариев, переформатирования текста программы и изменения идентификаторов в тексте программы. В группе маскирующих преобразований управляющей структуры, воздействующих на программу в целом, рассматриваются преобразования открытой вставки процедур, выделения процедур, переплетения процедур, клонирования процедур, устранения библиотечных вызовов. В группе маскирующих преобразований маскировки над одной процедурой рассмотрены преобразования внесения непрозрачных предикатов и переменных, внесения недостижимого кода, внесения мёртвого кода, внесения дублирующего кода, внесения тождеств, преобразования сводимого графа потока управления к несводимому, клонирования базовых блоков, развёртки циклов, разложения циклов, переплетения циклов, диспетчеризации потока управления, локализации переменных, расширения области действия переменных, повторного использования переменных, повышения косвенности.
цепочке A перед a j . Длину | A | строки A назовём сложностью метода демаскировки. Метод маскировки O называется устойчивым для множества программ D по отношению к множеству демаскирующих преобразований с порогом устойчивости , если выполняются следующие условия: Метод маскировки O является допустимым, то есть TC ( D) TC MAX . Для любой программы p , полученной из p, любой метод демаскировки A сложности не более C получает программу
p
отстоящую от p более чем на , то есть: p D, e E , p O ( p, e), A * , | A | C , p A( p ) : ( p , p ) . Константа называется порогом устойчивости. Параметры C и подбираются эмпирически. Параметр C – это оценка вычислительных ресурсов используемых для атаки на замаскированную программу. Чем больше C, тем более сложные методы демаскировки могут применяться для атаки. Параметр зависит от ценности защищаемой программы и уровня экспертизы, ожидаемого при атаке на замаскированную программу. Чем больше ценность маскируемой программы и чем выше ожидаемый уровень подготовки лиц, выполняющих атаку на замаскированную программу, тем больше должен быть порог устойчивости . Наш анализ методов маскировки программ исходит из предположения, что множество всех возможных алгоритмов анализа и преобразования программ, которые могут использоваться для демаскировки программ, фиксировано. Для нашего анализа мы выбрали представительное множество методов, составленное следующим образом. Большинство рассматриваемых демаскирующих преобразований являются оптимизирующими преобразованиями, используемыми в оптимизирующих компиляторах. К таким преобразованиям относятся, например, устранение общих подвыражений и устранение мёртвого кода. Кроме них описываются алгоритмы полустатического анализа такие, как построение и анализ покрытия дуг и базовых блоков, и основанные на них разработанные в рамках данной работы демаскирующие преобразования. В рамках нашего исследования нам удалось получить качественную и количественную характеристику опубликованных другими исследователями и разработчиками систем маскировки маскирующих преобразований. Был проведён сравнительный анализ их цены TC, усложнения маскируемой программы MC и оценки сложности OC. На примере программы, вычисляющей функцию Фибоначчи, проводится ранжирование маскирующих преобразо-ваний по соотношению усложнение/цена. 19
Int fib(int n) { int a, b, c; a = 1; b = 1; if (n <= 1) return 1; for (; n > 1; n--) { c = a + b; a = b; b = c; } return c; }
(a) исходная программа
int fib(int n) { int a, b, c, i; long long t; a = 1; b = 1; if (n <= 1) return 1; while (1) { t = n * n % 65537; for (i = 0; i < 15; i++) t = t * t % 65537; if (n * t <= 1) break; c = a + b; a = b; b = c; n--; } return c; } (b) замаскированная программа
Рис. 5. Пример применения маскирующего преобразования внесения тождеств 20
На Рис. 5 показан пример применения маскирующего преобразования внесения тождеств к программе, вычисляющей функцию Фибоначчи. Преобразование основано на малой теореме Ферма ( a p 1 1 (mod p) для любого целого a, такого, что a mod p 0 , и простого числа p). В таблице 2 приведена цена применения маскирующего преобразования и полученное усложнение программы. Для этого примера цена равна 3.83, а усложнение программы – 4.85. Расстояние между исходной и замаскированной программой равно 21. Исх. процедура fib Замаскированная fib
LC 12 23
UC 0 0
YC 0.1111 0.3086
DC 14 29
Таблица 2. Оценка влияния маскирующего преобразования внесения тождеств Другое маскирующее преобразование – введение непрозрачных предикатов – является ключевым для повышения устойчивости других маскирующих преобразований, например, внесения недостижимого кода. Непрозрачным предикатом называется предикат, всегда принимающий единственное значение true или false. При маскировке программы предикат строится таким образом, что его значение известно, но установить по тексту замаскированной программы, является ли некоторый предикат непрозрачным, трудно. В работе рассматриваются методы построения непрозрачных предикатов, использующие динамические структуры данных и булевские формулы. На основании определения устойчивости маскирующих преобразований, данного выше, становится возможным провести анализ всех опубликованных маскирующих преобразований для выявления их устойчивости по отношению к нашему множеству демаскирующих преобразований и алгоритмов анализа. Мы можем ввести количественную классификацию маскирующих преобразований и выявить наиболее устойчивые маскирующие преобразования. Для этого вводятся – эвристическая оценка CL сложности анализа, которая устанавливает глубину анализа замаскированной программы, необходимого для выполнения демаскирующего преобразования, и эвристическая оценка SL степени поддержки демаскировки, устанавливающая необходимую степень участия человека в процессе демаскировки. Для оценки CL используется шкала, приведённая в таблице 1. Для оценки SL используется шкала: «автоматический анализ» (0 баллов), «полуавтоматический анализ» (1 балл), «ручной анализ с развитой инструментальной поддержкой» (2 балла), «только ручной анализ» (3 балла). Итоговая оценка DL трудоёмкости анализа равна DL CL SL . В нашей работе показано, что для каждого маскирующего преобразования можно предложить автоматический или полуавтоматический метод демаскировки, позволяющий приблизить демаскированную программу p к исходной 21
программе p. При использовании полустатических алгоритмов анализа программ мы исходим из предположения, что для замаскированной программы существует достаточное количество тестовых наборов, обеспечивающее требуемый уровень доверия. Таким образом можно получить количественную классификацию маскирующих преобразований. Для каждого маскирующего преобразования приводится оценка сложности маскировки и оценка трудоёмкости демаскировки. Значение, получаемое как разность оценки трудоёмкости демаскировки и оценки сложности маскировки, позволяет оценить насколько демаскировка данного маскирующего преобразования сложнее, чем маскировка. Исходя из этого определяются маскирующие преобразования, применение которых неоправдано, например, переформатирование программы, разложение циклов, локализация переменных; методы маскировки, которые следует применять только в комплексе с другими методами, например, изменение идентификаторов, внесение дублирующего кода и методы маскировки, применение которых наиболее оправдано, например, внесение тождеств, переплетение процедур, построение диспетчера, повышение косвенности. Сравнение двух маскирующих преобразований приведено в таблице 3. Через D обозначена разность OC DL , через 1 обозначено расстояние между текстами замаскированной и исходной программ fib, а через 2 – расстояние между текстами демаскированной и исходной программ. Из таблицы следует, что маскирующее преобразование построения диспетчера предпочтительнее, так как, при равных с методом внесения тождеств трудозатратах на демаскировку, обеспечивает лучшее соотношение усложнения программы к цене преобразования. Преобразование
OC
TC
MC
1
CL
SL
DL
2 D
Внесение тождеств Построение диспетчера
2
3.83
4.85
21
4–5
2
7
0
5
1.27
2
3.83
6.14
39
5
2
7
2
5
1.60
MC ( fib) TC ( fib)
Таблица 3. Сравнение методов маскировки
3.3. Новый метод маскировки программ Новый метод маскировки программ мы далее обозначим аббревиатурой «ММ». Его более подробное описание можно найти в [2]. Метод ММ применяется к функциям маскируемой программы по отдельности, при этом структура маскируемой программы в целом не изменяется. Для изменения структуры маскируемой программы могут применяться стандартные методы открытой вставки и выноса функции, которые, однако, не являются частью предлагаемого метода маскировки. 22
При маскировке каждой функции ММ использует, наряду с локальными несущественными переменными, глобальные несущественные переменные, которые формируют глобальный несущественный контекст. В маскируемую программу вносятся несущественные зависимости по данным между существенным и несущественным контекстом функции. Наличие глобального несущественного контекста, совместно используемого всеми замаскированными функциями, приводит к появлению в замаскированной программе зависимостей по данным между всеми функциями и глобальными переменными. Метод ММ состоит главным образом из преобразований графа потока управления. В результате граф потока управления замаскированной программы значительно отличается от графа потока управления исходной программы. Метод не затрагивает структур данных исходной программы, но вносит в за-маскированную программу большое количество несущественных зависимостей по данным. В результате, замаскированная программа значительно сложнее исходной как по управлению, так и по данным. Мы предполагаем, что перед маскировкой были выполнены все стандартные шаги анализа программы: лексический, синтаксический, семантический, анализ потока управления (построение графа потока управления и деревьев доминирования и постдоминирования) и консервативный глобальный анализ потоков данных (достигающие определения и доступные выражения с учётом возможных алиасов). Дополнительно может быть выполнено профилирование дуг, результаты которого учитываются в преобразованиях клонирования дуг и развёртки циклов. Общая идея метода может быть охарактеризована следующим образом. Во-первых, значительно увеличить сложность графа потока управления, но так, чтобы все дуги графа потока управления, внесённые при маскировке, проходились при выполнении программы. Это позволяет преодолеть основную слабость «непрозрачных» предикатов: насколько бы не были они сложны для статического анализа программы, полустатический анализ позволяет выявить такие предикаты (точнее, порождённые ими несущественные дуги графа потока управления) с большой долей уверенности. Во-вторых, увеличить сложность потоков данных маскируемой функции, «наложив» на неё программу, которая заведомо не влияет на окружение маскируемой функции и, как следствие, не изменяет работы программы. «Холостая» функция строится как из фрагментов маски-руемой функции, семантические свойства которых заведомо известны, так и из фрагментов, взятых из библиотеки маскирующего трансля-тора. Чтобы затруднить задачу выявления холостой части замаскиро-ванной функции используются как языковые конструкции, трудно поддающиеся анализу (указатели), так и математические тождества. 23
Метод маскировки можно разбить на несколько этапов: 1. Увеличение размера графа потока управления функции без нарушения его структурности. На этом этапе выполняются различные преобразования перестройки циклов, которые изменяют структуру циклов в теле функции, клонирование базовых блоков. Цель этого этапа — существенно увеличить размер графа потока управления функции. 2. Разрушение структурности графа потока управления функции. На этом этапе в граф потока управления вносится значительное количество новых дуг. При этом существовавшие базовые блоки могут оказаться разбитыми на несколько меньших базовых блоков. В графе потока управления могут появиться пока пустые базовые блоки. Цель этого этапа — подготовить место, на которое в дальнейшем будет внесён несущественный код. 3. Генерация несущественного кода. На этом этапе граф потока управления заполняется инструкциями, которые не оказывают никакого влияния на результат, вырабатываемый маскируемой программой. Несущественная, «холостая» часть пока никак не соприкасается с основной, функциональной частью программы. 4. «Зацепление» холостой и основной программы. Для этого используются как трудноанализируемые свойства программ (например, указатели), так и разнообразные математические тождества и неравенства. В качестве примера применения предложенного метода маскировки мы выбрали небольшую программу, которая решает задачу о 8 ферзях. Для маскировки мы выберем основную функцию queens этой программы. Метрика LC YC UC DC
queens 49 0.595 0 82
MM(queens) 711 0.8119 0 8964
CM(queens) 4171 0.2402 0 143807
Таблица 4. Изменение метрик для замаскированной процедуры queens Преобразование MM(queens) CM(queens)
OC 4 ?
TC 29.02 170.24
MC 110.68 1754.14
MC/TC 3.81 10.30
CL 5 5
SL 2 2
DL 7 7
D 3 ?
Таблица 5. Сравнение методов маскировки для функции queens В таблице 4 в столбце queens приведены базовые метрики сложности кода для исходной процедуры queens; в столбце MM(queens) – для процедуры, замаскированной с помощью предложенного метода маскировки; в столбце CM(queens) – для процедуры, замаскированной с помощью коммерческого маскировщика рассмотренного выше. 24
В таблице 5 приведены метрики цены применения маскирующего преобразования, усложнения программы требуемой глубины анализа для предложенного метода маскировки MM и для коммерческого маскировщика CM. Для коммерческого маскировщика сложность алгоритма маскировки неизвестна, поэтому в соответствующих ячейках таблицы стоит знак «?». Из таблицы видно, что новый метод маскировки MM существенно дешевле, чем реализованный в коммерческом маскировщике.
4. Автоматическое выявление уязвимостей защиты программ Бурное развитие современных телекоммуникационных технологий позволило решить задачу доступа к информационным и вычислительным ресурсам вне зависимости от географического расположения поставщика и потребителя ресурсов. Сеть Интернет связывает миллионы компьютеров по всей планете. С другой стороны, именно общедоступность информационных ресурсов подняла на новый уровень требования к безопасности программного обеспечения. Необходимым условием обеспечения безопасности ПО является его корректная работа на всех возможных входных данных и всех других видах внешних по отношению к программе воздействий. Следует заметить, что данное требование сильнее, чем требование отсутствия в программе ошибок, если под ошибками понимать несоответствие действительного поведения программы специфицированному на указанном в спецификации множестве входных данных программы. Спецификация может определять поведение программы лишь на подмножестве множества всех возможных входных данных. Например, для программ, получающих данные от пользователя или из других неконтролируемых программой внешних источников реальное множество входных данных представляет собой просто множество всех возможных битовых строк вне зависимости от спецификации входных данных программы. Если программа является частью многопроцессной системы и взаимодействует с другими процессами и окружением, реальное множество входных данных зависит и от всех возможных темпоральных вариантов взаимодействия процессов, а не только от специфицированных. Когда требование корректной работы программы на всех возможных входных данных нарушается становится возможным появление так называемых уязвимостей защиты (security vulnerability). Уязвимости защиты могут приводить к тому, что одна программа может использоваться для преодоления ограничений защиты всей системы, частью которой является данная программа, в целом. В особенности это относится к программам, обслуживающим различные общедоступные сервисы сети Интернет и к программам, работающим в привилегированном режиме. Рассмотрим, например, последний случай “взлома” Интернет-сервера проекта Debian Linux. Программа-сервер синхронизации файлов по сети rsync 25
содержала уязвимость в защите, которая позволяла, подключившись к серверу rsync и подав на ему на вход специально подготовленные входные данные, принудить процессор исполнить не исполняемый код программы rsync, а исполняемый код, переданный в этих входных данных. Сама по себе программа rsync не является привилегированной, но таким образом был получен доступ к компьютеру с возможностью запускать произвольные программы (доступ shell account). Естественно, такой способ получения доступа к компьютеру обходит все нормальные средства аутентификации, такие как ввод регистрационного имени и пароля, ввод однократного ключа и т. д. Получив возможность выполнения произвольных программ на сервере, злоумышленник использовал другую уязвимость в защите, теперь непосредственно ядра Linux, которая была связана с недостаточной проверкой параметра, передаваемого системному вызову sbrk. Передавая этому системному вызову отрицательные значения можно было добиться открытия доступа к критически важным страницам памяти, после чего можно было добиться выполнения произвольной программы уже с правами суперпользователя (root). Обычно такая программа – это интерпретатор командной строки /bin/sh. Таким образом, неизвестный злоумышленник в два этапа получил полный контроль над машиной, на которой он раньше даже не имел shell account. Уязвимости в защите, которые могут быть использованы просто подключением к уязвимой программе без какой-либо авторизации называются удалённо-эксплуатируемыми (remotely exploitable). Уязвимости в защите, которые требуют наличия локального доступа типа shell account обычно называются локально-эксплуатируемыми (locally-exploitable). Наиболее опасен первый тип уязвимостей, так как он позволяет вообще произвольному (неизвестному) лицу получить возможность запуска произвольных программ. Следует заметить, что данный пример отнюдь не единичен. Уязвимости разной степени опасности обнаруживаются в программах систематически несколько раз в месяц. В связи со столь неблагоприятной ситуацией, в США была разработана процедура сертификации программного обеспечения (Common Criteria). ПО, не прошедшее сертификацию по этой процедуре не может работать на критически важных серверах государственного значения. Это показывает, почему ведущие производители телекоммуникационного оборудования и программного обеспечения привлекают большие ресурсы для аудита существующего массива программного обеспечения для выявления и устранения в них уязвимостей защиты. К сожалению, в настоящий момент процесс аудита программного обеспечения с целью выявления уязвимостей защиты совершенно неудовлетворительно поддерживается инструментальными средствами. Как будет показано далее, основная проблема существующих инструментальных средств – высокий процент ложных срабатываний, когда фрагмент программы, не содержащий ошибок, приводящих к уязвимостям защиты, отмечается как опасный. Высокий процент ложных срабатываний требует большого количества ручного труда для отсеивания ложных сообщений от сообщений, действительно выявляющих ошибки. 26
В настоящее время в рамках контракта с Nortel Networks в отделе компиляторных технологий ведётся разработка инструментального средства для автоматического выявления уязвимостей защиты некоторых типов. Дальнейшие разделы настоящей работы посвящены описанию разрабатываемого прототипа инструментального средства.
4.1. Виды уязвимостей защиты В настоящее время сложилась некоторая классификация уязвимостей защиты в зависимости от типа программных ошибок, которые могут приводить к появлению уязвимости в программе. В рамках данной работы мы рассмотрим лишь некоторые виды уязвимостей. Переполнение буфера (buffer overflow). Данная уязвимость возникает как следствие отсутствия контроля или недостаточного контроля за выходом за пределы массива в памяти. Языки Си/Си++, чаще всего используемые для разработки программного обеспечения системного уровня, не реализуют автоматического контроля выхода за пределы массива во время выполнения программы. Это самый старый из известных типов уязвимостей (знаменитый червь Морриса использовал, среди прочих, уязвимости переполнения буфера в программах sendmail и fingerd), уязвимости такого типа наиболее просто использовать. По месту расположения буфера в памяти процесса различают переполнения буфера в стеке (stack buffer overflow), куче (heap buffer overflow) и области статических данных (bss buffer overflow). Все три вида переполнения буфера могут с успехом быть использованы для выполнения произвольного кода уязвимым процессом. Так, упомянутая выше программа rsync содержала уязвимость буфера в куче. Рассмотрим для примера более детально уязвимость переполнения буфера в стеке как наиболее простую на примере следующей простой программы: #include <stdio.h> int main(int argc, char **argv) { char buf[80]; gets(buf); printf(“%s”, buf); return 0; } Предположим, что стек процесса растёт в направлении уменьшения адресов памяти. В таком случае непосредственно перед выполнением функции gets стек будет иметь следующую структуру:
27
SP+96 SP+88 SP+84 SP+80 SP+80 SP
Аргументы командной строки, переменные окружения и т. д. Аргументы функции main (argc, argv) Адрес возврата из main в инициализационный код Адрес предыдущего стекового фрейма Сохранённые регистры (если есть), локальные переменные (если есть) Буфер (char buf[80])
Как известно, функция gets не позволяет ограничивать длину вводимой со стандартного потока ввода строки. Вся введённая строка до символа '\n', кроме него самого, будет записана в память по адресам, начинающимся с адреса массива buf. При этом, если длина введённой строки превысит 80 символов, то первые 80 символов строки будут размещены в памяти, отведённой под массив buf, а последующие символы будут записаны в ячейки памяти, непосредственно следующие за buf. То есть, таким образом будут испорчены сначала сохранённые регистры и локальные переменные, затем адрес предыдущего стекового фрейма, затем адрес возврата из функции main и т. д. В момент, когда функция main будет завершаться с помощью оператора return, процессор выполнит переход по адресу, хранящемуся в стеке, но этот адрес испорчен в результате выполнения функции gets, поэтому переход произойдёт совсем в другое место, чем стандартный код завершения процесса. Теперь, чтобы проэксплуатировать такое переполнение буфера, необходимо подать на вход программе специальным образом подготовленную строку, которая будет содержать небольшую программу, выполняющую нужные злоумышленнику действия (это так называемый shellcode, который в простейшем случае просто выполняет вызов стандартного командного интерпретатора /bin/sh). Кроме того, нужно так подобрать размер подаваемых на вход данных, чтобы при их чтении на место, где размещается адрес возврата из main, попал адрес начала shellcode. В результате в момент завершения работы функции main произойдёт переход на начало фрагмента shellcode, в результате чего будет запущен интерпретатор командной строки. Интерпретатор командной строки будет иметь полномочия пользователя, под которым работал уязвимый процесс, кроме того, стандартные средства аутентификации оказываются обойденными. Для предотвращения выполнения произвольного кода в случае использования переполнения буфера используются такие приёмы, как запрет выполнения кода в стеке, отображение стандартных библиотек в адресное пространство процесса со случайных адресов, динамический контроль барьерных данных и так далее. Но не один из этих приёмов не может гарантировать предотвращения использования уязвимости переполнения буфера в стеке, поэтому ошибки приводящие к переполнению буфера должны быть устранены непосредственно в исходном коде. Ошибки форматных строк (format string vulnerability). Этот тип уязвимостей защиты возникает из-за недостаточного контроля параметров при использовании функций форматного ввода-вывода printf, fprintf, scanf, и т. д. стандартной библиотеки языка Си. Эти функции принимают в качестве одного 28
из параметров символьную строку, задающую формат ввода или вывода последующих аргументов функции. Если пользователь программы может управлять форматной строкой (например, форматная строка вводится в программу пользователем), он может сформировать её таким образом, что по некоторым ячейкам памяти (адресами которых он может управлять) окажутся записанными указанные пользователем значения, что открывает возможности, например, для переписывания адреса возврата функции и исполнения кода, заданного пользователем. Уязвимость форматных строк возникает, по сути, из-за того, что широко используемые в программах на Си функции, интерпретируют достаточно мощный язык, неограниченное использование возможностей которого приводит к нежелательным последствиям. Как следствие, в безопасной программе не должно быть форматных строк, содержимое которых прямо или косвенно зависит от внешних по отношению к программе данных. Если же такое невозможно, при конструировании форматной строки она должна быть тщательно проверена. В простейшем случае из пользовательского ввода должны “отфильтровываться” опасные символы “%” и “$”. Уязвимости “испорченного ввода” (tainted input vulnerability). Это широкий класс уязвимостей защиты, в качестве подкласса включающий в себя уязвимости форматных строк. Уязвимости испорченного ввода могут возникать в случаях, когда вводимые пользователем данные без достаточного контроля передаются интерпретатору некоторого внешнего языка (обычно это язык Unix shell или SQL). В этом случае пользователь может таким образом задать входные данные, что запущенный интерпретатор выполнит совсем не ту команду, которая предполагалась авторами уязвимой программы. Рассмотрим следующий пример: #include <stdio.h> #include <stdlib.h> int main(void) { char buf[80], cmd[100]; fgets(buf, sizeof(buf), 80); snprintf(cmd, sizeof(cmd), “ls -l %s”, buf); system(cmd); return 0; } В этом примере ожидается, что пользователь программы вводит имя файла, а программа вызывает стандартную программу ls, которая печатает информацию о введённом файле. При этом для вызова программы ls командная строка передаётся интерпретатору командной строки /bin/sh. Это можно использовать если ввести в программу строку, содержащую, например, символ ; (точка с запятой), например “myfile ; rm -rf /”. Строка, фактически переданная интерпретатору командной строки будет равна “ls -l myfile ; rm -rf /”, то есть 29
фактически будет состоять из двух команд интерпретатора shell, а не из одной, при этом вторая команда – это запрос на удаление всей файловой системы. Как и в случае уязвимости форматной строки, достаточное условие отсутствия уязвимости типа испорченного ввода в программе состоит в том, что “опасные” аргументы “опасных” функций никак не должны зависеть от внешних по отношению к программе данных. Кроме перечисленных здесь типов уязвимостей защиты существуют и другие типы, например – уязвимости как следствие синхронизационных ошибок (race conditions), некорректная работа с временными файлами, слабое шифрование и другие классы уязвимостей. В рамках данной работы мы остановимся лишь на трёх перечисленных выше типах.
4.2. Инструментальные средства для обнаружения уязвимостей защиты В настоящее время разработано большое количество инструментальных средств, предназначенных для автоматизации поиска уязвимостей защиты программ на языках Си и Си++. В данном разделе мы рассмотрим наиболее распространённые инструментальные средства. По виду использования инструментальные средства можно разделить на два типа: инструменты, добавляющие дополнительные динамические проверки в программу и инструменты только статического анализа программ. В нашей работе мы рассмотрим инструменты, которые выявляют уязвимости защиты с помощью статического анализа программ. CodeSurfer. CodeSurfer – это инструмент анализа программ, который не предназначается непосредственно для поиска ошибок уязвимости защиты. Его основными достоинствами являются: Анализ указателей Различные анализы потока данных (использование и определение переменных, зависимость данных, построение графа вызовов) Скриптовый язык. CodeSurfer может быть использован для поиска ошибок в исходном коде, для улучшения понимания исходного кода, и для реинженерии программ. В рамках среды CodeSurfer велась разработка прототипа инструментального средства для обнаружения уязвимостей защиты, однако разработанное инструментальное средство используется только внутри организации разработчиков. Flawfinder, ITS4, RATS, PScan. Все эти программы разработаны для поиска ошибок переполнения буфера и ошибок, связанных с использованием форматных строк. Данные инструменты во многом схожи. Они все используют возможности только лексического и простейшего синтаксического анализа, поэтому в данном случае не приходится говорить о скольнибудь эффективном нахождении ошибок при помощи этих программ – результаты, выданные ими, могут содержать до 100% ложных сообщений. 30
Основные свойства этих программ: База данных потенциально опасных функций (ITS4, RATS) Подробное аннотирование исходного кода (Flawfinder, ITS4) Возможность поиска функций, принимающих внешний ввод. (Flawfinder – с опцией –inputs, RATS) UNO. UNO – простой анализатор исходного кода. Он был разработан для нахождения таких ошибок, как неинициализированные переменные, нулевые указатели и выход за пределы массива. UNO позволяет выполнять несложный анализ потока управления и потоков данных, осуществлять как внутри- так и меж-процедурный анализ, специфицировать свойства пользователя. Однако, к сожалению, данный инструмент не доработан для анализа реальных приложений, не поддерживает многие стандартные библиотеки, и, на данном этапе, разработки не позволяет анализировать сколь-нибудь серьёзные программы. FlexeLint, Splint. Это наиболее мощные инструменты из всех, рассмотренных в данной работе. Они предназначены для анализа исходного кода с целью выявления различных ошибок. Обе программы производят семантический анализ исходного кода, анализ потоков данных и управления. В конце работы выдаются сообщения нескольких основных типов: Возможен нулевой указатель. Проблемы с выделением памяти (например, нет free() после malloc()). Проблемный поток управления (например, недостижимый код). Возможно переполнение буфера, арифметическое переполнение. Количество таких сообщений при работе над кодом большой программы может быть очень значительным. Поэтому оба инструмента поддерживают опции, позволяющие настраивать сообщения. Опции могут задаваться также и в исходном коде, например, в виде аннотаций. FlexeLint и Splint не разрабатывались с целью поиска ошибок уязвимости защиты. Однако обе программы позволяют находить некоторые, наиболее простые случаи потенциального переполнения буферов. При этом FlexeLint не подходит для нахождения ошибок с форматными строками, в то время как Splint выдаёт предупреждения такого типа. Как видно из приведённого краткого обзора, существующие инструменты не задействуют все современные методы статического анализа программ, ограничиваясь лишь контекстным анализом. Как было отмечено в [12], применение глубокого статического анализа программ может позволить существенно снизить количество ложных срабатываний и повысить точность обнаружения уязвимостей защиты.
31
4.3. Использование методов анализа потоков данных для решения задачи обнаружения уязвимостей В отделе компиляторных технологий по контракту с фирмой Nortel Networks разрабатывается прототип инструментального средства для автоматического обнаружения уязвимостей. В прототипе нами реализовано автоматическое выявление уязвимостей переполнения буфера, форматных строк, испорченного ввода. В дополнение к ним реализовано обнаружение ошибок утечки динамической памяти. Для разрабатываемого инструментального средства нами реализован новый алгоритм выявления уязвимостей защиты, основанный на глубоком межпроцедурном анализе указателей в программе. Алгоритм состоит из следующих основных компонент: Внутрипроцедурный анализ указателей, основанный на понятии “абстрактной ячейки памяти” (abstract memory location).
Анализ диапазонов для переменных целых типов.
Контекстно-зависимый (context-sensitive) и потоково-зависимый (flowsensitive) межпроцедурный анализ.
Специальная поддержка основных функций стандартной библиотеки языка Си и возможность спецификации семантики функции с помощью аннотаций.
Анализ указателей (alias analysis) [10] позволяет для каждой переменной указательного типа в каждой точке программы построить множество объектов, на которые он может указывать. В языке Си анализ указателей является необходимым шагом для выполнения практически любого оптимизирующего преобразования. Кроме того, анализ указателей для языка Си осложняется неразличимостью указателей и массивов, а также присутствием указательной арифметики. Для анализа указателей мы выбрали подход, основанный на моделировании операций с указателями. Каждому объекту, который может существовать при работе программы, то есть статическим переменным, переменным, создаваемым и уничтожаемым на стеке, переменным в динамической памяти ставится в соответствие абстрактная ячейка памяти. При анализе программы абстрактные ячейки памяти создаются, когда в работающей программе выделяется память под соответствующую переменную. Абстрактная ячейка памяти хранит следующую информацию:
32
Size
Размер данной абстрактной ячейки. Для функций динамического выделения памяти размер ячейки определяется по параметру функции.
overlap Множество абстрактных ячеек памяти, которые накладываются на данную абстрактную ячейку. Этот атрибут используется для переменных агрегатных, потому что в таких случаях создаются отдельные абстрактные ячейки памяти и для структуры целиком, и для каждого составляющего структуру поля.
Атрибуты абстрактной ячейки памяти, описанные выше, являются статическими, то есть не изменяются всё время жизни абстрактной ячейки памяти. В каждой точке программы с абстрактной ячейкой памяти могут быть связаны динамические атрибуты, которые описываются ниже. Len
Текущая длина строки для строковых переменных.
value
Значение переменной.
input
Указывает, зависит ли данная абстрактная ячейка памяти в данной точке программы прямо или косвенно от внешних источников данных.
Поле value содержит текущее значение переменных. Для хранения текущего значения переменных используются мета-типы, являющиеся расширением соответствующих типов языка. Например, значения переменных целых типов при анализе представляются типом M_Integer, который может принимать следующие значения: Undef
Неопределённое значение, изначально возникает, когда переменная неинициализирована и как результат операций, если один из аргументов – Undef.
Any
Переопределённое значение. Возникает когда статического анализа недостаточно для определения значения переменной (например, при чтении значения переменной из внешнего источника), либо как результат операции, если один из аргументов имеет значение Any, либо как результат операции при соответствующих операндах.
[a,b]
Любое значение в интервале от a до b.
При выполнении операций над интервалами, в особенности операций слияния значений в точках слияния потока управления, может возникнуть ситуация, когда результирующее множество целых значений состоит из нескольких непересекающихся интервалов, например [1,2]+[6,15]. В этом случае берётся минимальный интервал, включающий в себя все непересекающиеся интервалы, то есть в данном случае результатом будет интервал [1,15]. Значения указательных типов представляются множествами пар (AML, offset), где AML – абстрактная ячейка памяти, а offset – смещение от начала ячейки, которое имеет мета-тип M_Integer, то есть представляет собой диапазон смещений указателя внутри данного объекта. Кроме того, поддерживается значение Undef для неопределённых (неинициализированных) переменных, значение Any(type), если указательное выражение может принимать 33
произвольное значение типа type, и значение Any, если указательное выражение может принимать произвольное значение. Значения Any могут возникать как результат слияния значений переменных в точках слияния потока управления, вследствие ограниченной глубины анализа объектов в динамической памяти, и когда указательное значение возвращается функцией, для которой не существует исходного кода и не специфицированы аннотации. Внутрипроцедурный анализ указателей реализован по стандартной схеме итеративного прямого анализа потоков данных процедуры [11]. Для каждой инструкции процедуры на основании входящих динамических атрибутов абстрактных ячеек памяти вычисляются выходящие атрибуты, которые затем подаются на вход следующей инструкции. В точке слияния потока управления выполняется операция слияния динамических атрибутов (join). Анализ выполняется итеративно до тех пор, пока множества динамических атрибутов не перестанут изменяться. Одновременно с анализом указателей по аналогичной схеме выполняется анализ целочисленных интервалов. Эти два вида анализа переплетаются друг с другом, поскольку от интервалов целочисленных переменных могут зависеть указательные выражения и наоборот. При выполнении внутрипроцедурного анализа основную сложность представляют циклы. Для циклов реализуются специальный алгоритм вычисления диапазонов индуктивных переменных и зависящих от них выражений, состоящий из двух шагов. На первом шаге делается расширение диапазона индуктивной переменной до максимального, на втором шаге выполняется ограничение диапазона с учётом условий в теле цикла. При анализе практически любой программы возникает необходимость в межпроцедурном анализе. По степени точности анализа можно выделить контекстно-чувствительные и контекстно-нечувствительные методы анализа. Во втором типе методов анализа процедуры рассматриваются независимо от контекста, в котором они вызываются. Множество динамических атрибутов на входе в процедуру получается как слияние множеств динамических атрибутов во всех точках вызова данной процедуры. Множество динамических атрибутов на выходе процедуры переносится во все точки возврата из процедуры в вызывающую её процедуру. Как и в случае внутрипроцедурного анализа межпроцедурный анализ ведётся итеративно до тех пор, пока множества на входах и выходах не перестанут изменяться. В контекстно-чувствительных методах анализа, анализ каждой процедуры проводится независимо для каждого вызова процедуры и учитывает контекст вызова этой процедуры. Как следствие, контекстно-чувствительный анализ требует больше ресурсов для своего выполнения. В нашем инструментальном средстве мы используем гибридный подход. В точке вызова каждой процедуры учитывается контекст вызова, но контекст возврата из процедуры берётся как объединение всех контекстов выхода для 34
всех вызовов данной процедуры в программе. Это позволяет повысить точность анализа, несильно увеличивая его сложность. Дополнительной сложностью, возникающей при межпроцедурном анализе, является необходимость анализа указателей при вызовах процедур через указатель. Хотя множество возможных значений указательного выражения нарабатывается в процессе межпроцедурного анализа, это может потребовать перестройки графа вызовов процедур на ходу. В текущем прототипе нашего инструментального средства мы используем консервативный подход, предполагая, что каждый раз по указателю могут быть вызваны все процедуры, списки формальных параметров которых соответствуют фактическим параметрам вызова. Для выявления уязвимостей защиты программ, работающих в некотором операционном окружении необходимо знание семантики работы этого окружения. Прототипная версия инструментального средства разработана в расчёте на операционное окружение, предоставляемое Linux. Непосредственно в алгоритм анализа встроена поддержка основных функций стандартной библиотеки языка Си (в особенности функций работы со строками и с памятью, в том числе динамической), основных примитивов POSIX работы с файлами, файловой системой, процессами и т. д., а также некоторых специфичных расширений Linux, в частности, интерфейса модулей ядра. В настоящее время разрабатывается язык аннотаций, чтобы дать возможность пользователю нашего инструментального средства самому специфицировать семантику процедур, отсутствующих в исходном коде или для которых автоматический анализ недостаточно точен. При разработке языка аннотаций необходимо учитывать противоречивые требования: во-первых, язык должен быть достаточно мощным, чтобы позволять специфицировать семантику с требуемой для анализа степенью точности, но, с другой стороны, он должен быть достаточно простым, чтобы не требовать от пользователей специфических знаний формальных методов, и т. д. Язык аннотаций строится на расширении синтаксиса языка Си, уже применяющемся в широко распространённом компиляторе GCC. Так, для спецификации того, что возвращаемое значение некоторой функции foo находится в интервале [0,5] используется следующая конструкция: int foo(int x) __attribute__ ((post(foo >= 0 && foo <= 5))); Здесь __attribute__((...)) - это синтаксическое расширение GNU C, поддерживаемое нашим инструментальным средством, post – специальный атрибут, позволяющий определять постусловие для функции, а имя функции foo используется в постусловии для обозначения значения, возвращаемого этой функцией. Кроме того, реализуется специальная поддержка для стандартного макроса assert.
35
4.4. Результаты экспериментов Текущий прототип инструментального средства был проверен на нескольких тестовых примерах, как широко распространённых (bftpd), так и являющихся частью приложений, разрабатываемых в фирме Nortel для своего оборудования. Были получены следующие результаты. Application
Total number of warnings
Number of “true positives”
Number of Number “possible of “false errors” positives”
“false positives” %
FlexeLint
Bigfoot
20
4
3
13
65%
0 (0%)
Log_api
4
1
3
0
0%
0 (0%)
Bftpd
57
2
32
23
40%
0 (0%)
Config_api
11
9
0
2
18%
1 (11%)
Таблица 6. Результаты запуска инструментального средства В этой таблице, в столбце «Total» приведено общее количество сообщений об обнаруженных ошибках, выведенных нашим инструментальным средством. В столбце «True» дано количество сообщений, указывающих на действительные проблемы в коде. В столбце «Possible» дано количество сообщений, истинность или ложность которых мы не смогли подтвердить из-за недостатка информации о программе. В столбце «False» дано количество ложных срабатываний. Наконец, в столбце «FlexeLint» дано количество истинных сообщений об ошибке, выявленных инструментальным средством FlexeLint. Как видно из проведённых испытаний, текущий прототип системы для обнаружения уязвимостей защиты демонстрирует очень хорошие результаты. Процент ложных срабатываний оказался намного ниже, чем у других аналогичных инструментальных средств.
5. Интегрированная среда Все направления исследований, описанные в настоящей статье реализуются на базе единой интегрированной среды для изучения алгоритмов анализа и оптимизации программ [1]. IRE является системой с открытыми исходными кодами и распространяется на условиях Общей публичной лицензии GNU (GNU General Public License). Система доступна для загрузки из сети Интернет [4]. Интегрированная среда построена как набор связанных друг с другом инструментов, работающих над общим промежуточным представлением программ MIF. Для управления инструментами ИС предоставляется графический интерфейс пользователя. В настоящее время в качестве исходного и целевого языка программирования используется язык Си, но внутреннее представление разработано таким 36
образом, чтобы поддерживать широкий класс процедурных и объектно-ориентированных языков программирования. Все компоненты ИС реализованы на языке Java, за исключением транслятора из Си в MIF, который реализован на языке Си.
5.1. Состав среды Программа на языке Си транслируется в промежуточное представление с помощью компонента “Анализатор Си в MIF”. В настоящее время поддерживается стандарт ISO C90 и некоторые расширения GNU. Чтобы обеспечить независимость интегрированной среды от деталей реализации стандартной библиотеки Си для каждой конкретной платформы и обеспечить возможность корректной генерации программы на Си по её внутреннему представлению, анализатор использует собственный набор стандартных заголовочных файлов (stdio.h и т. д.). На уровне стандартной библиотеки полностью поддерживается стандарт ISO C90 и некоторые заголовочные файлы POSIX. Внутреннее представление программы находится в памяти инте-грированной среды, но возможно сохранение внутреннего представления в файле. Компонент “Генератор MIF ->C” позволяет по программе во внутреннем представлении получить программу на языке Си. При генерации программы корректно генерируются директивы #include для всех использованных в исходной программе системных заголовочных файлов. Для проведения полустатического анализа программ генератор поддерживает несколько типов инструментирования программы. Инструментирование программы заключается во внесении в ее текст специальных операторов, собирающих информацию о ходе выполнения программы. В настоящее время генератор поддерживает инструментализацию программы для сбора полных трасс выполнения программы, профилирование базовых блоков и дуг, профилирование значений. Собранные в результате выполнения инструментированной программы профили выполнения могут впоследствии использоваться для анализа и преобразования программ. Компоненты “Анализаторы” реализуют различные методы статического и полустатического анализа программ. При этом сама программа не трансформируется, а во внутреннее представление программы добавляется полученная в результате выполнения анализа информация. В интегрированной среде эти компоненты доступны посредством пункта меню Analyze. Например, алгоритм разбиения программы на базовые блоки, доступный через пункт меню Mark basic blocks, строит граф потока управления программы, создаёт соотвествующие структуры данных в памяти системы и добавляет ссылки на построенный граф в структуры данных внутреннего представления программы. Компоненты “Трансформаторы” реализуют различные преобразования программ. При этом результатом работы компонента трансформации является 37
новая программа во внутреннем представлении, для которой в интегрированной среде создаётся новое окно. Исходная программа сохраняется неизменной. Трансформационные компоненты доступны в интегрированной среде посредством пунктов меню Optimize, Transform и Obfuscate в зависимости от класса преобразования. Компоненты “Визуализаторы” реализуют различные алгоритмы визуализации информации о программе. Эти компоненты доступны посредством пункта меню Vizualize интегрированной среды.
5.2. Промежуточное представление Промежуточное представление MIF используется всеми инструментами интегрированной среды. Оно является представлением среднего уровня и спроектировано таким образом, чтобы представлять программы, написанные на широком спектре процедурных и объектно-ориентированных языков программирования. Программа в представлении MIF представляет собой последовательность четвёрок, которые используются для представления как декларативной, так и императивной информации о программе. Текстуальное представление MIF используется как интерфейс между анализатором языка и интегрированной средой, а также для хранения анализируемых программ.
6. Заключение В данной работе мы рассмотрели несколько направлений исследований, которые ведутся в отделе компиляторных технологий Института системного программирования РАН. Эти исследования используют интегрированную среду исследования алгоритмов анализа и трансформации программ, разрабатываемую в ИСП РАН и на факультете ВМиК МГУ. Открытость и расширяемость интегрированной среды позволяет достаточно легко накапливать прототипные реализации алгоритмов анализа и трансформации программ, которые разрабатываются в рамках проводимых исследований. Накопление библиотеки алгоритмов позволяет с успехом применять интегрированную среду в учебном процессе факультетов ВМиК МГУ и ФПМЭ МФТИ. Студенты, выполняя курсовые и дипломные работы, получают в своё распоряжение развитый инструментарий методов анализа и оптимизации, на основе которых они могут реализовывать новые методы анализа и оптимизации. После включения в интегрированную среду результаты работы станут доступны для дальнейшего использования. Другое учебное применение интегрированной среды заключается в использовании её в качестве пособия для изучающих курсы по методам анализа и оптимизации программ. В дальнейшем мы планируем развивать все три рассмотренных в данной работе направления работ, а также усовершенствовать интегрированную среду для облегчения её использования. Для этого, в частности, планируется 38
реализация объектной библиотеки и объектно-ориентированного интерфейса ко внутреннему представлению. Литература [1] А. В. Чернов. Интегрированная инструментальная среда Poirot для изучения методов маскировки программ. Препринт Института системного программирования РАН. М.: ИСП РАН, 2003. [2] A. Chernov. A New Program Obfuscation Method. In Proceedings of the Adrei Ershov Fifth International Conference “Perspectives of Systems Informatics”. International Workshop on Program Understanding, Novosibirsk, July 14-16, 2003. [3] A. Chernov, A. Belevantsev, O. Malikov. A Thread Partitioning Algorithm for Data Locality Improvement. To appear in Proceedings of Fifth International Conference on Parallel Processing and Applied Mathematics (PPAM 2003), Czestochowa, Poland, September 7-10, 2003. [4] The IRE Home Page. http://www.ispras.ru/groups/ctt/ire.html [5] J. E. Moreira. On the implementation and effectiveness of autoscheduling for sharedmemory multiprocessors. Ph.D. thesis, Department of Electrical and Computer Engineering, Univ. of Illinois at Urbana-Champaign, 1995. [6] J. G. Steffan, C. B. Colohan, A. Zhai, and T. C. Mowry. Improving Value Communication for Thread-Level Speculation. Computer Science Department Carnegie Mellon University. 2002. [7] SUIF Compiler System Group (http://suif.stanford.edu) [8] M. E. Wolf and M. Lam. A data locality optimizing algorithm. In ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), Totonto, CA, June 1991. [9] X. Tang, J. Wang, K. Theobald, and G. R. Gao. Thread partitioning and scheduling based on cost model. ACAPS Tech. Memo 106, School. of Computer Science, McGill University, Montreal, Quebec. Apr. 1997. [10] R. P. Wilson, M. S. Lam. Efficient context-sensitive pointer analysis for C programs. In Proceedings of the ACM SIGPLAN'95 Conference on Programming Language Design and Implementation, pages 1-12, June 1995. [11] S. Muchnick. Advanced Compiler Design and Implementation. Morgan Kaufmann Publishers, 1997. [12] D. Wagner, J. S. Foster, E. A. Brewer, A. Aiken. A First Step towards Automated Detection of Buffer Overrun Vulnerabilities. In Proceedings of Network and Distributed System Security Symposium, pages 3-17, February 2000.
39
40
Разработка параллельных Java программ для высокопроизводительных вычислительных систем с распределенной памятью В.П. Иванников, С.С. Гайсарян, А.И. Аветисян, В.В. Бабкова, В.А. Падарян Аннотация. В работе рассматривается интегрированная среда ParJava, поддерживающая разработку и сопровождение программ, параллельных по данным. При разработке и модификации параллельной программы необходимо убедиться не только в ее правильности, но также в ее эффективности и масштабируемости. Однако анализ динамических свойств программы (профилей, трасс, слайсов и т.п.), позволяющий установить ее эффективность и масштабируемость, как правило, бывает связан с необходимостью многочисленных прогонов еще не полностью отлаженной программы на целевом вычислительном комплексе (высокопроизводительном кластере). Среда ParJava предоставляет разработчику программы, параллельной по данным, широкий набор инструментов, позволяющих анализировать динамические свойства программы в процессе ее разработки. Эти инструменты позволяют получить достаточно точные оценки времени выполнения программы как функции числа узлов параллельной вычислительной системы и границ области масштабируемости. В среду ParJava включен символьный интерпретатор модели параллельной программы, который позволяет осуществлять ее динамический анализ на инструментальном компьютере, сокращая время разработки программы и затраты на ее отладку.
1. Введение В работе рассматривается интегрированная среда ParJava [1], поддерживающая разработку и сопровождение программ, параллельных по данным. Программы, параллельные по данным (в частности, SPMD-программы) характеризуются сравнительно высоким уровнем обмена данными между узлами параллельной вычислительной системы во время выполнения программы. Поэтому обеспечение таких свойств программы, как ее эффективность и масштабируемость требует дополнительной «доводки» программы, во время которой в программе обнаруживаются и устраняются «узкие места», мешающие достичь необходимого уровня ее масштабируемости. При «доводке» программы полезно знать ее динамические свойства (профили, трассы, слайсы и т.п.). Работа поддержена грантами РФФИ 02-01-00961, 02-07-90302, 03-07-90198 и грантом МК-2371.2003.01 Президента Российской Федерации
41
Среда ParJava предоставляет разработчику программы, параллельной по данным, широкий набор инструментов, позволяющих анализировать динамические свойства программы в процессе ее разработки. Эти инструменты позволяют получить достаточно точные оценки времени выполнения программы как функции числа узлов параллельной вычислительной системы и границ области масштабируемости. В среду ParJava включен символьный интерпретатор модели параллельной программы, который позволяет осуществлять ее динамический анализ не на целевой вычислительной системе, а на инструментальном компьютере, сокращая время разработки программы и затраты на ее отладку («доводку»). Использование языка Java для разработки высокопроизводительных параллельных программ вызывает большой интерес у программистского сообщества. Большая часть работ в этом направлении предлагает реализацию стандартного интерфейса MPI в окружении Java. Причина этого в том, что большая часть SPMD-программ реализуется с использованием этого интерфейса, несмотря на сложности, связанные с необходимостью в явном виде задавать все обмены. Языки высокого уровня (например, HPF [2]) используются редко, так как не обеспечивают возможности «доводки» программы и повышают накладные расходы при обмене данными (это связано, в частности, с тем, что функции MPI вызываются не непосредственно из программы, а из системы поддержки соответствующего компилятора). Поэтому в среде ParJava разработка прикладных программ ведется с явным использованием вызовов функций MPI. Будучи не в состоянии облегчить разработку параллельных программ с помощью языковых средств высокого уровня, мы разработали ряд инструментов, применение которых может помочь прикладному программисту при разработке, «доводке» и модификации его программы. Некоторые из этих инструментов обсуждаются в данной работе. Работа состоит из восьми разделов. В разделе 2 содержится краткое описание среды ParJava. В разделе 3 рассматриваются инструменты, поддерживающие разработку параллельных программ: в основном это средства сбора профилей и трасс. Средства, позволяющие определить возможность распараллеливания циклов, и средства, помогающие программисту преобразовать цикл таким образом, чтобы он допускал параллельное выполнение, в работе не рассматриваются, хотя ряд таких средств включен в среду ParJava. В разделе 4 описывается иерархическая модель параллельной программы и интерпретатор этой модели. Использование иерархической модели позволяет предсказать время выполнения программы на заданном числе узлов и оценить границы ее масштабируемости. В разделе 5 описывается подсистема мониторинга параллельной программы. В разделе 6 обсуждаются результаты экспериментальных расчетов с использованием среды ParJava. В разделе 7 среда ParJava сравнивается с другими инструментальными системами, поддерживающими разработку параллельных программ. 42
2. Краткое описание среды ParJava 2.1. Реализация интерфейса MPI в среде Java В настоящее время коммуникационные библиотеки окружения Java обеспечивают модель «клиент-сервер» и не поддерживают симметричных коммуникаций, которые необходимы для организации высокопроизводительных параллельных вычислений. Поэтому в среде ParJava был реализован стандартный интерфейс MPI, обеспечивающий симметричные коммуникации. Реализация MPI не должна увеличивать латентность и другие накладные расходы на организацию коммуникаций и уменьшать пропускную способность коммуникационного оборудования. Реализация MPI на «чистой» Java не может выполнить это условие, так как в этом случае коммуникации будут управляться JVM, и накладные расходы на организацию коммуникаций не смогут быть уменьшены ниже некоторого порога, определяемого особенностями работы JVM. Поэтому, в среде ParJava, MPI был реализован в виде «привязки» (binding) к реализации на языке С. Такой подход позволил использовать высокоэффективную реализацию MPI, которая учитывает аппаратную специфику используемого коммуникационного оборудования. Это позволяет сосредо-точиться на оптимизации кода «привязки», размер которого существенно меньше размера реализации MPI на Java. Для реализации MPI в среде ParJava используется аппарат прямых буферов, поддерживаемый пакетом java.nio в реализациях Java начиная с версии 1.4 [3].
2.2. Основные возможности среды ParJava (графический интерфейс) В среде ParJava взаимодействие с прикладным программистом осуществляется через графический интерфейс пользователя (GUI). Главное меню графического интерфейса (Рис. 1) обеспечивает доступ к следующим группам инструментов среды ParJava: File, Edit, View, Search, Run, Analyze, Transform, Visualize, Help. Меню File, Edit, View, Search содержат традиционные инструменты, обеспечивающие стандартные возможности. Остальные меню обеспечивают доступ к специальным инструментам среды ParJava. Меню Run позволяет начать выполнение программы или ее символьную интерпретацию. Меню Analyze, Transform и Visualize соответственно обеспечивают доступ к анализаторам, которые осуществляют различные виды статического и динамического анализа разрабатываемой программы, преобразователям, выполняющим требуемые преобразования программы, и визуализаторам, отображающим на монитор результаты работы анализаторов и других инструментов среды ParJava. 43
Рис. 1. Главное меню графического интерфейса пользователя среды ParJava. В текущей версии среды ParJava меню Analyze обеспечивает доступ к следующим инструментам: Slice – построение обратного динамического слайса для заданного набора переменных в заданной точке программы; Sequential – выделение последовательной части параллельной программы; AmdahlRatio – вычисление отношения Амдаля [4]; ForLoop – анализ возможности распараллеливания заданного цикла for с помощью теста расстояний [5]. Через меню Transform доступны следующие инструменты: Transform to IC – построение внутреннего представления параллельной программы; Compile – компиляция внутреннего представления отдельного фала параллельной программы в байткод; Build Project – сборка всего параллельного приложения; Parallelize – преобразование гнезда циклов к виду, допускающему распараллеливание [6]; Instrumentate – вставка обращений к инструментальным функциям в базовые блоки программы. Результаты анализов помогают прикладному программисту исследовать разрабатываемую программу, в результате символьной интерпретации получаются оценки границ области масштабируемости (по Амдалю [4], или по Густафсону [7]).
3. Инструменты, поддерживающие разработку параллельных программ 3.1. Внутреннее представление параллельной Java-программы В среде ParJava разрабатываемая прикладная программа может иметь три представления: исходный текст (Java + MPI), внутреннее представление (IC) и байт-код (BC). 44
Представление IC используется в большей части анализаторов, для символьной интерпретации и в других инструментах, доступных прикладному программисту через графический интерфейс. Во внутреннем представлении каждый метод, описанный в классах параллельной программы, представляется своим графом потока управления: вершинами этого графа являются базовые блоки, дуги задаются списком вершин. Каждый базовый блок B задается шестеркой B=<, P, I, O, L, A>, где – тип базового блока, P – последовательность операторов, I и O – списки входных и выходных переменных, соответственно, L – список базовых блоков, следующих за текущим (дуги графа потока управления), элементы списка L называются последователями блока B, A – список дополнительных атрибутов. В среде ParJava определены следующие типы базовых блоков: линейный участок – линейная последовательность операторов Java-программы (последним оператором такого базового блока может быть оператор ветвления), вызов метода, вызов коммуникационного метода MPI, вызов служебного метода MPI, вызов метода JDK. Каждый оператор в списке P представляется четвёркой: код операции, список операндов (от одного до трёх). Если список L содержит более одного элемента, то каждый его элемент снабжается селектором (селектор – это пара: ссылка на переменную, значение которой позволяет выбрать последующий блок, значение). Если блок B представляет вызов метода, P содержит две строки, определяющие имя переменной, на которой метод вызван и имя метода, I содержит не более одной переменной (возможно временной), в которой сохраняется значение, возвращаемое методом, L содержит только один элемент, селектор отсутствует. Внутреннее представление используется для построения модели параллельной программы. Дополнительные атрибуты (например, время выполнения, статистика ветвлений) вырабатываются анализаторами и используются при интерпретации модели. Когда у блока B больше одного последователя, список A может содержать статистическую информацию о том, как это ветвление выполняется при определённых начальных данных. Таким образом, внутреннее представление программы содержит информацию о потоке управления в каждом методе параллельной Java-программы.
3.2. Инструментирование и профилирование параллельной Java-программы Определить эффективность и масштабируемость параллельной программы во время ее разработки (отладки) помогают динамический анализ и/или символьная интерпретация ее текущей версии. Динамический анализ программы состоит в определении ее профилей и трасс. Они зависят от входных данных, и не могут быть определены во время компиляции. Профили и трассы параллельной программы могут быть получены при ее выполнении на одном процессоре в специальном окружении, обеспечивающем адекватную 45
интерпретацию операторов обмена данными между узлами кластера (обращений к интерфейсу MPI). Для исследования динамических свойств параллельной программы в каждый ее базовый блок добавляются инструментальные операторы, которые, не меняя алгоритма программы, обеспечивают сбор данных о свойствах программы в процессе ее выполнения (или интерпретации). Каждый инструментальный оператор – это обращение к библиотеке мониторинга, возвращающее значение атрибутов соответствующего базового блока. Для того, чтобы инструмен-тальные операторы действительно не меняли свойств программы, их количество по возможности минимизируется (для этого можно использовать, например, отношение доминирования, определенное на графе потока управления программы). Кроме того, в системе предусмотрена возможность компенсации влияния инструментальных операторов. Подсистема компенсации является частью библиотеки мониторинга. Она решает следующие две задачи: 1) корректная расстановка временных меток в записываемых событиях и 2) поддержка правильного порядка обработки сообщений. Необходимость поддержки порядка обработки сообщений возникает потому, что функции MPI не анализируют принимаемых сообщений и не следят за порядком приема сообщений. Выполнение инструментальных операторов может изменить временные промежутки между коммуникациями, в результате порядок обработки сообщений может измениться. Во многих системах динами-ческого анализа программ эту проблему обходят, обрабатывая трассы после завершения работы программы, когда имеется вся необходимая информация для перестройки трассы. В среде ParJava для поддержки исходного порядка выполнения программы она пересобирается после инструментирования. При этом в нее добавляются компенсационные операторы. При построении частотного профиля инструментальная программа получает данные о работе исследуемой программы через вызовы инструментальных методов, вставленные при ее инструментировании. Профиль хранится в виде одномерного массива целого типа, каждый элемент которого соответствует одному из базовых блоков. Каждый вызов увеличивает на единицу значение соответствующего элемента массива. Если в процессе инструментирования производилась оптимизация количества инструментальных операторов, профиль достраивается после завершения работы программы. Профили могут обрабатываться анализатором статистики. В этом случае каждый профиль рассматривается как многомерная выборка. На множестве выборок определяется расстояние между двумя элементами этого множества (a i , a j ) . Репрезентативным набором профилей, относительно определяющего критерия K ( , p, Q),0 p 1,0 , Q 1, Q N , понимается следующее множество профилей S: SBS {ai } : SBS S , ai , a j SBS (ai , a j ) , p SBS / S , S Q . 46
3.3. Выполнение (интерпретация) инструментированной программы Для выполнения инструментированной программы она транслируется в исходное представление на языке Java. Это позволяет, не меняя средств сборки проекта, снова скомпилировать байт-код, который теперь содержит вызовы инструментальных функций. Результаты сохраняются в отдельных файлах, каждый файл соответствует одному процессу параллельной программы. Помимо динамических характеристик программы, в файлы записывается служебная информация: номер процесса, параметры и время запуска и др.
3.4. Компенсация влияния инструментальных операторов Инструментальные операторы могут изменить работу программы и исказить ее временной профиль. Кроме того, может произойти искажение трасс параллельных процессов. Для иллюстрации искажения трасс рассмотрим следующий пример: первый процесс получает сообщения от двух других процессов, причем ее работа зависит от того, какой процесс прислал данные.
получает сообщение s1 от процесса p2 и выполняет подпрограмму A; затем процесс p1 получает сообщение s2 от процесса p3 и выполняет подпрограмму B. После инструментирования программы может оказаться, что выполнение инструментальных операторов в процессе p2 занимает больше времени, чем их выполнение в процессе p3. Тогда процесс p3 успеет послать сообщение s2 процессу p1 раньше, чем процесс p2 пошлет сообщение s1 (Рис. 2Б); в результате процесс p1 сначала получит сообщение s2 от процесса p3 и выполнит подпрограмму B, а потом, получив сообщение s1 от процесса p2, выполнит подпрограмму A. Таким образом, трасса инструментированной программы будет отличаться от трассы исходной программы. Для предотвращения искажений временного профиля необходимо, чтобы каждый из параллельных процессов инструментированной программы поддерживал три таймера: CTi (показание внутренних часов узла, на котором выполняется процесс i), i (время, которое процесс i потратил на выполнение инструкций, добавленных в код программы в процессе ее инструментирования) и LTi (локальное время процесса i, т.е. то время, в которое неинструмен-тированная программа находилась бы в той же точке выполнения, что и инструментированная). Легко видеть, что LTi = CTi – i. Методика синхронизации часов и технология работы с таймерами описаны в [8] и [9]. Для предотвращения искажения профиля достаточно вместо CTi заносить в профиль значение LTi.
4. Иерархическая модель параллельной Java-программы 4.1. Построение иерархической модели
Рис. 2. Влияние инструментального кода на трассу параллельной программы Пусть, в случае неинструментированного кода последовательность действий параллельной программы была следующей (Рис. 2А): сначала процесс p1 47
Наиболее точной моделью программы является сама программа, но такой подход не пригоден, так как предусматривает использование целевой платформы или средств симулирующих весь набор интерфейсов доступных выполняющейся программе (центральный процессор, системные и библиотечные вызовы). Поэтому в модели должны отражаться только те свойства программы, обладание которыми позволит оценить её время работы. Иерархическая модель программы определяется как набор направленных графов {Gi } , где каждой функции (методу) соответствует единственный граф Gi – граф потока управления i-ой функции. Представление каждого Gi описано в разделе 3.1. Каждая вершина каждого графа снабжена заполненным списком атрибутов A. Рассмотрим некоторые проблемы, которые приходится решать при построении модели. Если параллельная программа написана на объектно-ориентированном языке вызовы методов могут происходить с динамическим определением типа объекта (механизм виртуальных методов в С++). В общем случае, невозможно 48
статически определить переход управления из точки вызова такого метода, и при построении модели не удастся построить ребро вызова для вершины представляющей точку вызова. Решать эту проблему можно либо статически определяя тип переменной, на которой метод вызывается, либо профилируя программу – у отдельно взятого места вызова может быть всегда один и тот же динамический тип объекта, на котором происходит вызов метода. Помимо динамического определения типов, представляет сложность моделирование блоков try{}catch(){}. Выход из блока try может потен-циально произойти во время выполнения любого оператора. Попадая в блок catch невозможно определить место программы, из которого пришло управление, не анализируя стек вызова методов. Можно рассматривать блоки try{}catch(){} как обработку ситуаций, не происходящих при обработке корректных данных отлаженной программой на целевой системе. Тогда содержимое try становиться просто блоком, а блок catch исключается из рассмотрения. При построении модели у каждого базового блока должны быть определены атрибуты из списка A (см. раздел 3.1). Сложности, возникающие при определении этих атрибутов, связаны с особенностями работы системы замера времени на аппаратуре. Типичный случай, когда аппаратный счётчик времени не обеспечивает измерения достаточно малых промежутков времени. Например, если точность измерения времени составляет 1 мкс, то за это время центральный процессор успевает выполнить 106 команд. Измерить время выполнения базового блока можно в этом случае одним из следующих двух способов. Первый способ: создается искусственный контекст (программа), внутри которого рассматриваемый базовый блок может выполняться. Контекст, в частности, должен определять значения всех переменных из списка I. Измерить время работы искусственной программы не составляет труда: можно выпол-нить ее в цикле достаточно большое число раз и поделить суммарное время вы-полнения на число витков цикла. Второй способ измерения предусматривает статический подсчёт одинаковых операций выполняющихся в рассматри-ваемом коде, и последующее их сложение с весом, отражающим время выпол-нения этой операции на целевой машине. Такой подход требует однократной временной оценки операций JVM (сложение чисел, вычисление булевых выра-жений, создание массивов и т.д.) на целевой машине, после чего результатами можно пользоваться для статической оценки любого базового блока. Для узлов описывающих вызовы функций (методов), измерение времени зависит от типа узла. Если вызывается метод, определенный прикладным программистом, время его выполнения определяется при интерпретации этого метода. Если вызывается коммуникационная функция MPI, время ее работы определяется с помощью модели коммуникационной сети (одной из наиболее распространённых моделей сети является модель LogGP [10]).Другим способом измерения времени выполнения коммуникаций является 49
использование специального тестового режима работы библиотеки MPI (“Test mode”). В этом режиме выполняются инструментированные методы MPI, которые позволяют вычислить требуемый атрибут для каждого вызова коммуникационных функций MPI. Если вызывается библиотечная функция, считается, что время ее работы входит в спецификацию используемой библиотеки.
4.2. Интерпретация иерархической модели Имея определённые атрибуты «время выполнения» во всех узлах можно определить порядок определения времени выполнения всего графа. Делать это можно через построение цепочки узлов, по которым пройдёт выполнение (интерпретация работы программы) или через правила свёртки подграфов. Под цепочкой будем понимать мультимножество, под записью – добавление элемента в мультимножество, саму цепочку в дальнейшем будем назвать цепочкой выполнения. Первым записывается в цепочку корневой узел графа. Выполняются все четвёрки (если они есть) принадлежащие этому узлу. Если есть атрибут next, то следующий узел конец дуги с номером равным значению next. Если из узла не выходит никаких дуг, процесс построения цепочки окончен. Временем выполнения графа будем считать сумму атрибутов «время» всех узлов находящихся в цепочке. Возникает вопрос, как можно модифицировать граф, чтобы процесс построения цепочки происходил за меньшее число шагов, и при этом результат (сумма атрибутов) сохранялся. Возможно рассмотреть более широкий класс изменений, когда результат построения цепочки выполнения модифицированного графа отличается от оригинального результат не более чем на . Поскольку рассматривается граф потока управления, то в нём существуют подграфы, сами являющиеся графами потока управления. В некоторых случаях подграф может быть заменён одной вершиной, с атрибутами, построенными по определённым правилам, при этом граф остаётся графом управления. Если требуется провести свёртку, не изменяя результат построения цепочки управления, то выполнить её можно при выполнении следующих условий: 1. Подобие подграфа. Подграф является графом управления. 2. Замкнутость по результатам. Ни одна из определяемых в подграфе переменных не влияет на значения атрибутов next в узлах не входящих в подграф и над которыми доминирует выход из подграфа. 3. Статичность структуры. Для любых значений переменных при входе в подграф, цепочка управления подграфа одна и та же. Если в подграфе есть узлы представляющие коммуникации, требуется выполнение ещё двух условий: 4. Замкнутость по коммуникациям. Если в подграфе есть узлы отвечающие вызовам коммуникационных функций, то всем ответным 50
функциям (в случае send/recv), или соответствующим групповым соответствуют узлы также принадлежащие этому подграфу. 5. Синхронность начала. Последняя коммуникация, перед входом в подграф произвела синхронизацию всех процессов. Выделив подграф, удовлетворяющий перечисленным условиям, можно заменить его одним узлом с атрибутом время равным времени выполнения подграфа. Желательно привести свёртками граф к ацикличному виду, так как построение цепочки управления сводиться в таком случае к обходу дерева в глубину. На практике, модели немногих программ можно будет привести к ациклическому виду, руководствуясь указанными условиями. Ослабление требований можно провести в третьем пункте. Пусть на множестве всех значений переменных минимальное время выполнения подграфа m, максимальное M, и узел являющийся точкой входа появляется в цепочке выполнения Q раз. Тогда, заменив подграф на вершину с временем M, можно сказать что подграф свёрнут с точностью (M-m)Q. Данное преобразование может применяться к подграфам, относящимся к языковым конструкциям if и switch. Граф программы можно изначально представить в ациклическом виде, и проводить свёртки более агрессивно. Введём дополнительные типы вершин – LOOP и IF. Для определения атрибута «время» можно воспользоваться рекурсивными формулами. 1.
Если P – это последовательность блоков p1, p2, … , pM., а ti – время выполнения блока pi, то T ti .
i
2.
Ветвление. Если P – оператор if или switch, T max t i . Если i 1,n
собрана статистика ветвлений и fi – вероятность (частота) переходов по i-ой ветви, то T f i ti , fi 1.
i
i
Последовательный цикл с I итерациями. T tI , где t – время выполнения тела цикла. 4. Параллельный цикл. T=tI, where где t – время выполнения тела цикла, а I I ( P, N ) число итераций, зависящее от количества N процессоров P и размера задачи N (например, I ). P Пример. Программа решения системы алгебраических уравнений итерационным методом Якоби (см. раздел 7), имеет следующий приведённый граф для метода main. 3.
Рис. 3. Иерархическая модель для задачи решения линейных алгебраических уравнений методом Якоби. Для рассматриваемой программы применение формул свёртки даёт следующий результат 2 N (t 2 t 3 ) N (t 4 t 5 t 6 t 7 ) 2t send ( N ) 2t recv ( N ) . Как видно для T t1 P определения времени выполнения всего метода main достаточно определить время выполнения базовых блоков и промоделировать выполнение операций send и recv.
5. Мониторинг параллельной Java-программы Во время отладки параллельной программы важно добиться синхронности выполнения процессов на каждом узле, чтобы свести к минимуму их простои. Добиваться синхронности нужно путем корректировки алгоритма и эффективного распределения данных. Помочь в поиске мест в тексте программы, в которых необходимо улучшение кода, может мониторинг времени выполнения. С его помощью можно отслеживать согласованность работы параллельной программы в целом. Работы по стандартизации мониторов параллельных программ ведутся в Техническом Университете Мюнхена [11]. Опубли-кованный стандарт послужил основой для реализации в среде ParJava. Основное окно монитора представлено на Рис. 4.
Рис. 4. Основное окно монитора времени выполнения. 51
52
Как уже отмечалось, процесс мониторинга может не только замедлить ее работу, но и изменить порядок обработки сообщений (Рис 2). В системе мониторинга для предотвращения этого используется специальная («отладочная») версия библиотеки MPI, поддерживающая исходный порядок обработки сообщений. В реализации монитора использована архитектура распределённого монитора с центральным управляющим модулем [12]. Монитор состоит из головной части, расположенной на управляющей машине и «сборщиков», распределённых по узлам кластера. Головная часть обеспечивает интерфейс с пользователем и занимается приёмом данных от «сборщиков». Для передачи данных исполь-зуется протокол TCP/IP. При наличии в вычислительной системе двух сетей – вычислительной и служебной, трафик создаваемый монитором, не будет загружать вычислительную сеть, искажая работу параллельной программы. Схема, по которой происходит сбор данных на узле, показана на Рис. 5 и состоит в следующем. При запуске параллельной программы под управлением монитора на каждом узле выполняется два процесса: процесс основной программы и процесс «сборщика». При этом выполняется код, устанавливающий связь между этими двумя процессами через стандартные средства IPC. Создаётся общий сегмент памяти, в котором размещается объект, реализующий кольцевой буфер. Для явного указания расположения объекта в памяти используются возможности пакета java.nio, доступного в JDK 1.4.
прямоугольников. Цвет прямоугольника отражает специфику действий, выполняющихся данным процессом. Зелёный цвет соответствует выполнению вычислений, жёлтый – выполнению обмена данными, красный – простою процесса в ожидании прихода данных. Информация о состоянии процессов обновляется с задаваемой пользователем частотой. Более подробную информацию о процессе можно получить «нажав» мышью на соответствующий ему прямоугольник. После нажатия выплывает новое окно, в котором выдаются данные о количестве переданных/принятых данных, времени потра-ченном на вычисления и коммуникации, а также показывается оценка замедления программы из-за мониторинга. Присутствие в программе массовых коммуникаций точка-точка или групповых коммуникаций влияет на текущую пропускную способность сети, доступную для каждого конкретного процесса. Система мониторинга подсчитывает время передачи, что позволяет оценить этот показатель. Доступ к данным о пропускной способности сети (график по времени, последнее значение, среднее значение), также становится возможным при активировании окна процесса. Функции пакета MPI, используемые параллельной программой записывают в кольцевой буфер сообщения о коммуникациях, происходящих в программе. Монитор читает данные из кольцевого буфера, используя для навигации по буферу временные метки, связанные с каждым сообщением.
6. Результаты экспериментальных расчетов В этом разделе приводятся результаты экспериментальных расчетов, демонстрирующих такие свойства среды ParJava, как точность интерпретации модели программы, сравнение производительности Java+MPI по сравнению с C+MPI, переносимость параллельных программ. В качестве первого примера рассматривается программа численного решения трехмерной системы дифференциальных уравнений гидродинамики, моделирующих конвекционные потоки при взрыве сверхновой звезды. Система уравнений предложена в работе [13]. Она имеет вид: v gradP t E S P T t t 2
Рис. 5. Схема взаимодействия между параллельной программой и «сборщиком». Система мониторинга параллельной программы должна позволять варьировать уровень подробности получаемых данных. Это свойство реализовано введением двухуровневого интерфейса системы с пользователем. Графический интерфейс в обычном состоянии показывает только текущее состояние процессов. Основная часть окна представляет собой набор пронумерованных 53
GM 3
r,
divv 0, t
r S , 0. t t
где r – плотность вещества, v – скорость вещества, P – давление, E – энергия, S – энтропия. Для численного решения системы была применена консервативная разностная схема Годуновского типа второго порядка точности. Область была разбита на три концентрические части, каждая часть была покрыта равномерной прямоугольной сеткой, причем шаг сетки каждой внутренней области (по каждому направлению) был вдвое меньше, чем шаг сетки в более внешней области. 54
Вычисления выполнялись на высокопроизводительном кластере ИСП РАН, имеющем следующие параметры: 8 двухпроцессорных узлов Athlon 1533 MHz с 256 Mb оперативной памяти на каждом, коммуникационные сети – Myrinet, полнодуплексный гиперкуб с пропускной способностью 2 Gb/sec, служебная сеть – Fast Ethernet. На Рис. 6 ускорение параллельной программы (ускорением называется отношение времени выполнения программы на одном процессоре к ее времени выполнения на p процессорах), вычисленное с помощью ее символьной интерпретации (чёрная кривая), сравнивается с ускорением, полученным при ее фактическом выполнении (серая кривая).
На Рис. 7 время выполнения параллельной программы в среде ParJava, где она разрабатывается на языке Java с использованием библиотеки MPI (чёрная кривая) сравнивается с временем ее выполнения в системе программирования C+MPI (серая кривая). Из графиков видно, что параллельная программа на языке Java выполняется всего в полтора-два раза медленнее, чем аналогичная программа на языке C. Это означает, что существующее соотношение между временами выполнения последовательных программ на языках Java и C в среде ParJava сохраняется и для параллельных программ. Таким образом, график показывает, что реализация интерфейса MPI в среде ParJava действительно обеспечивает требуемое качество коммуникаций при выполнении параллельных программ.
Рис. 6. Сравнение ускорения программы, вычисленного с помощью символьной интерпретации программы (чёрная кривая), с ускорением, полученным при ее фактическом выполнении (серая кривая). Сравнение кривых показывает, что символьная интерпретация позволяет достаточно точно оценить характеристики параллельной программы. Ее преимущество перед фактическим выполнением в том, что вся чёрная кривая была получена на одном инструментальном процессоре, а для получения серой кривой потребовалось многократно выполнить ее на кластере. Таким образом, механизм символьной интерпретации позволяет сократить время, требуемое для «доводки» программы, так как инструментальный процессор значительно доступнее кластера.
55
Рис. 7. Сравнение времени выполнения параллельной программы в среде ParJava (Java+MPI – чёрная кривая) и времени ее выполнения на C+MPI (серая кривая). В качестве второго примера рассматривалась программа решения системы линейных алгебраических уравнений Ax = b итерационным методом Якоби. На Рис. 8 представлены графики зависимости ускорения от числа узлов параллельной вычислительной системы. Видно, что с увеличением порядка матрицы область масштабируемости расширяется. Вычисления выполнялись на высокопроизводительном кластере ИСП РАН (см. выше).
56
На Рис. 9 демонстрируется переносимость параллельной программы, разработанной в среде ParJava. Видно, что при выполнении на разных кластерах время счета ведет себя сходным образом. Для получения этих графиков были использованы кластеры: 18-ти узловой кластер Pentium (500MHz, два процессора на узле) с коммуникационной сетью SCI, 16-ти узловой кластер Alpha 21264 (667MHz, два процессора на узле) с коммуникационной сетью Myrinet, 16-ти узловой кластер Athlon XP (1533MHz, два процессора на узле) с коммуникационной сетью Myrinet.
7. Близкие работы
Рис. 8. Зависимость ускорения от числа узлов параллельной вычислительной системы для матриц различного порядка.
Рис. 9. Переносимость параллельной программы, разработанной в среде ParJava. 57
В работе рассмотрены следующие две проблемы: 1) применение средств анализа программ (как статического, так и динамического) для разработки, «доводки» и модификации параллельных программ; 2) обеспечение возможности разработки программ, параллельных по данным, в окружении Java. Первая проблема актуальна не только для разработки параллельных программ в окружении Java. Опубликовано несколько работ по средам, поддерживающим разработку параллельных программ на языках C/C++ и Fortran. Можно отметить такие исследовательские проекты, как AIMS (NASA Advanced Supercomputing Division) [14], TAU (University of Oregon) [15], Pablo (University of Illinois) [16], а также коммерческие системы Vampir (Pallas GmbH) [17], PGPROF (The Portland Group™ Compiler Technology) [18] и др. Большая часть этих систем ограничивается сбором статистики и построением профилей, проводя анализ параллельной программы после ее выполнения (post-mortem analysis). Наиболее близкой к ParJava является система AIMS. Сравнивая символьную интерпретацию параллельной программы в системе AIMS и в среде ParJava, можно отметить, что иерархическая модель программы, принятая в ParJava, более точно отражает специфику параллельных вычислений и допускает поэтапную частичную интерпретацию, что позволяет применять ее для моделирования высокопроизводительных распределенных вычислительных систем (кластеров) с большим числом узлов. Иерархическая модель позволяет менять уровень детализации интерпретируемой программы, позволяя в случае необходимости повысить точность интерпретации. Кроме того, в среде ParJava в отличие от AIMS более точно решена проблема символьной интерпретации циклов. В системе AIMS цикл рассматривается как целый базовый блок, тело цикла не интерпретируется, а заменяется набором атрибутов, вычисляемых в результате статического анализа тела цикла. В среде ParJava атрибуты тела цикла вычисляются в результате его автономной интерпретации, что дает гораздо более точные результаты, особенно для гнезд циклов. 58
Помимо этого символьная интерпретация в среде ParJava допускает генерацию трасс интерпретируемой программы, ее мониторинг, определение тупиковых ситуаций. Что касается второй проблемы, то все больше исследований посвящается параллельному программированию в окружении Java. Большая часть этих работ связана с реализациями интерфейса MPI для окружения Java как с помощью «привязки» к реализации MPI на языке C [19], так «чистые» реализации на языке Java [20]. Преимущество реализаций MPI, принятое в среде ParJava уже обсуждалось в разделе 2.1. Необходимо отметить несколько работ, связанных с введением в язык Java средств высокоуровневого параллельного программирования (в стиле HPF). Наиболее известны работы HPJava [21] и Titanium [22]. К сожалению, эти работы обладают всеми недостатками HPF, которые, как известно, не позволяют достичь достаточной степени масштабируемости программ из-за высоких накладных расходов на организацию коммуникаций.
8. Заключение В работе рассмотрена интегрированная среда ParJava, поддерживающая разработку и сопровождение программ, параллельных по данным. Показано, что для программ, параллельных по данным (в частности, SPMD-программ) среда ParJava помогает прикладному программисту обеспечить такие свойства разрабатываемой (модифицируемой) программы, как ее эффективность и масштабируемость, помогает осуществлять дополнительную «доводку» программы, во время которой в программе обнаруживаются и устраняются «узкие места», мешающие достичь необходимого уровня ее масштабируемости. «Доводке» программы существенно помогает выявление ее динамических свойств (профилей, трасс, слайсов и т.п.). В среде ParJava удалось реализовать оригинальный механизм символьной интерпретации, которая позволяет достаточно точно оценить характеристики разрабатываемой параллельной программы. Ее преимущество перед фактическим выполнением в том, что символьная интерпретация позволяет получить достаточно точные оценки динамических свойств разрабатываемой прикладной программы на персональном компьютере (рабочей станции), а не путем многократного выполнения разрабатываемой программы на целевой вычислительной системе (кластере). Это дает возможность прикладному программисту использовать свой персональный компьютер не только для предварительной отладки, но и для «доводки» параллельной программы, что существенно удешевляет и ускоряет ее разработку (или модификацию). Среда ParJava продолжает развиваться, в нее постоянно включаются новые инструменты. Интегрированная среда ParJava установлена на вычислительных ресурсах ИСП РАН, ГУ МСЦ и НИВЦ МГУ. Среда ParJava используется в учебном процессе 59
кафедр системного программирования факультета ВМиК МГУ и факультета ПМЭ МФТИ. Достоинством среды ParJava является также то, что параллельная программа, разработанная при помощи этой среды, может выполняться на любой масштабируемой вычислительной системе без каких-либо модификаций или преобразований, с сохранением условия масштабируемости. Это снимает многие проблемы по распространению параллельных программ. Литература 1. Victor Ivannikov, Serguei Gaissaryan, Arutyun Avetisyan, Vartan Padaryan. Improving properties of a parallel program in ParJava Environment // The 10th EuroPVM/MPI conference, Venice, Sept. 2003, LNCS v. 2840, pp 491-494. 2. D. Loveman. High-Performance Fortran. //IEEE Parallel and Distributed Technology, v. 1(1), 1993. 3. Java™ 2 Platform, Standard Edition, v 1.4.1. API Specification. http://java.sun.com/j2se/1.4.1/docs/api/index.html. 4. G. M. Amdahl. Validity of the single processor approach to achieving large scale computing capabilities. // Proc. AFIPS Conference, Reston, VA, vol. 30, pp. 483-485, April 1967. 5. E. Walker. Extracting data flow information for parallelizing FORTRAN nested loop kernels. / Submission for the degree of Doctor of Philosophy. Department of Computer Science, Heslington, the University of York, England. 1994. 6. A. W. Lim, G. I. Cheong, M. S. Lam. An Affine Partitioning Algorithm to Maximize Parallelism and Minimize Communication. // In Proceedings of the 13th ACM SIGARCH International Conference on Supercomputing, June 1999. 7. J. L. Gustafson. Reevaluating Amdahl’s law. // Communications of the ACM, vol. 31, no. 5, pp. 532-533, May 1988. 8. K. Arvind. Probabilistic Clock Synchronization in Distributed Systems. // IEEE Transactions on Parallel and Distributed Systems, Vol. 5, No. 5, May 1994. 9. R. Gupta and M. Spezialetti. Dynamic Techniques for Minimizing the Intrusive Effect of Monitoring Actions. // International Conference on Distributed Computing Systems, 1995. pp. 368-376. 10. R. Martin, A. Vahdat, D. Culler, T. Anderson. The Effects of Latency, Overhead and Bandwidth in a Cluster of Workstations. //In Proc. 24th Int. Symp. on Com. Arch. (ISCA'97), 1997, pp 85 – 97. 11. OMIS 2.0 -- On-line Monitoring Interface Specification. http://wwwbode.cs.tum.edu/~omis/. 12. K. Fürlinger and M. Gerndt. Distributed configurable application monitoring on SMP clusters. // Proceedings of Recent Advances in Parallel Virtual Machine and Message Passing Interface, Venice, 2003, p. 429-437. 13. S. D. Ustyugov and V. M. Chechetkin. Supernovae Explosions in the Presence of Largescale Convective Instability in a Rotating Protoneutron Star. // Astronomy Reports, 1999, vol. 43, №11, p. 718-727. 14. J. C. Yan. Performance Tuning with AIMS – An Automated Instrumentation and Monitoring System for Multicomputers. // Proceedings of the 27th Hawaii International Conference on System Sciences, Wailea, Hawaii, January, 4 - 7, 1994. Vol. II. pp 625-633.
60
15. Sameer Shende and Allen D. Malony. Integration and application of the TAU performance system in parallel java environments. // Proceedings of the Joint ACM Java Grande - ISCOPE 2001 Conferenc, June 2001. 16. Luiz DeRose and Daniel A. Reed. SvPablo: A Multi-Language Architecture-Independent Performance Analysis System. // Proceedings of the International Conference on Parallel Processing (ICPP'99), Fukushima, Japan, September 1999. 17. W. E. Nagel, A. Arnold, M. Weber, H.-C. Hoppe, and K. Solchenbach. VAMPIR: Visualization and analysis of MPI resources. // Supercomputer, 12(1): 69--80, January 1996. 18. B. Carpenter, G. Zhang, G. Fox, Xiaoming Li, Xinying Li, and Y. Wen. Towards a Java environment for SPMD programming. // D. Pritchard and J. Reeve, (eds.), 4th Intern. Europar Conf., LNCS vol. 1470, 1998. 19. S. Mintchev. Writing Programs in JavaMPI. // TR MAN-CSPE-02, Univ. of Westminster, UK, 1997. 20. Tong WeiQin, Ye Hua, Yao WenSheng. PJMPI: pure Java implementation of MPI. // Proceedings of the 4th International Conference on High Performance Computing in the Asia-Pacific Region, 2000. 21. B. Carpenter. Elements of the HPJava Language. //The HPJava Project.
http://www.npac.syr.edu/projects/pcrc/HPJava/elements.html. 22. K. Yelick, L. Semenzato, G.Pike, C. Miyamoto, B. Liblit, A. Krishnamurthy, P. Hilfinger, S. Graham, D. Gay, P. Colella, A. Aiken. Titanium: A High-Performance Java Dialect. // ACM 1998 Workshop on Java for High-Performance Network Computing. http://www.cs.ucsb.edu/conferences/java98.
61
Динамическая поддержка расширений процессора в кросс-системе В.В. Рубанов, А.И. Гриневич, Д.А. Марковцев, М.А. Миткевич Аннотация. В статье рассматривается задача моделирования расширений процессора в виде акселераторов (сопроцессоров) для автоматической настройки кросс-системы, включающей в себя ассемблер, компоновщик, симулятор, отладчик и профилировщик. Рассматриваемый подход основан на описании моделей акселераторов на разработанном языке спецификации с последующим использованием этих моделей кросс-системой во время ассемблирования, потактовой симуляции и отладки прикладных программ, содержащих команды акселераторов, не известные на этапе построения основного инструментария (определяемые соответствующими моделями). В статье рассматривается математическая модель поддерживаемых акселераторов и интерфейса с основным процессором. Описывается язык спецификации конкретных моделей акселераторов, дается обзор технологий настройки кросс-системы для поддержки описанных таким образом расширений.
1. Введение В статье рассматривается задача моделирования расширений процессора в виде акселераторов (сопроцессоров) для автоматической настройки инструмен-тария кросс-разработки для поддержки этих расширений. Под инструмен-тарием кросс-разработки (кросс-системой) понимается набор программных компонентов (ассемблер, компоновщик, симулятор, отладчик и профилиро-вщик) для разработки прикладных программ с использованием хост-машины, отличной от целевой аппаратуры. Под поддержкой расширений кросс-системой подразумевается ассемблирование, потактовая симуляция и отладка прик-ладных программ, содержащих команды, не известные на этапе построения основного инструментария (реализуемых специфическими для пользователя акселераторами). Рассматриваемый подход основан на предоставлении пользо-вателю возможности описать модели акселераторов на разработанном языке спецификации с последующим использованием этих моделей для настройки компонентов кросс-системы. Данная задача возникает в связи с тем, что многие современные аппаратные решения строятся на основе использования стандартного процессорного ядра со специализированными расширениями в виде акселераторов. Часть системы команд ядра зарезервирована для команд обращения к интерфейсу запуска инструкций акселераторов. Однако семантика реальных действий и вычис-лений, которые инициируют такие команды, определяется 63
конкретными акселераторами и не зависит от основного процессора. Производитель ядра и производители акселераторов могут быть разными компаниями, при этом инструментарий кросс-разработки от производителя основного процессора должен уметь поддерживать неизвестные для него расширения аппаратуры, которые создаются заказчиками. В данной работе под расширениями процессора понимается добавление акселераторов, которые могут вводить в систему новые элементы памяти (регистры, памяти данных) и определять семантику команд запуска инструкций акселераторов. Аппаратура на базе основного процессора с акселераторами представляется для прикладного программиста как вычислительная система с единой системой команд и одной программой. Память системы состоит из памяти основного процессора, разделяемой памяти и локальных памятей акселераторов. Для выделения класса поддерживаемых акселераторов и интерфейса с процессором была разработана абстрактная математическая модель, позволяющая моделировать состояние и поведение широкого класса акселераторов с потактовой точностью. Для описания конкретных моделей, в рамках данной абстрактной, предложен язык спецификации (ISE), разработаны средства визу-ального редактирования спецификаций на этом языке и средства анализа и выявления ошибок в спецификациях. Реализован подход интерактивной пере-настройки кросс-системы, заключающийся в настройке компонентов (ассемблер, дисассемблер, симулятор, отладчик) на основании интерпретации описаний моделей акселераторов. Система используется в коммерческой эксплуатации, в ней успешно реализованы модели реальных акселераторов. Статья состоит из введения, трех глав и заключения. В первой главе описывается подход к моделированию акселераторов, вводится абстрактная модель акселератора и средства описания конкретных моделей на языке ISE. Во второй главе содержится описание технологии интерактивной перенастройки кросс-системы для поддержки заданных пользователем моделей акселератов. Третья глава содержит краткий обзор смежных работ. В заключении приводятся практические результаты, полученные при эксплуатации разработанной системы. Приводится план будущих направлений развития темы.
2. Моделирование расширений процессора В данной главе рассматриваются вопросы моделирования расширений процес-сора в виде акселераторов. Для этого вводится абстрактная (математическая) модель акселератора, охватывающая достаточно широкий класс возможной аппаратуры (см. 2.1). В рамках этой абстрактной модели определяются сред-ства описания конкретных моделей акселераторов в виде файлов на специа-льном языке ISE (см. 2.2). Описанные таким образом модели акселераторов используются для автоматической конфигурации компонентов кросс-системы – симулятора, ассемблера, дисассемблера, отладчика и профилировщика (см. главу 3). 64
2.1. Абстрактная модель акселератора
2.1.1.2. Управляющее состояние
В нашей модели акселератор является сопроцессором, команды которому выдаются основным процессором. Акселератор работает синхронно с процессором. Акселератор может иметь собственную локальную память и имеет доступ к общей памяти между процессором и всеми акселераторами.
Акселератор имеет фиксированное количество управляющих слотов, совокупность которых обозначается P A . Каждый слот имеет номер, который далее будет отождествляться с соответствующим слотом. Каждый слот Li представляет собой пару целочисленных переменных (полей): поле номера команды nf и поле состояния команды t. Множество значений поля команды {nf} конечно. Ноль всегда принадлежит {nf}. Существует взаимно однозначное соответствие между {nf}\0 и множеством дескрипторов команд, определение которого будет дано ниже. Поэтому мы будем отождествлять номер n {n f } и соответсвующий дескриптор f. Множество значений поля
2.1.1. Состояние акселератора 2.1.1.1. Память акселератора Ячейка памяти представляет собой набор двоичных переменных (далее битов), с возможными значениями 0 или 1. Число битов определяет разрядность ячейки. Набор из одной или более ячеек одинаковой разрядности образует область памяти. Набор из одной или более областей образует память. Память будем обозначать большой буквой S. Состояние ячейки памяти определяется набором конкретных значений всех ее битов. Состояние памяти определяется состоянием всех ячеек ее областей. Состояние памяти будем обозначать маленькой буквой s. Обозначим через N сумму разрядностей всех ячеек памяти S, тогда память может находиться в одном из 2N состояний. Множество состояний памяти будем обозначать {s}. Заметим, что это множество однозначно задается структурой памяти. Дескриптор структуры памяти представляет собой следующий набор чисел: число областей O и набор из O пар (Wi, Si), задающих разрядность Wi ячеек области и их количество Si. В нашей модели память системы состоит из памяти основного процессора S P , разделяемой памяти S S и локальных памятей акселераторов S a :
S S
P
,S
S
,
{ S ia
A
} iN 1
, N
A
- число акселераторов
Рассмотрение памяти процессора не принципиально для данной статьи, так как акселератор имеет доступ только к разделяемой и своей локальной памяти. Пара из этих памятей формирует полную память акселератора: S
A
{S
S
a
,S }
Множество возможных состояний памяти акселератора обозначим как {s}A {s}S {s}a . Каждая область в локальной и разделяемой памяти характе-ризуется скоростью доступа - числом, означающим, сколько тактов проходит после записи в ячейку этой области, прежде чем измененное значение может быть прочитано; до этого момента при чтении считывается старое значение. Обычно в памяти акселератора можно выделить следующие области: Набор из одной или более памятей данных Набор из одного или более регистровых файлов Одиночные регистры 65
состояния команды есть натуральные числа (включая 0). Состояние слота с номером n обозначается l n (n f , t ) и определяется значениями полей этого слота. Множество возможных состояний слота {l} {n f } . Слот в состоянии (0, 0) называется свободным, в ином случае активным. Управляющим состоянием p акселератора называется совокупность состояний всех его управляющих слотов. Множество управляющих состояний акселератора обозначим { p}A {l}N S , где Ns число слотов акселератора. Активные слоты соответствуют выполняющимся командам акселератора, число управляющих слотов задает максимальное количество параллельно выполняющихся команд. В состоянии активного слота значение поля номера команды задает выполняющуюся команду, а значение поля состояния команды соответствует количеству тактов, прошедших с начала выполнения этой команды. 2.1.1.3. Состояние акселератора Состояние акселератора a задается парой из состояния памяти и управляющего состояния: a={s, p}. Множество состояний акселератора обозначим как {a} A {s} A { p} A . Элементом состояния акселератора называется любая ячейка памяти акселератора или любой управляющий слот. Состоянием элемента называется соответственно состояние ячейки или слота. Параллельной композицией функций 1 , 2 ... n (заданных на множестве состояний акселератора) назовем функцию 1 || 2 || ... || n (также заданную на множестве состояний акселератора), получаемую следующим образом: пусть {} S A P A множество всех элементов состояния акселератора, i множество элементов, состояние a которых было изменено функцией i : i a i (a ) .
66
Если пересечение всех i , i 1..n не пустое множество, то значение функции не определено. В ином случае значение задается следующим образом: a , \ A a i a (a ), a i i
управляющих состояний акселератора. Параметром функции является номер слота nl [1..N S ] . Действие next увеличивает на 1 значение поля состояния команды t для слота, заданного параметром nl . l n l n , n nl p next(n l , p ) l n ( f n , t n 1), n nl
, здесь a и a - новое и старое состояние элемента соответственно
Действие end переводит соответствующий слот в холостое состояние. ln l n , n nl p end (nl , p) ln (0, 0), n nl
2.1.2. Модель акселератора Операцией [элементарной] называется, заданная на множестве состояний памяти акселератора {s} A (см. 2.1.1.1) функция , формирующая следующее состояние памяти акселератора на основе предыдущего. Операции соответствуют действиям, которые могут быть выполнены за один такт (например, сложение двух регистров):
: {s} A {s} A Множество операций акселератора обозначим A { } . Для любого акселератора в этом множестве присутствует так называемая пустая операция, не изменяющая состояние и обозначаемая 0 . Каждая элементарная операция характеризуется функциональными ресурсами, которые необходимы для выполнения этой операции. Обозначим множество всех ресурсов акселератора как R A , а множество всех его подмножеств (включая пустое) как A . Функция r A , отображающая множество операций A на множество A , называется функцией ресурсов. Она задает набор ресурсов для каждой операции в A :
Множество из этих управляющих действий обозначим U A {next, end} . Дескриптором
команды
акселератора
называется
функция
f ,
A
вычисляющая пару из комплекс-операции и управляющего действия u U A на основании состояния памяти акселератора s {s} A и состояния команды t (см. 2.1.1.2): f : {s} A A U A A Множество дескрипторов команд акселератора обозначается I { f i } . Это множество конечно и каждому элементу f приписывается номер n f 1
(например, в порядке возрастания машинного кода в соответствии с отображением, задаваемым функцией декодирования, см. ниже). При этом для дескриптора команды всегда верно следующее (единственность конца команды): f (s , ) { , end } t : f ( ( s ), t ) undefined
r A : A A
Обозначим множество всех подмножеств в A , которые состоят из операций, использующих не пересекающиеся ресурсы, как A :
Дескриптор команды f однозначно задает функцию потактового поведения команды b f , определенную на множестве состояний акселератора и параметризуемую номером слота nl . Значение функции b f не определено,
A i , j , i j r A ( i ) r A ( j ) Таким образом, элемент множества A задает группу операций { i } , которые могут выполняться параллельно (в рамках одного такта). Применением параллельной композиции (см. выше) этот элемент задает функцию на множестве состояний памяти акселератора {s} A. Далее элементы множества A будем отождествлять с задаваемыми ими функциями и называть комплекс-операциями. Заметим, что в этом смысле A A . Определим два управляющих действия: продвижения next и окончания end. Каждое представляет собой параметрическую функцию на множестве 67
если значение поля номера команды в соответствующем слоте nl не совпадает с номером соответствующего дескриптора f . В ином случае функция b f (nl ) : {a} A {a} A задается следующим образом: 1. На основании состояния памяти s и значения поля состояния команды t в слоте c номером nl c помощью дескриптора команды определяется пара из комплекс-операции и управляющего действия u : { , u} f ( s , t ) 68
2. C помощью определяется следующее состояние памяти s (s) , а управляющее действие задает следующее управляющее состояние p u (nl , p) . Пара ( s, p ) задает значение b f (nl , s, p) . Таким образом, множество дескрипторов команд однозначно задает множество функций потактового поведения B A , имеющее столько же элементов. A Множество кодов инструкций акселератора C {ci } представляет собой множество двоичных чисел одинаковой разрядности. Каждый элемент этого множества соответствует одному из возможных значений поля код инструкции акселератора в машинном коде команды запуска акселератора (см. 2.1.3.1).
Функция
dA
декодирования
инструкций акселератора C
A
задает
отображение
множества
кодов
A
на множество дескрипторов команд I :
M
A
MA
определяется
S A, PA, C A, D A,T A
следующими
2.1.3. Симуляция акселератора Для симуляции акселератора, заданного моделью M A (см. 2.1.2), необходим генератор тактов, а также определенное начальное состояние памяти s 0 {s} A . В начальном управляющем состоянии p 0 все слоты свободны. В рассматриваемой системе акселераторы и основной процессор работают тактово-синхронно (тактовый генератор единый для всей системы), то есть такт работы акселератора равен такту работы процессора. Кроме тактового генератора, единственным внешним событием для акселератора является выдача очередной команды основным процессором (см. 2.1.3.1 ниже). 2.1.3.1. Запуск команд акселератора
dA : CA IA
Функция декодирования однозначно задает декодер акселератора – функцию DA:
D A : C A { p} A { p} A : Функция DA определяется следующим образом: если n 0 : l n0 (0, 0 ) , то l ( f n , t n ), n n0 , иначе значение p D A (c, p) n A ln (d (c), 1), n n0
Абстрактная модель акселератора описанными выше элементами:
D A не определено.
Иными словами, в случае наличия свободного управляющего слота декодер инициирует состояние этого слота в ( f , 1) , где f определяется по коду инструкции с помощью функции декодирования d A . Тактовая функция T A на множестве состояний акселератора {a} A, определяет изменение состояния акселератора на каждом такте: T A : {a} A {a} A
Эта функция однозначно задается параллельной композицией (см. 2.1.1.3) функций потактового поведения b f , соответствующих дескрипторам команд f , заданным в поле n f каждого активного управляющего слота. Иными словами для каждого такта управляющее состояние акселератора определяет набор активных команд, характеризуемых функциями потактового поведения. Параллельная композиция этих функций задает отображение T A (поведение акселератора) для текущего такта. Если активных слотов нет, то состояние акселератора не меняется. 69
В рассматриваемой модели аппаратуры множество команд основного процессора должно иметь непустое подмножество, представляющее собой команды запуска акселераторов. Такие команды инициируют запуск определенной инструкции соответствующего акселератора. С точки зрения основного процессора команда запуска акселераторов определяется тремя полями машинного кода (порядок полей несущественен, также поля не обязательно должны быть непрерывными): {КОП, номер акселератора, код инструкции акселератора} Действия основного процессора при выполнении команды запуска акселератора заключаются в активации акселератора с номером в соответствующем поле и выдаче этому акселератору кода инструкции акселератора для дальнейшего декодирования и выполнения команды в самом акселераторе параллельно с работой процессора. Для основного процессора выполнение команды запуска акселератора всегда занимает один такт. В терминах абстрактной модели выдача команды акселератора основным процес-сором заключается в передаче кода инструкции акселератора в функцию деко-дера акселератора D A ( C A это подмножество множества значений поля код инструкции акселератора). За один такт процессор может выдать не более одной команды акселератора. Заметим, что код инструкции акселератора в свою очередь может содержать КОП команды акселератора и операнды. Акселератор может параллельно выполнять несколько многотактовых команд, в том числе с одинаковым дескриптором. То есть основной процессор может выдавать новую команду акселератора, до того как отработали предыдущие команды. В рамках рассматриваемой модели это возможно, если все операции, выполняемые параллельно на каждом такте, используют непересекающиеся ресурсы (см. 2.1.2). На практике это 70
возможно, если позволяет конвейер и функциональные устройства акселератора, при этом ответственность за корректную (своевременную) выдачу команд акселератора лежит на прикладном программисте. 2.1.3.2. Тактовое поведение акселератора В ответ на событие от тактового генератора, в рассматриваемой модели действия акселератора сводятся к изменению состояния в соответствии со A
своей тактовой функцией T . Эта функция определяет поведение акселератора на каждом такте. 2.1.3.3. Обмен данными и синхронизация с процессором Обмен данными между процессором и акселераторами осуществляется через разделяемую (общую) память (см. 2.1.1.1). Заметим, что дополнительная информация от процессора к акселератору может также поступать в виде параметров инструкции (см. 2.1.3.1). Заметим, что разные акселераторы не имеют доступа к локальной памяти друг друга. Разделение доступа к общей памяти в нашей модели соответствует типу CREW (Common Read Exclusive Write). Это означает, что процессор и акселераторы могут одновременно (в рамках текущего такта) читать из ячейки памяти, однако одновременная запись запрещена. В рассматриваемой модели области памяти могут иметь задержку записи, характеризуемую скоростью доступа к памяти (см. 2.1.1.1). По умолчанию, все области памяти имеют задержку 1, то есть изменения могут быть прочитаны только на следующем такте (flip-flop модель). Заметим, что если задержка больше ноля, то возможна одновременная запись и чтение одной и той же ячейки, при чтении считывается предыдущее значение. Команды акселератора могут занимать фиксированное или переменное (в зависимости от данных) число тактов. С точки зрения прикладного программиста (компилятора) существует три способа синхронизации вычислений основного процессора и результатов работы определенной команды акселератора:
2.2. Средства описания конкретных моделей акселераторов Для задания конкретной модели акселератора необходимо определить следующие параметры, множества и функции: m
A
, N
S
,C
A
, d
A
, I
A
,
A
, R
A
, r
A
Соответствующие определения были даны в 2.1.1 и 2.1.2, где также было показано, что они однозначно задают все элементы абстрактной модели: A S A, N S PA , d A DA , A,R A,r A A , I A,A B A T A . Для описания конкретных моделей акселераторов в ИСП РАН был разработан язык спецификации ISE (Instruction Set Extension). Кроме собственно спецификации соответствующих элементов конкретной модели акселератора (см. выше), в язык также входят средства описания дополнительной информации об ассемблерном синтаксисе команд акселератора, отображении ассемблерных команд в машинные коды и описание форматов для визуализации областей памяти в отладчике. Модель акселератора далее будет отождествляться со спецификацией этой модели на языке ISE.
2.2.1. Дескриптор структуры памяти Существуют отдельные синтаксические конструкции для описания следующих типов областей памяти: Памяти данных Регистровые файлы Одиночные регистры С помощью этих конструкций можно задать дескриптор структуры памяти A (см. 2.1.1.1). Пример. Структура памяти простого акселератора: две памяти данных LDM и TM размером 2048 слов каждая с разрядностью 16 и 64 бита со скоростью доступа 3 такта Регистровый файл GRF из двух 16-ти разрядных регистров GR0 и GR1 Одиночный регистр-аккумулятор ACR разрядностью 36 бит
1. Когда команда акселератора всегда имеет фиксированное число тактов выполнения, программист может статически просчитать, когда будут готовы результаты вычислений (процессор и акселераторы работают синхронно, см. 2.1.3). 2. Акселератор в процессе выполнения может выставлять определенные флаги (менять ячейки) в общей памяти. Программа основного процессора может считывать значения этих флагов и определять готовность результатов вычислений акселератора.
DECLARE_MEMORY(INT(16, 3), 2048) LDM; DECLARE_MEMORY(INT(64, 3), 2048) TM; DECLARE_REGISTERS_FILE(INT(16), 2) GRF; DECLARE_REGISTER(UINT(36)) ACR; // debugging names and registers file structure MEMORY(LDM, "Acc LDM"); MEMORY(TM, "Acc TM"); REGFILE_BEGIN(GRF, "General Registers")
3. Частным случаем пункта 2 является вызов акселератором прерывания основного процессора. Обработчик прерывания может прочитать результаты вычислений акселератора. 71
A
72
Заданная на C++ операция может быть оформлена в виде отдельной функции (см. примеры выше) или встраиваться непосредственно в тело функции поведения команды (см. примеры в 2.2.2.2).
REGISTER(0, "GR0"); REGISTER(1, "GR1"); REGFILE_END()
2.2.2.2. Дескрипторы команд
2.2.2. Описание поведения К семантике поведения акселератора относятся следующие элементы модели m A : множество ресурсов R A , функция ресурсов r A , множество операций A , множество дескрипторов команд I (вместе с C A ).
A
и функция декодирования d A
2.2.2.1. Операции Для задания операций из A используется язык C++. Ячейки памяти акселератора доступны в качестве глобальных переменных (регистровые файлы и памяти в виде массивов). Для удобства описания могут объявляться собственные локальные переменные. Также могут быть использованы возможности специальной библиотеки (например, N-битные типы данных INT
, UINT, типы данных с фиксированной точкой FIXED, операции битовых манипуляций и т.п.). Используемые в операции ресурсы обозначаются в виде вызова функции UseResources(resources) (тем самым задается функция r A ). В существующей реализации список используемых в данной операции ресурсов передаются в виде битовой строки, где каждый ресурс соответствует определенному биту. Множество ресурсов R A задается в виде перечисления (enum) со значениями элементов по степеням двойки: enum Resources {MAC_ADDER=1, MAC_MULTIPLIER=2, ALU_ADDER=4};
Дескрипторы команд акселератора из I A задаются соответствующими функциями поведения команд. Функция поведения может принимать аргументы в виде параметров инструкции p i . Тем самым одна функция поведения может описывать набор дескрипторов (один дескриптор соответствует одному конкретному набору значений параметров). Тело функции поведения может описываться на языке C++. Отображение в операции для соответствующих значений состояния команды t неявно задается путем использования специальной функции FinishCycle(). Вызовы данной функции отделяют операции внутри функции поведения, относящиеся к последовательным тактам исполнения (значениям параметра t дескриптора команды). Для описания динамического характера выбора операций в зависимости от состояния акселератора (аргумент дескриптора s) в описании функции поведения команды допускается использование управляющих конструкций языка C, в частности циклов и ветвлений (см. пример 3 ниже). Вызов функции FinishCycle() означает окончание всех операций для текущего такта команды и соответствует управляющему действию next. Возврат из функции поведения команды соответствует управляющему действию end. Использо-вание такого решения позволяет эффективно описывать дескрипторы команд, тем самым определяя потактовое поведение команд акселератора. Пример 1. Однотактовая команда перемещения между регистрами, содержащая единственную операцию, задаваемую конструкцией GRF[greg] = LRF[lreg]: ACC_FUNCTION Move_LREG_GREG(INT<4> lreg, INT<4> greg) { GRF[greg] = LRF[lreg]; FinishCycle(); }
Пример 1. Операция по сложению двух 36-ти разрядных чисел: void ADD_36_36(INT<36>& res, INT<36> a, INT<36> b) { UseResources(MAC_ADDER); res = a + b; } Пример 2. Операция по перемножению двух 16-ти разрядных знаковых чисел: void SMUL_16_16(INT<32>& res, INT<16> a, INT<16> b) { UseResources(); res = a * b; }
73
Пример 2. Двухтактовая команда перемножения и аккумуляции результата. На первом такте происходит перемножение операндов (операция SMUL_16_16 – см. пример 2 в 2.2.2.1), на втором аккумуляция результата (операция ADD_36_36 – см. пример 1 в 2.2.2.1): ACC_FUNCTION MAC_LREG_GREG(INT<4> grs, INT<4> grt) { SMUL_16_16 (mulres, GRF[grs], GRF[grt]); FinishCycle(); ADD_36_36 (ACC, ACC, mulres); FinishCycle(); } 74
Заметим, что две выдачи подряд этой команды процессором приведут к ситуации, когда одновременно будут исполняться две различные стадии этой функции (стадия умножения второй команды и стадия сложения первой команды). Такой эффект может быть использован для моделирования конвейера акселератора. Пример 3. Команда свертки векторов, расположенных в памятях DM0 и TM0. Длительность команды зависит от данных (длина векторов задается регистром LOOPREG). Заметим, что в теле цикла за один такт выполняются несколько операций, использующих непересекающиеся ресурсы. Для синхронизации с процессором используется механизм прерывания: ACC_FUNCTION CONV_ACC_DM0_TM0(INT<4> dreg, INT<4> treg) { SMUL_16_16 (mulres, DM0[AR[dreg]++], TM0[AR[treg]++]); FinishCycle(); while (LOOPREG>0) { ADD_36_36 (ACC, ACC, mulres); SMUL_16_16 (mulres, DM0[AR[dreg]++], TM0[AR[dreg]++]); LOOPREG--; FinishCycle(); } ADD_36_36 (ACC, ACC, mulres); InterruptProcessor(); FinishCycle(); } 2.2.2.3. Функция декодирования Функция декодирования d A задается описанием множества пар из формата машинного слова команды и ссылки на функцию поведения команды: INSTRUCTION(, ); Формат машинного слова команды задается строкой в следующем алфавите: 1. Битовые символы: ‘0’ и ‘1’ 2. Параметрические символы: ‘A-Z’ и ‘a-z’ 3. Групповой символ: ‘*’ 4. Разделительный символ: ‘-‘ Символы из пунктов 1-3 называются значимыми символами. Заметим, что число значимых символов в строке формата команды должно быть равно разрядности машинного слова в системе. Непрерывная цепочка параметрических символов задает операнд. Декодер акселератора выделит указанные биты и передаст полученное значение в функцию поведения команды в виде параметра p i . Различные операнды 75
разделяются групповым или разделительным символом. Операнды нумеруются в порядке справа налево. Битовые символы задают фиксированные значения в соответствующих позициях машинного слова. На месте параметрических и групповых символов в машинном коде команды может быть любое битовое значение. Разделительные символы используются для косметических целей, а также для отделения подряд идущих операндов. Пример: INSTRUCTION("11-**-0000-0000-0001-LREG-GREG", Move_LREG_GREG); Функция поведения MoveLREG_GREG (см. пример 1 в 2.2.2.1) имеет два параметра по 4 бита каждый (LREG[4;7] и GREG[0;3]). Биты [20;21] могут принимать любые значения для данной команды (в данном примере эти биты относятся к коду акселератора и используются командой запуска акселератора основного процессора). Остальные биты фиксированы и составляют КОП инструкции аскелератора. Заметим, что совокупность всех строк форматов машинного слова задает множество допустимых кодов инструкций данного акселератора ( C A в 2.1.2). Число управляющих слотов NS задается директивой SLOTS().
2.3. Ассемблерный синтаксис команд акселератора Отдельная секция файла описания модели акселератора отвечает за определение синтаксиса ассемблера для системы команд этого акселератора. Более точно, эта секция определяет синтаксис для подмножества системы команд основного процессора, соответствующего командам запуска инструкций этого акселератора (см. 2.1.3.1). Это полезно для адекватного отра-жения на уровне ассемблера соответствующей семантики команд, так как одни и те же (в смысле машинных кодов) команды основного процессора (для запуска акселераторов) могут иметь разную семантику, в зависимости от конкретной конфигурации акселераторов в системе, специфичной для каждого заказчика. В дополнение к определению семантики команд акселераторов (см. 2.2), возможность настраивать синтаксис для этих команд является важной функциональностью рассматриваемой системы, позволяющей легко получать готовую для производственного использования кросс-систему, адаптированную для специфичной конфигурации «процессор + акселераторы пользователя». Описание ассемблерного синтаксиса системы команд состоит из трех секций: 1. Секция типов операндов и псевдонимов 2. Секция команд 3. Секция ограничений (constraints)
76
Детальное рассмотрение средств описания синтаксиса команд выходит за рамки данной статьи. Ниже приводится только краткий обзор основных возможностей.
31] и располагается в машинном слове в двух частях: в 4х битах, начиная со 2-го, и 2х битах, начиная с 8-го. КОП равен 1010-10XX-11XX-XXXX.
2.3.2. Ограничения 2.3.1. Отображение ассемблерных команд в машинное слово Общий шаблон допустимого акселератора задается в виде:
ассемблерного
синтаксиса для
2.3.2.1. На отдельные операнды команд
command ::= mnemonic [parameter {, parameter}*] {|| mnemonic [parameter {, parameter}*]}* mnemonic
::= const_string
parameter ::= operand {[const_string] [operand]}* operand
::= const_string
const_string ::= любой текст без запятых и пробелов Примеры возможных команд: DMOVE ACR1.h, DM0(DA0--), ACR1.L, TM0(TA0++) MOVE GRA, DM1(TA0+25) || ADD GR3, ACR2.H На языке ассемблера команда состоит из мнемоники (нескольких мнемоник для параллельных команд) и набора параметров, разделенных запятой. Каждый параметр может содержать несколько частей - операндов, принадлежащих к каким-либо из описанных типов. В рамках одного параметра операнды должны отделяться непустыми строками константных символов. Комбинация мнемоник ассемблерного синтаксиса отображается в поле КОП соответс-твующей команды. Операнды (operand) отображаются на поля-операнды машинного слова. Возможно задание отображения на не непрерывные поля (когда биты поля перемежаются битами других полей). Пример: .types grn [gr0:0] [gr1:1] [gr2:2] [gr3:3] const6b $ -32 31 .mnemonics MOVE {grn#0;2},{const6b#2;4#8;2} % 0xA8C0 0xFCC0 Описание задает команду MOVE с двумя операндами. Первый операнд типа grn является регистром общего назначения, код регистра размещается в 2х битах начиная с 0-го. Второй операнд является константой в диапазоне [-32; 77
Ограничения на отдельные операнды определяются соответствующим типом, к которому принадлежит операнд. Однако для наглядной генерации ошибок можно задать более широкий тип для операнда и воспользоваться механизмом общих ограничений (см. 2.3.2.2) для выделения допустимых значений. 2.3.2.2. На взаимосвязь операндов команды Ограничения на взаимосвязь операндов команды задаются в виде набора логических высказываний относительно сравнений арифметических выражений, которые могут содержать значения любых использованных в команде операндов. Считается, что ограничения выполнены, если все логические высказывания для данной инструкции принимают значение «истина». Выражения ограничений поддерживают следующие операции: Логические операции Операции сравнения Арифметические операции Битовые операции
&&, ||, ! <, >, <=, >=, ==, <> +, -, *, /, % |, &, ^, ~
В выражениях могут быть использованы числовые константы и, собственно, ссылки на операнды. Если несколько операндов имеют одинаковый тип, то следует использовать псевдонимы типов для различения операндов в выражениях ограничений. Пример. Операнды 1 и 2 не должны быть равны: ADD {GRs#8;4}, {GRt#4;4} % 0x796000 0xf9f000 (GRs <> GRt) % “Operands must be different for ADD” Заметим, что с помощью описанного механизма также можно задавать ограничения на отдельные операнды. Таким образом, возможны две стратегии работы с ограничениями на значения операндов: с одной стороны можно создать систему общих типов и затем сужать множества значений с помощью логических высказываний, а с другой работать с большим количеством специфических типов. В первом случае можно достичь более конкретных сообщений об ошибках в операндах инструкции, во втором – упрощается описание системы команд. Пользователь может выбрать любую стратегию. 2.3.2.3. На комбинации команд 78
Каждой команде можно назначить некоторый набор свойств и задать для них значения и области активации. В качестве значения свойства может выступать либо константа, либо значение одного из операндов команды. Область активации задает диапазон соседних команд, на котором данное свойство активно. Область активации по умолчанию [1;1] затрагивает только текущую команду. Механизм описания свойств (дополненный предикатами совместимости – см. ниже) фактически является модифицированным описанием таблиц использования ресурсов (reservation tables). Пример:
Зарезервировано специальное свойство «any», которым по умолчанию обладает любая инструкция. [any=X] дает истинный предикат, если вторая инструкция обладает свойством X (независимо от его значения).
MAC {acr#14;1},{grs#4;4},{grt#0;4} % 0x6c2000 0xffb800 [read_grn:grs, read_grn:grt, write_acr:acr:2;2] Данная команда обладает следующими свойствами: read_grn – двойное свойство со значениями равными значениям операндов grs и grt. Область активации по умолчанию затрагивает только текущую команду (здесь означает, что значения регистров, заданных операндами grs и grt, читаются на первом такте). write_acr – значение свойства равно значению операнда acr. Область активации [2;2] затрагивает следующую команду (здесь означает, что значение acr будет записано на втором такте). На механизме описания свойств базируется способ задания ограничений на использование ресурсов. Задается список предикатов совместимости свойств. Предикат совместимости свойств задает в квадратных скобках набор из пар свойств (пары разделяются запятыми, свойства в паре знаком =). Предикат истинен для пары команд, когда выполняются следующие условия: первая команда обладает всеми свойствами из левых частей пар, вторая обладает всеми свойствами из правых частей пар; при этом для каждой пары значения свойств совпадают на пересечении их областей активации. Предикаты совместимости оцениваются ассемблером для всех пар команд при ассемблировании программы, таким образом обнаруживаются конфликтующие команды. Заметим, что оценки работают гарантированно корректно только на линейных участках. Пример: [write_acr=read_acr] % warning: “WAR conflict for ACRs” Данный предикат будет верен, если у пары команд значение свойства write_acr первой команды совпадет со значением свойства read_acr второй команды на пересечении областей активации этих свойств. В данном примере это отражает конфликт по данным (по аккумуляторным регистрам) типа WRITE AFTER READ.
79
80
2.3.3. Сообщения об ошибках 2.3.3.1. Ошибки симуляции Число NS (см. 2.1.1.2) определяет максимальное количество параллельных команд в акселераторе. Симулятор генерирует ошибку, если процессор пытается выдать команду, когда нет свободных слотов. Другой механизм обнаружения ошибок выполнения основывается на использовании ресурсов (см. 2.1.2). Если в пределах одного такта один и тот же ресурс используется разными параллельно выполняющимися командами, симулятор генерирует ошибку выполнения. Для обеспечения CREW модели доступа к данным симулятор обнаруживает запись разными процессами в одну и ту же ячейку памяти и генерирует ошибку выполнения. 2.3.3.2. Ошибки ассемблирования Для ограничений 2.3.2.2 и 2.3.2.3 пользователь может задавать специализированный текст сообщений об ошибке и критичность ошибки (warning или error). Существует возможность задавать как индивидуальные тексты для каждого ограничения, так и ссылаться на общую таблицу сообщений. Данный подход предоставляет пользователю возможность точной настройки диагностики ошибок ассемблирования с детализированными описаниями, что является необходимым условием промышленной эксплуатации кросс-системы.
3. Динамическая настройка кросс-системы В данной главе приводится краткий обзор нашей технологии динамической настройки кросс-системы для работы с моделями акселераторов, заданных в соответствии с 2.2 и 2.3 в виде файлов описания акселераторов.
3.1. Конфигурация системы Под процессом конфигурации системы подразумевается определение конкретного набора акселераторов (типа и номера каждого акселератора). Тип акселератора (конкретная модель) определяется файлом спецификации на языке ISE. Интегрированная среда позволяет задать упорядоченный список акселераторов (файлов описания акселераторов), который и определяет конфигурацию системы, используемую для настройки соответствующих компонентов кросс-инструментария. В рамках одной сессии интегрированной среды пользователь может многократно менять как конфигурацию системы, так и сами файлы описания акселе-раторов (и, конечно же, прикладную программу). Однако изменение конфигу-рации невозможно в режиме отладки, когда работает симулятор. Для смены конфигурации сессия отладки должна быть остановлена. Для редактирования файлов описания акселераторов может быть использован 81
визуальный front-end, который поддерживает средства анализа и верификации спецификаций (напри-мер, обнаружение конфликтующих машинных кодов для разных команд).
3.2. Настройка симулятора Для настройки симулятора используется информация из файла описания акселератора, соответствующая элементам, описанным в 2.2. В существующей реализации для настройки симулятора используется два альтернативных подхода: Компиляция файла описания акселератора внешним компилятором C++ Интерпретация файла описания во время работы (run-time) В первом случае файл описания акселератора транслируется внешним компилятором в динамическую библиотеку DLL. Заметим, что в этом случае синтак-сис, описанный в 2.2, трактуется как макросы, определения переменных (2.2.1) и функции (2.2.2) C++. Функция-декодер задается таблицей соответствия шаблонов машинных команд и указателей на функции команд (2.2.2.3). Инфор-мация о синтаксисе команд (2.3) не используется симулятором и для компиля-тора в этом случае представляется в виде строки инициализации специальной глобальной переменной для использования ассемблером и дисассемблером. Программный интерфейс (API) этой библиотеки DLL содержит набор функций для извлечения информации об акселераторе. Память акселератора симулируется в виде переменных и массивов в адресном пространстве DLL. Функции поведения команд акселератора (включая операции) компилируются в исполняемый код хост-машины. Симулятор основного процессора обращается к соответствующим функциям DLL для выдачи команд акселе-ратора и инициировании очередного такта (тактовый генератор находится в отладчике). Для синхронизации потактового выполнения команд основного процессора и всех акселераторов используется модель нитей с ручным переключением контекста. Такие возможности предоставляются в операционной системе Windows в виде примитивов Fibers. Для платформы UNIX используется библиотека QuickThreads (David Keppel, 1993). Директива FinishCycle() в этом случае вызывает явное переключение нитей (fibers). В случае отсутствия внешнего компилятора C++, используется другой подход, когда функции поведения команд интерпретируются внутренней виртуальной машиной во время симуляции. Однако в этом случае существует ряд ограни-чений на использование конструкций и типов языка C++ при описании модели акселератора, так как не все возможности поддерживаются интерпретатором.
82
3.3. Настройка ассемблера/дисассемблера
4. Смежные работы
Для обеспечения динамической настройки ассемблера на новые команды акселераторов был разработан «универсальный» ассемблер, интерпретирующий описание синтаксиса системы команд и отображения в машинные коды, заданное в соответствии с 2.3, в процессе ассемблирования входной программы. Заметим, что часть системы команд основного процессора, не относящаяся к командам запуска акселераторов, также задается в виде 2.3. Таким образом, кроме собственно текста прикладной программы, входной информацией для ассемблера является набор файлов описания для системы команд ядра процессора и всех акселераторов системы. Объединение этих описаний задает общий ассемблерный синтаксис всех команд системы «процессор + акселераторы». В конкретной реализации, информация о синтаксисе извлекается ассемблером либо из указанных в параметрах командной строки библиотек DLL или непосредственно из файлов описания акселераторов. При этом описание системы команд ядра основного процессора зашито в самом ассемблере, так как она не изменяется пользователем. Заметим, что в текущей версии динамически настраиваемым является только синтаксис отдельных команд. Общий синтаксис ассемблерного файла фиксирован: Секции Объявление переменных Выражения Конструкции для макропроцессора Отладочная информация С-компилятора Дисассемблер извлекает информацию о синтаксисе команд из набора файлов описания также динамически во время своей работы (in run-time).
Для спецификации аппаратуры на низком уровне используются языки HDL (Hardware Description Languages), наиболее известными из которых являются Verilog [6] и VHDL [7]. Задачей этих языков является создание спецификации, пригодной для синтеза реальной аппаратуры. Поэтому, задание аппаратуры на данном уровне абстракции является трудоемким и непригодным для быстрого проведения исследования альтернатив дизайна, далее DSE (Design Space Exploration). Также автоматическое построение кросс-системы затруднительно на основании описания HDL, так как информация о системе команд не определяется явно (см. [1]). Интересный подход для моделирования аппаратуры разрабатывается в рамках программы Open SystemC Initiative [8], первоначально представленной в 2000 году. В настоящее время все активности по SystemC спонсируются и управляются комитетом из индустриальных компаний: ARM, Cadence, CoWare, Fujitsu, Mentor, Motorola, NEC, Sony, ST, Synopsys. SystemC это библиотека C++ классов, которая упрощает создание поведенческих моделей аппаратных систем за счет предоставления набора макросов и классов, реализующих элементы аналогичные конструкциям HDL. С помощью этих конструкций (см. [9]) возможно структурное описание системы, используя понятия модулей, процессов, портов, сигналов, интерфейсов, событий и т.п. Библиотека также предоставляет набор типов, удобных для моделирования аппаратных элементов, таких как битовые строки и числа с фиксированной точкой. Однако модель системы на SystemC предназначена только для симуляции и последующего синтеза аппаратуры, система команд явно не выделяется и построение полной кросс-системы на основании модели на SystemC затруднительно (см. [5]). В этом смысле SystemC относится скорее к классу HDL языков, при этом существуют автоматические конвертеры из Verilog и VHDL в SystemC ([10] и [11]). Скорость симуляции моделей SystemC невелика ввиду слишком низкого уровня описания деталей аппаратуры, несущественных для кросс-системы. Однако заметим, что для описания поведения отдельных операций аппаратуры примитивы SystemC очень удобны, аналогичные конструкции предоставляются и в рассматриваемой работе для описания операций и команд (см. 0). В частности предоставляются типы данных, аналогичные SystemC; также синхронизация между командами аналогична синхронизации между процессами SystemC (FinishCycle() аналогична функции wait() в SystemC).
3.4. Настройка отладчика Под настройкой отладчика подразумевается настройка соответствующих окон для отображения состояния памяти акселераторов во время симуляции, включая разбиение на именованные области. С помощью отладчика пользователь также может вручную изменять значения определенных ячеек. Во время старта отладочной сессии отладчик считывает информацию о структуре памяти акселераторов (см. 2.2.1) из соответствующих библиотек DLL или непосредственно из файлов описания акселераторов. Также для настройки подсветки синтаксиса ассемблерных команд в редакторе используется инфор-мация из синтаксической части (см. 2.3). Оттуда же берет информацию и один из профилировщиков (а именно, профилировщик покрытия системы команд).
83
Для решения задачи автоматической генерации компонентов кросс системы предназначены языки класса ADL (Architecture Description Languages). Дополнительная информация и полный обзор языков ADL может быть найден в [1] - [5]. Здесь приведем только наиболее известные решения. Одним из первых языков ADL был nML [12], изначально разработанный в Техническом Университете Берлина, Германия (1991). nML использовался в качестве способа описания аппаратуры для симулятора SIGH/SIM и компилятора CBC (с языка ALDiSP). В nML система команд процессора 84
описывается с помощью атрибутных грамматик. Атрибуты включают в себя поведение (action), ассемблерный синтаксис (syntax) и отображение в машинные коды (image). Оригинальный nML не содержит механизмов описания многотактовых команд. Однако nML получил дальнейшее развитие в бельгийском научно-исследовательском центре микроэлектроники IMEC, где в рамках дочерней компании Target Compiler Technologies была создана коммерческая среда разработки [13]-[14], ориентированная на DSP архитектуры (1995). В эту среду входят компилятор CHESS (с языка C), симулятор CHECKERS, ассемблер, дисассемблер и линкер. Также поддерживается синтез VHDL описания. В рамках этой коммерческой среды компания Target Compiler Technologies модифицировала nML для поддержки более сложной аппаратуры (в частности введены механизмы явного описания конвейера), хотя из маркетинговых заявлений компании (технические спецификации недоступны) до конца не ясно, какие именно средства описания ILP поддерживаются. Также nML поддерживает только команды фиксированной длительности и производительность симулятора, опубликованная в [14], невысока. Последователем nML стал язык Sim-nML [15], работы над которым ведутся с 1998 года в Индийском Технологическом Институте (Indian Institute of Technology Kanpur) при поддержке компании Cadence. Главным принципиальным нововведением стал дополнительный атрибут использования ресурсов (uses) в грамматике описания команд. Это позволяет описывать использование ресурсов и, тем самым, обнаруживать конфликты между командами. В рамках проекта Sim-nML были разработаны кодогенератор для компилятора, симулятор, ассемблер и дисассемблер. К сожалению, отсутствует интегрированная среда разработки и отладки. Язык ISDL был разработан в университете MIT, США [16] и представлен на конференции по автоматизированному дизайну DAC [17] в 1997 году. Основной специализацией ISDL является описание VLIW архитектур. Изначально задумывалась реализация компилятора, ассемблера и симулятора, а также генератора Verilog описания. Аналогично nML, ISDL главным образом описывает систему команд процессора, включающую в себя семантику поведения, синтаксис ассемблера, машинные коды, а также описание ресурсных конфликтов, используя атрибутную грамматику. К важным достоинствам языка можно отнести возможность точно специфицировать задержки и конфликтные ситуации для ILP в виде логических правил, хотя явное описание конвейера отсутствует. Несмотря на довольно продуманный язык, к сожалению, отсутствуют в доступном виде реальные утилиты, поддерживающие его. Инициаторы проекта ограничились только реализацией ассемблера и некоторых модулей симулятора и кодогенератора для компилятора в качестве диссертационных работ MIT. Язык EXPRESSION [18]-[19] разработан в Университете Калифорнии (University of California, Irvine, США), впервые был представлен на конференции DATE в 1999 году. Этот язык поддерживает широкий класс встроенных систем с ILP и иерархиями памяти от RISC, DSP, ASIP до VLIW. 85
EXPRESSION содержит интегрированное описание структуры и поведения подсистемы процессор-память. Спецификация на EXPRESSION состоит из шести секций (первые три отвечают за поведение, последние три за структуру): Спецификация операций (набор атомарных команд с кодами, описанием параметров и семантики (поведения)). Описание формата команды (команда состоит из ячеек, ответственных за определенный функциональный модуль, которые могут заполняться атомарными операциями для параллельного выполнения). Отображение общих операций компилятора на машинные операции, описанные в первой секции. Данное описание используется для кодогенератора компилятора. Описание компонент (функциональные устройства, шины, порты и т.п.). Описание конвейера и связей компонентов. Описание иерархии памяти (регистровая память, кэш, SRAM, DRAM). Из описания EXPRESSION автоматически генерируются компилятор EXPRESS и симулятор SYMPRESS. К недостаткам решения на основе EXPRESSION следует отнести невысокую скорость симуляции и относительную трудоемкость описания (из-за наличия детальной структурной составляющей). В этом смысле EXPRESSION стоит между чистыми поведенческими ADL решениями (типа nML) и структурными описаниями HDL уровня. Язык LISA [21]-[22] разрабатывался в университете RWTH Aachen (Германия) изначально в качестве средства описания аппаратуры для генерации симуляторов. Первые результаты работ по проекту LISA были опубликованы в 1996 году. Первоначальной целевой архитектурой были DSP процессоры. К ключевым характеристикам LISA можно отнести подробное описание конвейера на уровне операций с возможностью задания зависимостей и блокировок. Конвейерные конфликты задаются явно. Каждая команда задается в виде набора операций, которые определяются как регистровые пересылки за время одного кванта синхронизации. Описание LISA состоит из двух основных частей: спецификации ресурсов и описания операций. Описание операций в свою очередь содержит следующие секции: DECLARE (определение объектов и групп через другие объекты и операции - фактически правила грамматики). CODING (описание бинарного кодирования операции). SYNTAX (описание ассемблерного синтаксиса и параметров). BEHAVIOR и EXPRESSION (описание поведения операции в виде кода на языке C/C++). ACTIVATION (описание задержек (timings) и поведения конвейера). 86
К сожалению, отсутствует полная публичная спецификация языка LISA, вся информация взята из различных статей. Согласно [20], из всех представленных подходов только система на основе языка EXPRESSION предоставляет средства для описания акселераторов. Однако, она ориентирована только на проведение фазы DSE, в ней отсутствуют такие производственные компоненты как ассемблер, дисассемблер, отладчик. Кроме того, ни одна из систем не поддерживает динамическую настройку компонентов, так как все компоненты создаются специальными генераторами кода в виде исходного кода на C/C++ и необходимо использование внешних компиляторов для получения готовой кросс системы. Настройка обработки ошибок в ассемблере также не поддерживается указанными языками.
5. Заключение В данной статье представлена технология динамической настройки кросссистемы для поддержки ассемблирования, симуляции и отладки программ, содержащих команды, неизвестные на этапе построения основного инструмен-тария. Семантика и синтаксис этих команд определяются конкретными акселе-раторами, создаваемыми пользователями при построении специфической конфигурации системы «процессор + акселераторы» и неизвестными производителю основного процессора (и соответственно кросс-системы). Для решения этой задачи была разработана абстрактная модель поддерживаемых акселераторов и интерфейса с процессором, охватывающая широкий спектр возможной аппаратуры. Предложенный язык спецификации ISE позволяет пользователям описывать спецификации конкретных акселераторов в рамках этой абстрактной модели. Созданные файлы спецификаций регистрируются в настройках интегрированной среды при описании конфигурации системы (см. 3.1). При этом компоненты кроссинструментария настраиваются в соответствии с этими спецификациями динамически (in-run-time). В результате прикладные программисты получают возможность писать и отлаживать программы с использованием новых команд. Спецификации и конфигурация акселераторов в системе могут многократно меняться в рамках одного сеанса интегрированной среды, в том числе с помощью визуальных средств редактирования, анализа и верификации. На основе описанной технологии в рамках коммерческого проекта в ИСП РАН была реализована настраиваемая кросс-система для DSP процессора заказчика (поддерживающего акселераторы). Авторам известно, что с помощью этой сис-темы пользователями были созданы рабочие модели реальных акселераторов: a. Быстрого преобразования Фурье b. Алгоритмов эхо подавления c. Операций с комплексными числами 87
d. Операций кодирования видео e. Операций цифровой фильтрации звука Пиковая производительность симулятора центрального процессора (на хостмашине PIII-1000MHz) в рассматриваемой системе составляет порядка 10 миллионов тактов в секунду. При использовании конфигурации с одним акселератором (эхо подавления) производительность составила порядка 1 миллиона тактов в секунду (при этом симулируются процессор и акселератор, работающие параллельно), что обусловлено большими потерями на синхронизацию процессов выполнения процессора и акселератора. Дальнейшие наши работы в этой области направлены на расширение языка ISE и соответствующих утилит для поддержки моделирования полной системы, включая описание центрального процессора. Отдельное внимание уделяется увеличению производительности симулятора за счет использования JIT технологий и использования знаний о конкретной программе. Также предполагается расширить возможности системы для настройки компилятора с языка высокого уровня для генерации кода с учетом наличия акселераторов (в настоящее время команды акселератора на уровне языка C используются вручную в виде ассемблерных вставок). Литература [1] Hiroyuki Tomiyama, Ashok Halambi, Peter Grun. Architecture Description Languages for Systems-on-Chip Design. Center for Embedded Computer Systems, Univertsity of California. 2000. [2] Wei Qin, Sharad Malik. Architecture Description Languages for Retargetable Compilation. The Compiler Design Handbook, CRC Press, 2003. [3] Clifford Liem, Pierre G. Paulin, Ahmed A.Jerraya. Retargetable Compilers for Embedded Core Processors. Kluwer Academic Publishers, 1997. [4] Rainer Leupers. Retargetable Code Generation for Digital Signal Processors. Kluwer Academic Publishers, 1997. [5] Lin Yung-Chia. Hardware/Software Co-design with Architecture Description Language. Programming Language Lab. NTHU. 2003. [6] IEEE Standard Hardware Description Language Based on the Verilog® Hardware Description Language, IEEE Std 1364-1995. [7] IEEE Standard VHDL Language Reference Manual, IEEE Std 1076-1987 [8] Open SystemC Initiative. http://www.systemc.org/ [9] SystemC User’s Guide. Version 2.0.1. http://www.systemc.org/ [10] N.Agliada, A.Fin, F.Fummi, M.Martignano, G.Pravadelli. On the Reuse of VHDL Modules into SystemC Designs, FDL 2001 [11] Leila Mahmoudi Ayough Ali Haj Abutalebi Omid F. Nadjarbashi Shaahin Hessabi. Verilog2SC: A Methodology for Converting Verilog® HDL to SystemC. HDLCon 2002 [12] A. Fauth, J. Van Praet, M. Freericks. Describing Instruction Set Processors Using nML. Proc European Design and Test Conf., Paris, March 1995. [13] Chess/Checkers Products. Target Compiler Technology. http://www.retarget.com/ [14] Mark R. Hartoog, James A. Rowson, Prakash D. Reddy. Generation of Software Tools from Processor Descriptions for Hardware/Software Codesign. Alta Group of Cadence Design Systems, Inc. DAC 1997.
88
[15] Sim-nML Homepage. http://www.cse.iitk.ac.in/sim-nml/ [16] ISDL Project Homepage. http://caa.lcs.mit.edu/caa/home.html [17] George Hadjiyannis, Silvina Hanono. ISDL: An Instruction Set Description Language for Retargetability. Srinivas Devadas. Department of EECS, MIT. DAC 1997. [18] EXPRESSION Homepage. http://www.cecs.uci.edu/~aces/index.html [19] Ashok Halambi, Peter Grun, Vijay Ganesh, Asheesh Khare, Nikil Dutt and Alex Nicolau. EXPRESSION: A Language for Architecture Exploration through Compiler/Simulator Retargetability, DATE 99. [20] Prabhat Mishra, Frederic Rousseau, Nikil Dutt, Alex Nicolau. Architecture Description Language Driven Design Space Exploration in the Presence of Coprocessors. SASIMI 2001. [21] V. Zivojnovic, S. Pees, and H. Meyr. LISA: Machine description language and generic machine model for HW/SW co-design. In Proc. of Workshop on VLSI Signal Processing, 1996. [22] Andreas Hoffmann, Achim Nohl, Stefan Pees, Gunnar Braun, Heinrich Meyr. Generating Production Quality Software Development Tools Using a Machine Description Language. DATE 2001. [23] N. Cutland. Computability: an introduction to recursive function theory. Cambridge University Press, 1980.
89
Команда "шаг" в параллельных отладчиках А.Я. Калинов, К.А. Карганов, К.В. Хоренко Аннотация. В статье рассматривается новая схема команд перемещения в параллельных отладчиках на примере команды «шаг». Основное отличие предложенной схемы от существующих заключается в том, что отладчик на основе модели параллельной программы анализирует момент завершения «шага» программы, чем приближает отладку параллельной программы к отладке последовательной программы. Рассмотрены проблемы, возникающие при реализации данной схемы для отладчика MPI-программ, и описана ее реализация в отладчике mpC-программ.
1. Введение Одной из важнейших возможностей, предоставляемых отладчиком, является возможность управления выполнением программы. Семантика команд управления выполнением в последовательных отладчиках (когда отлаживается один процесс с одним потоком управления) достаточно ясна. Например, семантика команды пошагового выполнения последовательной программы заключается в следующем – выполнить операторы текущей строки и прервать выполнение отлаживаемой программы. Если операторы текущей строки не выполнены, то пользователь анализирует причину (например, ожидание взаимодействия с внешним миром, длинный счет и т.д.) и предпринимает или не предпринимает какие-либо действия. Причины невыполнения шага последовательной программы назовем «последовательными». Естественное расширение этой семантики на случай параллельного отладчика (когда отлаживается несколько потоков управления, возможно, в нескольких процессах) – выполнить операторы текущих строк для выделенных потоков управления и прервать их выполнение. Однако, в случае параллельного отладчика, некоторые потоки могут не выполнить шаг не только по «последовательным», но и по «параллельным» причинам, связанным с взаимодействием между потоками/процессами параллельной программы. Большинство существующих параллельных отладчиков являются многоцелевыми, не ориентированными на поддержку какого-либо конкретного параллельного языка программирования или коммуникационного пакета. В них применяется комбинация двух основных схем реализации команды "шаг":
89
синхронная – команда выдается для всех процессов группы, ожидается завершение шага для всех процессов группы, имеется возможность принудительного прерывания – основная схема в Mantis [1,2];
асинхронная – команда выдается для всех процессов группы завершивших предыдущий шаг на данный момент, управление в отладчике передается пользователю без ожидания окончания выполнения команды - основная схема в TotalView [3].
При этом ответственность за анализ и обработку всех «параллельных» причин незавершения шага возлагается на пользователя. В тоже время, если рассматривать не параллельную программу вообще, а MPIпрограммы или программы на параллельном языке высокого уровня, то среди «параллельных» причин незавершения шага большинство является «тривиальными», обработку которых может производить отладчик, приближая тем самым, насколько это возможно, отладку параллельной программы к отладке последовательной программы. Конечно, это возможно только в том случае, если отладчик понимает семантику параллельной программы и имеет соответствующую поддержку со стороны реализации библиотеки или языка. В данной статье обсуждается возможность реализации синхронной модели выполнения команды "шаг", которая отличается от традиционной тем, что:
последовательная команда "шаг" выполняется только теми процессами, которые завершили выполнение предыдущей команды перемещения;
«тривиальные параллельные» обрабатываются отладчиком.
причины
незавершения
шага
Рассматриваются проблемы, возникающие при реализации такой модели для отладчика MPI-программ, и описывается ее реализация для параллельного отладчика для языка mpC [4,5], который является составной частью интегрированной системы разработки и выполнения mpC программ mpC Workshop. Статья организована следующим образом: в первом параграфе дается определение параллельной команды "шаг", которое демонстрируется на примере простой MPI-программы. Во втором параграфе анализируется возможность учета «тривиальных причин» незавершения шага для MPIпрограмм. Третий параграф дает введение в язык параллельного программирования mpC. В четвёртом параграфе описывается mpC-отладчик.
90
2. Синхронная модель команды «шаг» с обработкой «тривиальных причин» незавершения шага на примере MPI-программ
программы, и текущей строкой для всех процессов является строка 3. Тогда для последовательности шагов параллельной программы для различных процессов текущими будут следующие строки:
Введём определение команды синхронной команды «параллельного шага». Примем, что для выполнения команды «шаг параллельной программы» группой процессов каждому процессу из группы, завершившему предыдущие команды перемещения, необходимо выполнить действия, определяемые командой «шаг» последовательного отладчика (“последовательной” команды «шаг»). Шаг параллельной программы будем считать завершённым, если каждый процесс отлаживаемой программы: а) выполнил действия, предписанные последней данной ему “последовательной” командой перемещения (возможно, не командой «шаг») или б) остановился и не может продолжить выполнение без дополнительных действий со стороны пользователя по отношению к другим процессам отлаживаемой программы. Назовем «тривиальной параллельной» причиной незавершения параллельной команды шаг процессом ожидание синхронизации с другими процессами, про которую известно, что она не произойдет на данном шаге параллельной программы. Пример 1. Рассмотрим пошаговое выполнение следующей MPI-программы: /* 0*/ #include "mpi.h" /* 1*/ int main(int argc, char **argv) { /* 2*/ int rank, i; /* 3*/ MPI_Init(&argc, &argv); /* 4*/ MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* 5*/ if (rank == 1) { /* 6*/ MPI_Status stat; /* 7*/ MPI_Recv(&i,1,MPI_INT,0,0,MPI_COMM_WORLD,&stat); /* 8*/ } /* 9*/ if (rank == 0) { /*10*/ i = 0; /*11*/ MPI_Send(&i,1,MPI_INT,1,0,MPI_COMM_WORLD); /*12*/ } /*13*/ MPI_Finalize(); /*14*/ return 0; /*15*/ } Пусть отладчик является «умным», то есть обрабатывающим «тривиальные параллельные» причины незавершения шага и интерпретирует вычисление управляющего выражения условного оператора как самостоятельный шаг. Пусть, кроме того, команды выдаются для всех процессоров отлаживаемой 91
Текущие позиции для процессов с rank
Шаг
Примечание
0
1
остальные
1
3
3
3
2
4
4
4
3
5
5
5
4
9
7
9
Процесс с rank равным 1 не может закончить свой шаг по «тривиальной параллельной» причине - управление не может вернуться из функции MPI_Recv так как процесс с rank равным 0 еще не вызвал функцию MPI_Send в строке 11 и не вызовет ее на этом шаге.
5
10
7
13
Остальные процессы не могут завершить шаг по «тривиальной параллельной» причине - для завершения работы MPI_Finalize ее должны вызвать все процессы.
6
11
7
13
Процесс с rank равным 1 процесс должен закончить выполнение MPI_Recv.
7
13
9
13
8
13
13
13
Таблица 1. Текущие позиции для различных процессов при пошаговом выполнении MPI программы. В данном примере за восемь шагов параллельной программы процесс с rank равным 0 сделал 7 последовательных шагов, процесс с rank равным 1 сделал 6 последовательных шагов, остальные процессы сделали 5 последовательных 92
шагов, и пользователю не потребовалось никаких дополнительных действий для этого. Основные отличия предложенной схемы выполнения команды «шаг» от существующих схем: 1.
2.
Первые три шага в параллельном отладчике с синхронной схемой команды «шаг» будут идентичны приведённым выше. Однако пользователь не дождётся завершения шага 4 в таком отладчике, поскольку процесс с rank равным 1 не сможет завершить свою часть команды. Пользователю придётся прервать выполнение команды. В результате он получит набор процессов, остановленных в разных точках программы. Он не будет знать, какой из процессов остановился самостоятельно, выполнив свой элементарный шаг, а какой был прерван пользователем. Если в отладчике реализована асинхронная модель параллельной команды «шаг», то пользователь, после того, как выдал команду и получил управление в отладчике (сразу же после выдачи команды), не может быть уверен, что все процессы завершили выполнение своих частей общей параллельной команды «шаг». Пользователь может убедиться в полном завершении (или незавершении) общей команды лишь исследовав статус каждого процесса вручную и проанализировав их.
Важно отметить, что в обоих рассмотренных случаях после четвёртого шага процесс с rank 1 будет находиться где-то внутри функции MPI_Recv. В тоже время отладчик уровня исходного текста языка параллельного программирования должен обеспечивать отладку в терминах самого языка. Отладчик MPI-программ также должен поддерживать отладку в терминах MPI и языка последовательного программирования, из которого вызываются функции MPI. Соответственно, для него функции MPI должны являться неделимыми примитивами. Для пользователя, отлаживающего MPI-программу, получить информацию о том, что один из процессов его программы находится в какойто внутренней функции, вызванной, например, внутри MPI_Recv также неестес-твенно, как для пользователя, отлаживающего последовательную программу на языке высокого уровня, получить информацию, что программа выполняет какую-то из ассемблерных операций. Мы считаем это существенным недостатком существующих схем параллельных команд перемещения, который устраняется в предлагаемом подходе.
3. Подход к учету «тривиальных причин» незавершения шага для MPI-программ Предлагаемая реализация шага параллельной программы возможна только в том случае, если отладчик понимает семантику функций MPI и имеет модель выполнения MPI-программы. Это невозможно без поддержки отладчиков со 93
стороны MPI, так же как отладка программ на языке высокого уровня невозможна без поддержки со стороны компилятора. В настоящее время поддержка параллельных отладчиков реализациями MPI ограничивается интерфейсом, разработанным для TotalView [7], который ориентирован только на просмотр очередей сообщений и не позволяет обрабатывать «тривиальные параллельные» причины незавершения шага в MPI-программе. Современные параллельные отладчики (например, p2d2[6]) имеют следующую клиент-серверную архитектуру: Клиент отладчика
Нераспределенная часть сервера отладчика
Распределенная часть сервера отладчика
Распределенная часть сервера отладчика
Исполняемый код
Исполняемый код Рис. 1
В ней сервер состоит из двух частей: нераспределенной, которая отвечает за управление параллельной программы как целым, и распределенной, которая отвечает за непосредственное управление выполнением каждого из процессов параллельной программы. Соответственно, нераспределенная часть должна поддерживать модель текущего состояния параллельной программы и, на основании информации, получаемой от распределенных частей обрабатывать «тривиальные параллельные» причины незавершения шага. Рассмотрим, какой информации не хватает в текущем интерфейсе «MPI – отладчик» [7] на примере функции MPI_Send. С помощью этого интерфейса доступна очередь незаконченных посылок для каждого коммуникатора. Элемент этой очереди имеет тип структуры mqs_pending_operation[8] и содержит большое количество информации о посылке. Известно, что реализация MPI самостоятельно принимает решение о том буферизировать, или нет пересылаемое сообщение. В случае буферизации сообщения операция пересылки является локальной и заканчивается вне зависимости от соответс94
твующего запроса на прием. В противном случае она не является локальной и не может закончиться, если не был выдан соответствующий запрос на прием. Для того, чтобы передать эту информацию компоненте отладчика, связанной с конкретным процессом, достаточно просто добавить в структуру mqs_pending_operation еще одно поле, которое говорило бы о том было ли сообщение буферизировано или нет. Построение полного интерфейса «MPI – отладчик», удовлетворяющего требованиям предлагаемого подхода, не является целью данной работы. Мы просто хотим обратить внимание на то, что он может быть получен путем незначительной доработки уже имеющегося интерфейса. Мы реализовали предлагаемый подход в отладчике для языка параллельного программирования mpC, который описан ниже.
4. Язык параллельного программирования mpC Язык параллельного программирования mpC был разработан в конце 90х в Институте системного программирования РАН. В языке mpC, который является расширением языка С, вводится понятие вычислительного пространства, которое определяется как некоторое доступное для управления множество виртуальных процессоров. Основным понятием mpC является понятие сетевого объекта или просто сети. Сеть является областью вычислительного пространства, которая может быть использована для вычисления выражений и выполнения операторов. Размещение и освобождение сетевых объектов в вычислительном пространстве выполняется аналогично размещению и освобождению объектов данных в памяти. Концептуально, создание новой сети инициируется процессором уже существующей сети. Этот процессор называется родителем создаваемой сети. Родитель всегда принадлежит создаваемой сети. Единственным виртуальным процессором, определенным от начала и до конца выполнения программы, является предопределенный виртуальный хостпроцессор. Любой сетевой объект, объявленный в программе, имеет тип. Тип специфицирует число и производительности процессоров. Например, объявление nettype SimpleNet(n) { coord I=n; }; вводит параметризованный сетевой тип с именем SimpleNet, соответствующий сетям, состоящим из n виртуальных процессоров. Виртуальные процессоры сети связаны с координатной переменной I, значение которой изменяется от 0 до n-1. Родитель сети имеет по умолчанию координату равную 0. Это простейшая сеть, определение которой содержится в стандартном файле mpc.h. 95
Пример 2. Рассмотрим mpC-программу эквивалентную MPI-программе, приведенной в примере 1. /* 0*/ #include “mpc.h” /* 1*/ int [*]main(int argc, char **argv) { /* 2*/ net SimpleNet(2) w; /* 3*/ int [w]i; /* 4*/ [host]i=0; /* 5*/ [w:I==1]i=[host]i; /* 6*/ return 0; /* 7*/ } Имея объявление сетевого типа, можно объявить идентификатор сетевого объекта этого типа. Например, объявление в строке 2 вводит идентификатор w сетевого объекта состоящего из 2 виртуальных процессоров. Объект данных, распределенный по некоторой области вычислительного пространства, составляется из обычных (нераспределенных) объектов одного типа, размещенных в процессорных узлах этой области таким образом, что каждый процессорный узел содержит одну и только одну компоненту распределенного объекта. Например, объявление в строке 3 вводит целую переменную i, распределенную по сети w. Конструкция [w] представляет собой спецификатор распределения переменной. В данной программе используются спецификаторы распределения [*] и [host], соответствующие всему вычислительному пространству и хост-процессору соответственно, а также [w:I==1], выделяющий узел сети w с координатой I, равной 1. Отметим, что хост-процессор имеет в этой сети координату 0. Оператор в строке 4 присваивает компоненте переменной i, расположенной на хост-процессоре, значение 0. Это локальное присваивание. Присваивание в строке 5 является расширением присваивания языка С. Оно присваивает компоненте переменной i, расположенной на узле сети w с координатой I, равной 1, значение компоненты переменной i, расположенной на хост-процессоре. Это распределенное присваивание. Компилятор транслирует текст исходной программы на mpC в ANSI Cпрограмму с обращениями к функциям системы поддержки времени выполнения. Используется SPMD-модель целевого кода, когда все процессы, составляющие параллельную программу, выполняют одинаковый код. Система поддержки времени выполнения управляет вычислительным пространством, которое отображается на некоторое число процессов, выполняющихся на целевой вычислительной машине с распределенной памятью (например, на сети ПК и рабочих станций), а также обеспечивает передачу сообщений. Она полностью инкапсулирует конкретный коммуникационный пакет (в настоящее время, подмножество MPI 1.1) и обеспечивает независимость компилятора от конкретной целевой платформы.
96
5. Отладчик mpC-программ mpC Workshop является интегрированной средой разработки и выполнения mpC программ для Windows, разработанной в Институте системного программирования РАН для компании ATS (www.atssoft.com). Он состоит из набора инструментов, поддерживающих все стадии разработки и выполнения mpC-программ, основным из которых является отладчик mpC-программ. С каждым виртуальным процессором (процессом параллельной программы) отладчик связывает курсор, который указывает на его текущую выполняемую строку. Курсор имеет цвет, который указывает на его статус. Цвета определяются в соответствии со стилем светофора, то есть, зеленые курсоры могут выполнить команду перемещения, желтые могли бы выполнить команду перемещения, но остановлены пользователем и, наконец, красные курсоры не могут выполнить команду перемещения, так как они не закончили один из предыдущих шагов и ожидают синхронизации с другими виртуальными процессорами для его завершения. Курсоры одного цвета, указывающие на одну и ту же строчку, объединяются в составной курсор. Существует возможность поменять цвет, как у всего составного курсора, так и у некоторых входящих в него курсоров. Можно менять цвет курсора только с желтого на зеленый и наоборот. Красный цвет курсора определяется отладчиком. Далее если это не будет оговорено отдельно, мы не будем делать различия между простым и составным курсором, а также между курсором и виртуальным процессором. В отладчике mpC принята описанная выше синхронная модель. То есть, отладчик ожидает окончания шага всеми зелеными курсорами. Если отладчик знает, что какой-либо курсор не может закончить текущий шаг по «тривиальной параллельной» причине, он помечает этот курсор красным цветом и не ожидает завершения им последовательного шага на данном шаге параллельной программы. После того, как на каком-то шаге параллельной программы произошло событие, которое позволяет красному курсору закончить незавершенный последовательный шаг, отладчик начинает ожидать его завершения. Рассмотрим пошаговое выполнение программы из примера 2. Пусть текущая виртуальная параллельная машина состоит из 2 виртуальных процессоров. В начале сессии отладки существует только один курсор зеленого цвета, показывающий на 1-ю строчку.
97
После первого шага появляется два курсора. Первый с номером 0 соответствует хост-процессору, который должен выполнить оператор в строке 4. Второй с номером 1, соответствует узлу сети w с координатой 1, который должен выполнить оператор в строке 5.
После второго шага курсор с номером 1 остается в той же позиции, но меняет свой цвет, так как он не может выполнить оператор в строке 5 до тех пор, пока его не начнет выполнять хост-процессор.
98
системы программирования, в отладочном режиме, стандартные команды пересылки заменяются на синхронные. В будущем, когда удастся решить проблему с идентификацией выбранного режима выполнения стандартной команды пересылки, это ограничение будет снято.
6. Заключение
После выполнения третьего шага хост-процессором, процесс, которому соответствует курсор с номером 1 также заканчивает выполнение оператора в строке 5 и опять получается только один зеленый курсор.
Существует естественное противоречие между общностью параллельного отладчика и сервисом, который он мог бы предоставлять при отладке программ, разработанных с помощью конкретного параллельного языка программирования или коммуникационной платформы. В данной статье мы рассматриваем один из аспектов построения специализированных параллельных отладчиков для конкретной коммуникационной библиотеки (MPI) и конкретного языка параллельного программирования (mpC), а именно, реализацию команд перемещения на примере команды «шаг». Предлагаемая синхронная схема команды «шаг», с обработкой «тривиальных параллельных» причин незавершения позволяет, освободить пользователя от рутинной работы и, по возможности, приблизить отладку параллельной программы к отладке последовательной программы. Рассмотрена возможность реализации предлагаемой схемы для отладчика MPI-программ и показано, что она может быть реализована при незначительном усложнении существующего интерфейса «MPI – отладчик». Описана реализация предлагаемой схемы в отладчике mpC-программ, который является составной частью интегрированной системы разработки mpC Workshop. Литература
Отладчик mpC имеет традиционную модель «клиент-сервер». Клиент связан со специальным процессом – менеджером отладки, который получает команды пользователя и управляет выполнением процессов параллельной программы. Когда, при выполнении шага, процесс параллельной программы выполняет действие, требующее синхронизации с другими процессами, информация об этом передается менеджеру отладки. Он понимает семантику соответствующих действий и поддерживает внутри себя модель состояния параллельной mpC программы, которая позволяет ему определять, какие процессы завершат выполнение шага, а какие нет. Как отмечалось выше, mpC-компилятор транслирует mpC-программу в MPIпрограмму. Получающаяся в результате MPI-программа является “безопасной” (“safe”) в смысле стандарта MPI [9], то есть, для ее успешного выполнения не требуется буферизация сообщений. Для того чтобы устранить неопределенность, связанную со стандартным режимом, в текущей версии 99
1. Steven S.Lumetta, David E.Culler, “Mantis User's Guide, Version 1.0”, 1994, http://www.cs.berkeley.edu/projects/parallel/castle/mantis/mantis.tr.html. 2. Steven S. Lumetta, David E. Culler: The Mantis Parallel Debugger, Proceedings of SPDT'96: SIGMETRICS Symposium on Parallel and Distributed Tools. 3. TotalView Users Guide, Etnus, 2003, http://www.etnus.com/Download/TV.html. 4. Lastovetsky A.: Parallel Computing on Heterogeneous Networks, John Wiley & Sons, New Jersey, 2003, 159-254. 5. A.Lastovetsky, D.Arapov, A.Kalinov, and I.Ledovskih, "A Parallel Language and Its Programming System for Heterogeneous Networks", Concurrency: Practice and Experience, 12(13), 2000, pp.1317-1343. 6. Hood, R.: The p2d2 Project: Building a Portable Distributed Debugger. Proceedings of the 2nd Symposium on Parallel and Distributed Tools (SPDT'96). Philadelphia PA, USA, 1996. 7. Cownie, J., Gropp, W.: A standard interface for debugger access to message queue information in MPI. In Dongarra, J., Luque, E., Margalef, T., eds.: Recent Advances in Parallel Virtual Machine and Message Passing Interface. Volume 1697 of Lecture Notes in Computer Science., Berlin, Springer (1999) 51—58. 8. http://www-unix.mcs.anl.gov/mpi/mpi-debug/mpi_interface.h.html. 9. The MPI Standard version 1.1 June 12, 1995, http://www.netlib.org/mpi/mpi-1.1-report.ps
100
Обучение передовым технологиям разработки ПО: проблемы и методы их решения В. В. Кулямин, В. А. Омельченко, О. Л. Петренко
1. Введение В современном мире все больше задач в экономике, социальной и частной жизни людей решаются с использованием программного обеспечения (ПО). В связи с этим функциональность индустриально разрабатываемого ПО все больше усложняется, и вместе с тем возрастают требования к его надежности и другим показателям качества. Проблемы построения надежного ПО высокой сложности не могут быть решены без привлечения передовых методов его разработки, использующих последние достижения научной мысли. Однако внедрение подобных методов в промышленную практику сталкивается с целым рядом проблем, которые можно классифицировать следующим образом. 1. Проблемы исследовательского плана, связанные с принципиальной ограниченностью метода и возможностью использовать его только для разработки ПО, относящегося к определенным предметным областям, или построенного по архитектуре определенного вида. Решение таких проблем предполагает значительную модификацию метода с целью расширения его области применимости на новые классы ПО, и, обычно, требует большого объема исследовательских работ. 2. Проблемы технического характера, связанные с необходимостью привязки метода к технологиям и инструментам разработки, использующимся в организации, куда он внедряется. Проблемы такого рода обычно можно решить, разработав инструменты или дополнения к имеющимся инструментам, которые позволяют использовать рассматриваемый метод разработки из привычного персоналу организации окружения. 3. Проблемы организационного характера, связанные с необходимостью сочетать сложившиеся процессы разработки ПО и практику управления этими процессами с новым, нетрадиционным методом разработки. При использовании обычных форм управления и распределения труда, обычных метрик производительности такой метод часто снижает 101
эффективность производства или дает настолько парадоксальную его картину, что строить работу по ней большинство управленцев с традиционной подготовкой не способно. 4. Проблемы культурного плана возникают из-за повышенных, или просто отличающихся от традиционных, требований к персоналу, предъявляемых передовыми методами разработки ПО. При этом эффективное производство разлаживается как из-за неспособности имеющегося персонала справиться с новыми задачами, так и из-за неспособности менеджеров найти подходящий персонал в силу необычности требований к его знаниям и умениям. Данная статья предлагает подходы к решению проблем, относящихся к последним двум категориям напрямую связанных с проблемами внедрения. Технические и исследовательские аспекты передовых методов разработки ПО в ней рассматриваются лишь в контексте проблем внедрения новых методов в производство. С точки зрения преодоления проблем как организационного, так и культурного характера, существенным недостатком передовых методов разработки является большая трудоемкость их освоения, которая вызвана сложностью, внутренне присущей проблемам разработки сложного многоцелевого ПО, и недостаточной «обкатанностью» подобных методов на практике. Методы такого рода появляются на основе исследований, и их первоначальное представление обыч-но отличается большей абстрактностью изложения по сравнению с обычным уровнем, на котором привыкло работать большинство разработчиков ПО, и слабой привязкой к задачам, с которыми им постоянно приходится сталкиваться. Сложность передовых методов и трудность их освоения отталкивает многие организации от внедрения подобных подходов. Поэтому, успешное использование их на практике предполагает предварительное обучение пользователей и руководителей эффективному использованию этих методов и поддерживающих их инструментов. Руководителей приходится обучать также эффективным подходам к организации труда в соответствии с новыми реалиями, складывающимися в организации, использующей такие методы, и способам измерения производительности труда и других показателей, учитывающим специфику этих подходов. Обучение разного рода является практически единственным эффективным методом решения проблем организационного и культурного характера, с которыми приходится сталкиваться при внедрении передовых методов разработки, как в краткосрочном, так и в долгосрочном плане. Разные виды обучения включают следующие: 1. Обучение студентов ВУЗов по специальностям, связанным с разработкой ПО, как подготовка кадров для индустрии производства ПО.
102
2.
Обучение непосредственных пользователей инструментов, поддерживающих передовые методы разработки. 3. Обучение руководящего персонала методам эффективного управления проектами в новом окружении. 4. Обучение сотрудников организаций, отвечающих за модернизацию процессов разработки методам успешного внедрения рассматриваемых подходов. 5. Широкая пропаганда передовых методов, проведение открытых семинаров по ним для руководителей и технических специалистов. Примером передовых методов разработки ПО являются методы тестирования ПО на основе моделей, позволяющие эффективно контролировать качество промышленного ПО высокой сложности, чего практически невозможно добиться с помощью традиционных подходов. Несмотря на наличие такого важного преимущества внедрить такие методы не просто. При внедрении методов тестирования на основе моделей в индустриальные процессы разработки возникают те же проблемы, что и при внедрении большинства передовых методов разработки ПО. Данная статья представляет подход к обучению таким методам на примере технологии тестирования на основе моделей UniTesK, разработанной в группе верификации, спецификации и тестирования ИСП РАН (RedVerst, [1]). В статье излагается почти десятилетний опыт использования различных образовательных методов при обучении будущих тестировщиков, архитекторов, руководителей проектов, а также студентов ВУЗов передовым технологиям разработки тестов на основе моделей, полученный группой верификации, спецификации и тестирования ИСП РАН.
3.
4.
Заочное обучение: презентации, статьи, документация Эксперты (аналитики, менеджеры, архитекторы)
Инструменты
2. Цели обучения и его структура Конечной целью обучения будущих пользователей новой технологии является внедрение этой технологии в практику промышленного производства ПО. Для достижения этой цели необходимо учитывать интересы и различия в восприятии и оценках различных групп пользователей. 1. Студенты, получающие базовое теоретическое образование, которое они надеются с пользой применить на своем будущем месте работы. Для студентов крайне важно, чтобы полученные ими теоретические знания подкреплялись практическим опытом работы в реальных проектах, который им может обеспечить ИСП РАН, вовлеченный в академические и промышленные разработки. Наличие навыков использования знаний на практике позволит студенту в дальнейшем получить более интересную работу. 2. Тестировщики ПО, которые непосредственно после обучения должны будут использовать полученные навыки в конкретных проектах.
103
Проектировщики и архитекторы ПО, которые должны понять, каким образом данная технология влияет на их работу, что она потребует делать в дополнение к обычной практике, и как это отразится на свойствах результирующего продукта. Руководители проектов, которым необходимо ознакомиться с экономическими показателями технологии в различных типах проектов, понять, как должны быть изменены процессы разработки при использовании в них данной технологии, какие формы деятельности и документов она добавляет в процесс, а какие ранее использовавшиеся типы документов и виды деятельности становятся излишними, какие метрики надо применять для оценки состояния процесса и результирующего продукта.
Студенты Теоретический курс: лекции, семинары, самостоятельное выполнение заданий
Разработчики тестов, инженеры Тренинги: базовые, углубленные, по управлению проектами
Рис. 1. Общая структура обучения. Поскольку удовлетворить потребности всех лиц, затрагиваемых технологией, в рамках одного курса обучения практически невозможно, были разработаны следующие виды курсов, нацеленные на более узкие группы лиц:
104
1.
Теоретический курс по формальным методам разработки программ и их использованию в тестировании для студентов ВУЗов, дополненный серией практических занятий. 2. Базовые тренинги по использованию инструментов, поддерживающих технологию разработки тестов на основе моделей, для тестировщиков ПО. Для каждого инструмента требуется отдельный такой тренинг. 3. Углубленные тренинги по использованию инструментов, поддерживающих технологию разработки тестов на основе моделей, для проектировщиков и архитекторов ПО. 4. Тренинг по управлению проектами с использованием технологии разработки тестов на основе моделей для руководителей проектов. Можно использовать также заочный способ обучения, когда специалист изучает статьи, документацию и другие материалы, но при этом важно поддерживать активную связь с обучаемым, контролировать получение им необходимых знаний и навыков. Общая структура обучения показана на Рис. 1.
«Математические модели ПО, используемые в тестировании», «Спецификации и оракулы», «Проблемы построения тестовой последовательности». UniTesK — это технология тестирования на основе формальных спецификаций. Все инструменты семейства UniTesK используют общие методы описания (спецификации) функциональности тестируемого ПО и унифицированную архитектуру тестовой системы. Инструменты семейства отличаются друг от друга языком разработки ПО, для тестирования которого они предназначены. Это может быть C, C++, Java или C#. Основные шаги разработки тестов по технологии UniTesK представлены на следующем рисунке, подробнее об этой технологии см. [3,4].
Интерфейс ПО
3. Организация обучения 3.1. Теоретический курс
Требования к ПО
Требования к качеству тестирования
1
2
Спецификации 4
В учебном плане факультета ВМК МГУ им. Ломоносова есть курс «Формальные спецификации программ», который преподается студентам 4-го курса. Одной из важнейших целей данного курса является демонстрация современных достижений в области использования формальных методов при создании реального программного обеспечения. Для решения этой задачи, с одной стороны, необходимо было выбрать язык спецификаций, хорошо зарекомендовавший себя как инструмент при использовании в реальных проектах, и, с другой стороны, показать, как формальные методы могут использоваться в ходе всех фаз жизненного цикла программного обеспечения: от проектирования до внедрения ПО. Первая часть курса содержит теоретические лекции, которые позволяют студентам получить знания о формальных методах на основе изучения языка RSL. Затрагиваются следующие темы: Место формальных спецификаций в промышленной разработке ПО. Виды формальных спецификаций. Метод разработки RAISE (RAISE Development Method) и язык спецификаций RAISE (RAISE Specification Language, RSL) [2]. Вторая часть курса посвящена тестированию на основе моделей. В ней рассматриваются как общие подходы к такому тестированию, так и конкретный пример — технология разработки тестов UniTesK, разработанная в Институте системного программирования РАН в 1994-2000 годах. Теоретический материал этой части излагается в трех лекциях: 105
4 Медиаторы
Критерии покрытия
2
3
3
Тестовые сценарии 5 Автоматическая генерация
Тестовая система
Автоматическое выполнение тестов, их отладка и генерация отчетов
6 Тестовые отчеты
7
Ошибки
Оценка качества тестов
Рис. 2. Процесс разработки тестов по UniTesK. Особенностью курса можно считать большую практическую часть, в которой студенты сначала знакомятся со способами разработки формальных спецификаций на языке RSL, а затем с инструментами тестирования, используемыми в реальной практике (например, J@T). Студенты проходят практику в ИСП, где их включают в рабочие группы по проектам с выполнением конкретного задания. У каждого студента есть «наставник» в проекте, который помогает организовать реальную работу и получение конкретных результатов, поскольку, даже имея хорошую 106
теоретическую подготовку, с применением своих знаний на практике студенты обычно испытывают трудности. В дальнейшем полученные ими результаты находят отражение в курсовых и дипломных работах. После окончания курса студенты знают: Как используются математические модели при тестировании ПО; Как проектируются тестовые системы для сложного ПО; Как используется тестирование в промышленном производстве ПО; Как можно организовать автоматизированное тестирования разных видов ПО и умеют: Разрабатывать формальные спецификации функциональности ПО; Разрабатывать медиаторы, связывающие спецификации с реализацией целевой системы; Разрабатывать тестовые сценарии; Запускать разработанные тесты и проводить анализ результатов тестирования. Для углубленного изучения (по выбору студентов) проводится спецсеминар «Верификация и валидация программ». На пятом курсе Московского физико-технического института читается обзорный курс «Языки формальных спецификаций», который содержит следующие лекции: Место формальных спецификаций в промышленной разработке ПО; Виды формальных спецификаций; Абстрактные типы данных и их применение в спецификациях; Описание инвариантов, аксиом, пред- и постусловий — основа спецификаций; Моделирование с использованием языков формальных спецификаций, проверка согласованности моделей; Использование формальных спецификаций для тестирования программ. После окончания этого курса студенты знают, чем языки формальных спецификаций отличаются от языков программирования, умеют различать языки структурных и функциональных спецификаций, понимают принципы моделирования с использованием формальных спецификаций и их использование в тестировании. Поскольку курс запланирован как обзорный, то практической части в нем нет. Все перечисленные курсы разработаны сотрудниками ИСП РАН, имеющими уникальный многолетний опыт использования формальных спецификаций как для описания функциональности сложного промышленного ПО и анализа его свойств, так и для последующей разработки тестов на основе спецификаций. Некоторые из них являются ведущими мировыми специалистами по методам построения тестов на основе моделей. 107
Вторая часть курса «Формальные спецификации программ» распространяется в университетах Европы, Азии и Австралии под академической лицензией. Рассматриваемый подход к обучению студентов позволяет: Поддерживать хороший теоретический и практический уровень преподаваемых курсов; Быстро знакомить студентов с новейшими достижениями данной отрасли; Давать твердые практические навыки, применимые в реальной работе; Отбирать на ранних этапах обучения перспективных студентов для научной работы.
3.2. Обучающий тренинг Вести обучение тестировщиков, работающих в промышленных компаниях, занимающихся разработкой ПО, по аналогии с обучением студентов нельзя, так как основными требованиями к процессу обучения являются: короткий срок обучения (несколько дней) и гарантированный результат. Как способ обучения в этом случае, был выбран обучающий тренинг. Обучающий тренинг рас-сматривается как базовый курс, после прохождения которого человек уже может заниматься тестированием программ. С другой стороны, он является той основой, которая позволяет совершенствовать дальнейшее мастерство тестирования и грамотно использовать ко-верификационные процессы разработки. Коверификационный процесс [5] — это процесс разработки ПО, при котором одновременно с разработкой самого ПО разрабатываются средства проверки его корректности. Использование процессов такого вида является одним из перспективных подходов к созданию качественного программного обеспечения. Цель тренинга — выработка необходимых умений и навыков для разработки тестов на основе спецификаций по технологии UniTesK. Для быстрого и качественного усвоения навыков разработки тестов на основе моделей в основу обучающего тренинга были положены следующие принципы: 1. Тщательный отбор содержания обучения в соответствии с поставленными целями. 2. Выбор адекватных форм обучения. 3. Обучение слушателей в активном, деятельностном режиме. 4. Создание благоприятной образовательной среды [6]. Каждый из этих принципов определенным образом реализован в предлагаемом тренинге, что позволило сократить сроки обучения до 4-5 дней и давать гарантированные результаты обучения.
3.2.1. Отбор содержания Для отбора содержания используется метод генерализации учебного материала, при котором выделяется один или несколько основополагающих 108
принципов, которые многократно и всесторонне раскрываются в курсе с самых разных сторон. В данном случае такими принципами являются основные положения UniTesK: тестирование рассматривается как сопоставление свойств поведения тестируемого ПО свойствам модели, заданной формальными спецификациями; тестируемое ПО рассматривается как «черный ящик», т.е. оно тестируется как набор интерфейсов (операций, процедур, методов, структур данных и пр.), внутренняя организация которых, их реализация, алгоритмы работы не рассматриваются; спецификация задается в форме пред- и постусловий операций и инвариантов типов, задающих ограничения целостности данных; интерфейсы самого целевого ПО и его модели, заданной спецификациями, могут различаться как по структуре так и уровнем абстракции, связь между соответствующими интерфейсами задается специальными программными компонентами, называемыми медиаторами; UniTesK предлагает унифицированную архитектуру тестовой системы, эта архитектура предусматривает отдельные компоненты для генерации тестовых воздействий и для анализа поведения тестируемой системы; подсистема генерации тестовых воздействий разбита на два уровня: генерация входных тестовых данных для отдельных операций (итераторы значений параметров) и генерация последовательности вызовов операций (тестовой последовательности); в основе метода генерации тестовой последовательности лежит идея обхода некоторого конечного автомата, который строится на основе спецификаций операций и тестового сценария. Отобранное по этим принципам содержание обучения представляется в виде программы тренинга. На Рис. 3 приводится программа одного из разработанных нами тренингов по технологии CTesK, входящей в семейство UniTesK и предназначенной для тестирования программ, написанных на языке С. Получение знаний, перечисленных в этой программе, дает необходимую базу для усвоения следующих умений и навыков: 1. Тестирование функций, поведение которых не зависит от истории взаимодействия системы с окружением: выделение предусловия функции; выделение ветвей функциональности; выделение постусловия функции; выделение инвариантов типов; описание итерации параметров.
Программа курса по технологии тестирования CTesK Введение Назначение технологии тестирования CTesK. Понятия целевой программной системы, тестовой системы, результаты выполнения тестов. Архитектура теста в CTesK. Постоянные компоненты. Генерируемые компоненты. Компоненты, разрабатываемые вручную. Шаги разработки теста в CTesK. Разработка спецификаций, разработка медиаторов, разработка сценария, отладка, выполнение тестов. Тестирование на соответствие. Формальные требования. Критерии покрытия требований.
Спецификации функций целевой программной системы Спецификации функций, поведение которых не зависит от истории взаимодействия системы с окружением. Спецификации данных: определение модельных типов данных, инварианты типов. Спецификации функций: структура спецификации функции, пред- и постусловия, критерии покрытия. Спецификации функций, поведение которых зависит от истории взаимодействия системы с окружением. Спецификация данных: состояние системы, инварианты переменных состояния. Спецификации функций: пре- и пост- состояние; пресостояние в предусловии и критериях покрытия; пре- и пост- состояние в постусловии.
Медиаторы Связь спецификаций и реализации целевой системы. Структура медиаторов на SE C. Преобразования модельных типов в реализационные и обратно. Вычисление параметров для вызова целевых функций. Вычисление возвращаемого значения спецификации. Синхронизация состояния спецификации с состоянием реализации. Вычисление модельного состояния из реализационного (открытое реализационное состояние). Вычисление модельного состояния без доступа к реализационному (закрытое реализационное состояние).
Сценарии Сценарии для тестирования функций, поведение которых не зависит от истории взаимодействия системы с окружением. Структура сценария. Определение сценария с единственным состоянием. Итераторы параметров спецификаций функций. Процедуры инициализации и завершения теста. Сценарии для тестирования функций, поведение которых не зависит от истории взаимодействия системы с окружением. Определение сценария с множеством состояний, определенным в спецификациях. Определение сценария с обобщенным состоянием.
Отладка Шаги отладки тестовой системы. Добавляемые трассировки. Связь компонентов тестовой системы и спецификаций. Виды ошибок.
Инструменты разработки тестов Способы вызова инструмента. Входная/выходная информация. Опции в командной строке. Сообщения об ошибках.
Рис. 3. Программа тренинга по технологии CTesK. 109
110
2.
3.
Тестирование функций, поведение которых зависит от истории взаимодействия системы с окружением, не нуждающихся в факторизации: выделение предусловия функции; выделение ветвей функциональности; выделение постусловия функции; выделение инвариантов типов; выделение инвариантов переменных состояния; описание тестового состояния; описание итерации параметров. Тестирование функций, поведение которых зависит от истории взаимодействия системы с окружением, требующих факторизации: выделение предусловия функции; выделение ветвей функциональности; выделение постусловия функции; выделение инвариантов типов; выделение инвариантов переменных состояния; описание обобщенного состояния; описание итерации параметров; преобразование обобщенных параметров в параметры функций.
Управление деятельностью слушателей во время практикумов сводится к самостоятельному выбору последовательности шагов при решении задачи и самооценки ее выполнения. Последовательность шагов может быть составлена из следующего набора: Знакомство с заданием. Самостоятельное выполнение задания. Сравнение выполненного задания с контрольным вариантом. Изучение предлагаемого алгоритма выполнения задания. Знакомство с выполнением одного шага предлагаемого алгоритма. Разные последовательности шагов, которые могут быть составлены для выполнения конкретного задания представлены на Рис. 4. З наком ство с зад ание м
И зучение а л го р и тм а
С ам остоя тельное вы полнение
З наком ство с вы полнением ш а га
3.2.2. Выбор адекватных форм обучения Для тренинга основной формой обучения выбран метод «погружения». На протяжении всего курса обучения (4-5 дней) слушатели полный день заняты только в тренинге и не отвлекаются на на другие задачи. В тренинге предусмотрены следующие формы проведения занятий: 1. Традиционная лекция. Она предполагает работу лектора сразу со всей аудиторией в едином темпе и с общими задачами. Используется для сообщения нового теоретического материала. Этот теоретический материал используется в инструктивных лекциях, которые непосредственно предшествуют практическим работам. 2. Инструктивная лекция знакомит слушателей с технологией их предстоящей деятельности, с особенностями выполнения отдельных действий, способами работы, алгоритмами решения задач. Учитывая сложность изучаемого курса в инструктивных лекциях даются определения основным понятиям, структура понятий выделенной части предметной области и связи между ними. 3. Практикумы проводятся после изучения крупных разделов тренинга в форме самостоятельного выполнения практических работ, с возможностью обратиться за консультацией к тренеру. В данном курсе содержанием практических работ являются: написание спецификаций, разработка тестового сценария, запуск и отладка тестов. 111
С равнение с контр ол ьн ы м вар ианто м
1 -а я п о с л е д о в а т е л ь н о с т ь 2 -а я п о с л е д о в а т е л ь н о с т ь 3 -я п о с л е д о в а т е л ь н о с т ь
Рис. 4. Возможные последовательности выполнения практических заданий. 4.
Консультации специалистов (индивидуальная форма обучения) используются как сопутствующая форма обучения, направленная на разъяснение отдельных вопросов, а также углубленное изучение предмета.
3.2.3. Обучение в деятельностном режиме При выборе способа обучения учитывалось то, что участники тренинга по роду своей основной работы участвуют в различных проектах, которые требуют творческого мышления, коммуникационной и кооперативной активности. 112
Поэтому при прохождении тренинга решено было создать знакомую и привычную среду для работы. При активном способе обучения слушатели на всех этапах занятия включаются в активную познавательную деятельность, самостоятельно открывают для себя те знания, которые при традиционном подходе излагаются преподавателем без активного участия самого слушателя [7]. Известно, что при деятельностном режиме обучения усваивается от 75% до 90% материала. (Для сравнения: при прочтении традиционной лекции усваивается около 20% изложенного [8]). Для реализации такого подхода используются следующие приемы работы: 1. Работа с рабочими материалами (портфолио) для самостоятельного отслеживания освоения учебного предмета и формулировки возникающих вопросов. Применялась на лекциях как форма организации индивидуальной работы слушателей. 2. Организация групповой работы на лекциях. Использовалась для обсуждения поставленных проблем, принятия решений и для определения в конце учебного дня общих невыясненных вопросов [9]. 3. Индивидуальная система практических заданий, которая позволяет каждому слушателю построить собственную траекторию освоения практической части курса. 4. Применение на лекциях опережающих заданий, в рамках которых слушателям предлагается найти решение проблемы в процессе индивидуальной работы, обсуждения в парах или группах еще до получения основного материала курса по заданной теме, после чего организуется дискуссия по предложенной проблеме, а после получения нового материала проводится анализ её хода и результатов. 5. Использование одной из базовых моделей активного обучения: вызовосмысление-рефлексия. Вызов — процесс актуализации знаний слушателей по данному вопросу и формирование интереса к его изучению. Осмысление — получение новой информации или идей. Рефлексия — стадия включения нового знания в собственную систему знаний. В качестве вызова, например, используется первая традиционная лекция, в которой актуализируются имеющиеся знания и формируются «зоны непонимания», которые будут ликвидироваться в процессе последующего обучения. Вызов подготавливает, настраивает на ту информацию и на тот процесс, которые будут излагаться на следующих этапах работы. Этап осмысления предполагает предоставление новой информации. Осознание нового осуществляется только в активной деятельности познающего, поэтому создаются специальные условия для активного включения слушателя в процесс усвоения новой информации. Хорошо зарекомендовали себя два
приема работы: INSERT (разметка текста и занесение результатов чтения в специальную таблицу) и «Зигзаг1» [14]. Рассмотрим пример работы с приемом «Зигзаг1». Текст инструктивной лекции «Тестирование функций, поведение которых зависит от истории взаимодействия системы с окружением, с обобщением состояния» разбивается на число частей, равное числу малых групп в аудитории*. Каждая группа получает одну часть текста и задание представить его в форме рисунка или схемы. Затем каждая группа представляет свой рисунок аудитории и отвечает с его помощью на возникающие вопросы. После представления работы каждой группы все слушатели получают весь текст лекции. Полнота восприятия информации в данном случае обеспечивается за счет неоднократного прочтения предложенного текста и представления его в другой форме (резко отличающейся от первоначальной), что позволяет задействовать разные каналы восприятия информации у человека [10]. На Рис. 5 и Рис. 6 показаны две формы представления одной и той же информации при перекрестном чтении текста. Кроме того, для корректной работы обходчика требуется, чтобы при всех вызовах любой целевой функции группы с одними и теми же параметрами в одном и том же состоянии система переходила в одно и то же состояние (требование детерминированности). Но группа функций с состоянием, определенным в спецификациях, не всегда обладает этим свойством. Эти проблемы решаются при помощи введения отношения эквивалентности на множестве состояний системы. Каждый класс эквивалентных состояний, порождаемый данным отношением эквивалентности, называется обобщенным состоянием. Использование обобщенных состояний вместо обычных состояний системы позволяет обходчику сократить количество необходимых шагов тестирования до разумных размеров, а также избавиться от недетерминированности. С другой стороны, за это приходится расплачиваться некоторым снижением подробности тестирования: вместо тестирования каждой функции в каждом достижимом состоянии системы, обходчик будет тестировать каждую функцию в каждом достижимом обобщенном состоянии. Под тестированием функции в обобщенном состоянии системы понимается последовательность вызовов этой функции в тот момент, когда система находится в некотором состоянии, принадлежащем данному обобщенному состоянию. При этом, как и в случае с обычными состояниями, обходчик вызывает каждую функцию с такими наборами параметров, чтобы в каждом состоянии попасть во все допустимые в нем ветви функциональности данной функции.
Рис. 5. 1-ая форма. Часть текста, предложенная группе.
*
113
Заметим, что с материалом этой лекции слушатели еще не знакомились.
114
Заключительным этапом в каждом блоке является рефлексия. Рефлексия состоит в осознании способов деятельности, обнаружении ее смысловых особенностей и выявлении образовательных приращений обучающегося. Использовались следующие формы рефлексии: Устное обсуждение с экспертами и обучающимися. Письменное анкетирование. Заполнение рабочих материалов (портфолио).
Рис. 6. 2-ая форма. Графическое изображение этого же текста, сделанное группой.
Основная составляющая деятельностного освоения технологии — это поэтапное выполнение специальных учебных заданий. Успешность упражнений достигается при следующих основных психологических условиях: Каждое упражнение должно иметь конкретно определенную цель — чему учащийся должен научиться и как он может проверить это. Знания, которые должны осваиваться в упражнении, а также техника его выполнения и предлагаемая последовательность действий должны быть ясно и четко представлены в предоставляемом учащемуся материале. Правила выполнения действий, которым нужно научиться, должны осваиваться предварительно, до выполнения задания. Задания должны выполняться многократно в целях достижения все возрастающей точности и быстроты выполнения действий, являющихся предметом обучения. Хода и результаты действий учащегося должны подвергаться постоянному самоконтролю, а также должны управляться и контролироваться преподавателем. Все эти психологические условия создаются при проведении упражнений, которые должны включаться в обучение постепенно, в несколько этапов. Для этого была разработана четырехуровневая система упражнений. Ознакомительное задание
3.2.4. Создание благоприятной образовательной среды Создание благоприятной образовательной среды — это одна из основных задач тренера. Этой задачей он занимается постоянно и для ее решения используются: вводное занятие; обратная связь в конце каждого дня; адаптация тренинга к конкретной аудитории; учет индивидуальных стилей обучения [11]. Цели вводного занятия: познакомиться с обучаемыми и дать им возможность познакомиться между собой; составить портрет аудитории; сделать презентацию курса; ознакомить обучаемых с программой курса; объяснить работу с портфолио; объяснить принципы обратной связи; создать благоприятную обстановку для работы. 115
Пробное упражнение
Основное упражнение
Тренировочное задание
Рис. 7. Система практических заданий тренинга.
116
Ознакомительное упражнение проводится с целью создания ясных представлений о правильной последовательности действий путем ее показа слушателям на примере и мысленного воспроизведения ими предстоящих действий. Ознакомительное упражнение выполняет тренер во время инструктивной лекции и, тем самым, дает слушателям первые сведения о предстоящей работе. Пробное упражнение проводится для усвоения правильной последовательности действий. После ознакомительного упражнения, когда у слушателя сложится ясное представление о всем процессе работы, в пробном упражнении слушатель пробует выполнить его самостоятельно. Пробные упражнения выполняются до их безошибочного выполнения. Пробное упражнение является репродуктивным и проводится для отработки одного навыка, показанного и теоретически обоснованного в ознакомительном задании. Пробное задание может быть только учебным и должно отрабатывать навык в ситуации, которая на практике не встречается. Когда навык освоен, можно переходить к следующему уровню заданий. Основное упражнение проводится с целью использования нескольких частных навыков для решения некоторой задачи. Основное упражнение строится по принципу добавления одного вновь полученного навыка ко всем предыдущим. Поэтому во время прохождения курса сложность и объем основных упражнений возрастает, так как вновь полученные навыки добавляются к уже освоенным. Тренировочные упражнения наиболее приближены к реальной практике. Они основаны на использовании полученных навыков в ситуациях, не всегда повторяющие учебные упражнения. Тренировочные упражнения применяются с целью закрепления навыков, умений и развития способностей к выполнению задач в реальных условиях. Заключительным этапом работы является выполнение учебного проекта. Цель проекта — написать тестовую систему для реальной программы. Работа выполняется малой группой под руководством одного из членов группы. Предложенный подход был использован при разработке следующих тренингов: инструмент тестирования CTesK [12]; инструмент тестирования J@T [13]; инструмент тестирования J@T-C++Link [13]; инструмент тестирования Ch@se; инструмент для создания генераторов тестов для автоматического тестирования анализирующих и оптимизирующих модулей компиляторов ОТК. Участники тренингов имели общую математическую подготовку в объеме ВУЗа, знание базового для технологии языка программирования, соответственно, С или Java, опыт разработки, отладки, тестирования программ. 117
Перед началом одного из тренингов его участники высказали следующие ожидания от курса: «Овладение технологией тестирования в объеме ее дальнейшего доосмысления и использования» Дмитрий М. «Прослушать курс по технологии тестирования. Получить возможность посмотреть, что это такое на реальном проекте, оценить, насколько ее можно использовать» Елена С. Итоговые оценки курса: «Тренинг достиг своей цели. После него я реально представляю как и где можно использовать инструмент тестирования» Дмитрий М. «Мне курс понравился. Результат — это получение некоторого представления о технологии тестирования. Технология интересная, ее стоит внедрять на предприятиях и использовать». Елена С.
4. Заключение Описанная методика была реализована при разработке тренингов по всем инструментам семейства UniTesK: CTesK [12], J@T, J@T-C++ link [13], Ch@se, OTK. Тренинги проводились в следующих организациях: Lanit-Tercom (Санкт-Петербург, Россия); Systematic Software Engineering (Оденсе, Дания); ГосНИИАС (Москва, Россия); Saarland University (Саарбрюкен, Германия); ATS India (Ченнай, Индия); Luxoft (Москва, Россия); Intel Technologies Inc. (Нижний Новгород, Россия), а также в исследовательских группах ИСП РАН и в Московском Государственном университете. Опыт показал, что большая часть слушателей полностью справляется с поставленными задачами и овладевает инструментами в такой степени, что сразу после тренинга может его использовать самостоятельно, практически без консультаций с экспертами. Из трудностей, которые еще предстоит преодолеть, можно назвать проблему стартовой фазы тренинга, в течение котор ой аудиторию приходится настраивать на активные методы обучения, что многим, привыкшим к академическому формату, дается с большим трудом. Проблемой является и длительность тренинга. Хотя сейчас удалось сократить длительность обучения с 2-3 месяцев до 4-5 дней — это все равно много для большинства коммерческих 118
компаний. В дальнейшем для решения этой проблемы предполагается разбить тренинг на части и выделить специальные блоки, адресованные разным целевым группам: менеджерам, архитекторам, разработчиками ПО, тестировщикам и т.д. Разработанные способы обучения в тренинге возможно использовать и в университетских курсах. Из-за большого числа студентов на лекции применение активных методов работы, которые требуют обсуждений в группах, высказывания каждым студентом своего мнения, защиты проектов, весьма ограничены. Практикум можно полностью заимствовать из тренингов для промышленных предприятий, что обеспечивает хорошее и быстрое усвоение материала и получение практических навыков тестирования. Такая организация практических занятий также учит студентов самостоятельно принимать решения на основе анализа многих факторов. Опыт общения группы RedVerst с потенциальными и действительными пользователями технологии UniTesK показывает, что успешное внедрение передовых методов разработки ПО, в особенности основанных на формальных методах и других техниках, доступных обычно для людей с университетским математическим образованием и серьезными навыками оперирования абстрактными сущностями, требует повышенного внимания именно к организационным и общекультурным аспектам их использования в индустрии. Наш опыт взаимодействия с разработчиками ПО и тестов, работающими в разного рода организациях, производящих ПО, показал необходимость использования различных форм обучения для решения различных задач, возникающих при внедрении. Для подготовки кадров можно использовать традиционные академические курсы, подкрепленные практической работой по изучаемым технологиям на примерах реального ПО. Для эффективного обучения конечных пользователей больше подходят обучающие тренинги, основанные на активном подходе к обучению и полной погруженности учащихся в тренинг. Для обучения руководителей нужны специальные тренинги, дающие навыки управления проектами, работы в которых ведутся по новым технологиям, предлагающие наборы метрик, лучше традиционных подходящие для оценки состояния процесса разработки, готовности и качества результирующего продукта. Кроме того, необходимы особые формы краткосрочных тренингов, презентаций, учебных пособий и вспомогательных материалов для широкой пропаганды передовых методов разработки ПО и создания условий для их более осмысленного усвоения промышленностью. Хотя остается много открытых вопросов, связанных с выбором конкретных форм обучения, наиболее подходящих в том или ином случае, для специализированных тренингов руководителей разного уровня, в целом рассмотренный подход, использующий обучение для решения проблем организационного и культурного плана, возникающих при внедрении передовых методов разработки ПО в индустриальное производство, продемонстрировал свою эффек119
тивность. Нет сомнений и в том, что этот успех не является особенностью технологии UniTesK, которая была выбрана в качестве предмета обучения. Литература 1. http://www.ispras.ru/groups/rv/rv.html 2. The RAISE Language Group. The RAISE Specification Language. Prentice Hall Europe, 1992. 3. В. В. Кулямин, А. К. Петренко, А. С. Косачев, И. Б. Бурдонов. Подход UniTesK к разработке тестов. Программирование, 29(6), 2003. 4. А. Баранцев, И. Бурдонов, А. Демаков, С. Зеленов, А. Косачев, В. Кулямин, В. Омельченко, Н. Пакулин, А. Петренко. Подход UniTesK к разработке тестов: достижения и перспективы. Труды ИСП РАН, №5, 2004. 5. http://www.ispras.ru/groups/rv/tutorial.html 6. Хуторской А. В. Современная дидактика. Питер, 2001. 7. Педагогика. Педагогические теории, системы, технологии. Под ред. С. А. Смирнова. Москва, 2000. 8. J. Hartley and I. K. Davies. Note-taking: A critical review. Programmed Learning and Educational Technology, 15, 207-224 (1978). 9. Л. Рай. Упражнения: схемы и стратегии. Пер. с анг. Питер, 2003. 10. Петренко О. Л., Прокофьева Л. Б. и др. Технологии открытого обучения. Москва, 2002. 11. К. Торн, Д. Маккей. Тренинг. Настольная книга тренера. Пер. с анг. Питер, 2001. 12. http://www.unitesk.com 13. http://www.atssoft.com 14. Ученик и учитель: возможность диалога и понимания. Сборник статей, составители Е.А. Генике, Е.А. Трифонова, т. 1, Москва, 2002 г. 15. D.W. Johnson, R.T. Johnson, and K.A. Smith, Active Learning: Cooperation in the College Classroom, 2nd Edn., Edina, MN, Interaction Book Company, 1998.
120
Подход UniTesK к разработке тестов: достижения и перспективы А.В. Баранцев, И.Б. Бурдонов, А.В. Демаков, С.В. Зеленов, А.С. Косачев, В.В. Кулямин, В.А. Омельченко, Н.В. Пакулин, А.К. Петренко, А.В. Хорошилов Аннотация. Данная статья излагает базовые принципы технологии разработки тестов UniTesK, основанной на использовании формальных моделей тестируемого программного обеспечения (ПО). Кроме того, излагается опыт использования этой технологии для тестирования ПО разных видов, описываются проблемы внедрения в промышленность, свойственные всем технологиям, основанным на формальных методах, и формулируются возможные пути их решения. Технология UniTesK была разработана в группе спецификации, верификации и тестирования [RedVerst] ИСП РАН на основе многолетнего опыта проведения проектов верификации и тестирования сложного промышленного ПО. Статья содержит материал, который заинтересует как исследователей в области формальных методов, так и практиков, которые хотели бы ознакомиться с потенциалом тестирования на основе моделей в реальных крупномасштабных приложениях. Читателям из последней группы рекомендуется после разделов «Основные принципы UniTesK» и «Процесс построения тестов по UniTesK» перейти к разделу «Опыт использования UniTesK», а затем выбрать те разделы, которые покажутся им интересными.
1. Введение В настоящее время промышленное производство программного обеспечения (ПО) достигло таких масштабов и такой степени сложности, что необходимость в индустриально применимых технологиях систематического тестирования общепризнана. Особенно актуальным является создание таких технологий, которые обеспечивают одновременно качественное, систематическое тестирование целевого ПО и высокую степень автоматизации разработки тестов. Традиционные методы разработки тестов вручную уже не могут обеспечить качественное тестирование современных программных систем. Обычно автоматизация тестирования сводится к автоматизации выполнения тестов и генерации отчетов по их результатам. Автоматизировать подготовку тестов и анализ полученных результатов труднее, поскольку при этом необходимо обращение к требованиям к ПО, соответствие которым, должно быть проверено во время тестирования. Требования же часто представлены в 121
виде неформальных документов, а иногда — только как знания и опыт экспертов, аналитиков и проектировщиков ПО. Для того, чтобы вовлечь требования в автоматизированный процесс разработки тестов, необходимо перевести их в формальное представление, которое может быть обработано полностью автоматически. Для этой цели требования описывают в виде формальных спецификаций целевой системы, которые можно преобразовать в программы, выполняющие проверку соответствия работы целевого ПО зафиксированным в них требованиям. Несмотря на активное развитие методов построения тестов на основе формальных спецификаций или формальных моделей в академическом сообществе, лишь немногие из них оказываются применимыми в индустрии производства ПО. Основная проблема здесь в том, что индустрии нужны не отдельные методы, а технологии, т.е. инструментально поддержанные системы методов для решения наборов связанных задач, относящихся к выделенному аспекту разработки ПО. Данная статья представляет описание технологии UniTesK, которая была разработана в ИСП РАН на основе опыта нескольких проектов по верификации сложного промышленного ПО и нацелена на то, чтобы сделать возможным использование передовых методов тестирования в контексте индустриального производства ПО. UniTesK в первую очередь предназначена для разработки функциональных тестов на основе моделей требований к функциональности целевой системы. Проблемы построения тестов для проверки нефункцио-нальных требований выходят за рамки данной работы. Структура статьи такова. Следующий за введением раздел содержит описание основных элементов технологии UniTesK, начиная с общего обзора ее базовых принципов и дальше раскрывая некоторые из них в деталях. В третьем разделе проводится сравнение UniTesK с другими подходами к разработке тестов на основе моделей. В четвертом разделе кратко описываются примеры приложений UniTesK и опыт использования этой технологии для тестирования промышленного ПО. В заключении рассматриваются направления дальнейшего развития этой технологии.
2. Описание технологии UniTesK 2.1. Основные принципы UniTesK Технология построения тестов для ПО общего назначения становится пригодной для широкого использования в промышленной практике, только когда она обладает следующими характеристиками. Во-первых, все определяемые ею операции, где это возможно, должны поддерживаться инструментами. Во-вторых, она должна обладать широким набором функций, позволяющим использовать ее в проектах, имеющих различные цели, для тестирования ПО из разных предметных областей и построенного с 122
использованием различных архитектур и технологий. И, наконец, она должна достаточно хорошо интегрироваться с имеющимися процессами разработки, в частности, быть основана на системе понятий и обозначений, достаточно простой и широко используемой, чтобы не требовать долгой и дорогой переподготовки персонала. Для обеспечения таких характеристик при разработке UniTesK были предложены следующие решения. 1. Для обеспечения максимальной гибкости технологии, была спроектирована универсальная архитектура теста, определяющая набор компонентов теста с ясным разделением функций и четкими интерфейсами, так, чтобы большое многообразие различных видов тестов для разных программ можно было реализовать в ее рамках. 2. Чтобы сделать возможной значительную степень автоматизации, в рамках полученной архитектуры вся информация, которая может быть предоставлена только человеком, сконцентрирована в небольшом числе компонентов. Все остальные компоненты теста генерируются автоматически или используются во всех тестах в неизменном виде. Во многих случаях все изменяемые компоненты теста, кроме спецификаций, определяющих критерии корректности ПО, могут быть сгенерированы интерактивно, на основе ответов пользователя на ряд четко поставленных вопросов. 3. В качестве метамодели для представления функциональных спецификаций, моделирующих требования, был выбран широко известный подход на основе программных контрактов (Design by Contract [DBCA,DBCO,DBCE]), состоящих из предусловий и постусловий интерфейсных операций и инвариантов типов данных. Программные контракты, с одной стороны, достаточно удобны для разработчиков ПО, поскольку хорошо привязываются к архитектуре ПО, с другой стороны, в силу своего представления стимулируют усилия по созданию независимых от реализации критериев корректности целевой системы. Основное же их преимущество в том, что они позволяют автоматически построить оракулы [Parnas,KVEST,ADLt], проверяющие соответствие поведения целевой системы спецификациям, и критерии тестового покрытия, которые достаточно близки к критериям покрытия требований. 4. Практически невозможно обеспечить универсальный механизм построения единичных тестовых воздействий (например, вызовов операций с разными наборами аргументов), который был бы достаточно эффективен как по времени, затраченному на тестирование, так и с точки зрения достижения высокого тестового покрытия. В то же время, довольно просто построить итератор, перебирающий большое множество значений некоторого типа. Инструменты, поддерживающие UniTesK, предоставляют пользователям библиотеки базовых итераторов значений простых типов, которые могут быть непосредственно использованы для генерации тестовых воздействий, 123
5.
6.
7.
8.
а могут быть скомпонованы в более сложные генераторы. Для уменьшения затрат времени на тестирование сгенерированные тестовые воздействия можно фильтровать, отбрасывая те и них, которые не увеличивают достигнутый уровень покрытия. Фильтры для этого генерируются автоматически из определения критерия тестового покрытия (см. пункт 6). Для автоматического построения последовательности тестовых воздействий используются модели тестируемой системы в виде конечных автоматов (КА). Тестовая последовательность строится как последовательность обращений к целевым операциям, соответствующая некоторым путям в графе переходов КА, например, обходу всех переходов автомата. Поскольку конечно-автоматная модель используется только для построения тестовой последовательности, а не для проверки корректности поведения целевой системы, осуществляемой оракулами, можно не задавать автомат полностью, а лишь указать способ идентификации его состояний и способ итерации входных воздействий в зависимости от текущего состояния. Представленные таким, неявным, образом автоматы удобно задавать в виде тестовых сценариев. Часто тестовый сценарий можно сгенерировать автоматически на основе спецификации целевых операций, способа итерации наборов их аргументов и стратегии тестирования. Стратегия тестирования определяет, когда тестирование можно заканчивать. UniTesK предлагает при этом опираться на достигнутый уровень тестового покрытия в соответствии с некоторым критерием покрытия. Из структуры спецификаций, разработанных в соответствии с технологией UniTesK, можно автоматически извлечь несколько таких критериев. Пользователь имеет возможность гибко управлять этими критериями или определять свои собственные. Чтобы обеспечить более удобную интеграцию в существующие процессы разработки, UniTesK может использовать для представления спецификаций и тестовых сценариев расширения широко используемых языков программирования, построенные на основе единой системы понятий (хотя классические языки формальных спецификаций тоже могут использоваться). Такое представление делает спецификации и сценарии понятнее для обычного разработчика ПО и позволяет сократить срок освоения основных элементов технологии до одной недели. Сразу после этого обучения разработчик тестов может использовать UniTesK для получения практически значимых результатов. Кроме того, использование расширений известных языков программирования вместо специального языка значительно облегчает интеграцию тестовой и целевой систем, необходимую для проведения тестирования. На данный момент в ИСП РАН разработаны инструменты, поддерживающие работу по технологии UniTesK с использованием расширений Java, C и C#. Спецификации на основе программных контрактов в рамках технологии UniTesK могут использоваться не только как вставки в исходный код
124
целевой системы. Они могут быть отделены от целевого кода и использоваться в неизменном виде для тестирования различных реализаций одной и той же функциональности, таким образом представляя собой формализацию функциональных требований к ПО. Для определения связи между спецификациями и конкретной реализацией используются специальные компоненты, медиаторы, которые могут осуществлять довольно сложные преобразования интерфейсов. Использование медиаторов открывает дорогу следующим возможностям. Спецификации могут быть гораздо более абстрактными, чем реализация, и, тем самым, более близкими к естественному представлению функциональных требований. Спецификации остаются актуальными для нескольких версий целевого ПО. Для переработки тестового набора под новую версию, в которой изменились внешние интерфейсы, но не их функции, достаточно заменить медиаторы. Во многих случаях такая замена может быть автоматизирована. Становится возможным широкое переиспользование спецификаций и тестов, которое значительно повышает отдачу от вложенных в их разработку ресурсов. При использовании технологии UniTesK в специфической области зачастую бывают нужны не все техники построения тестов из набора входящих в технологию, и не все компоненты из универсальной архитектуры теста бывает необходимо строить. А в некоторых случаях использование каких-то техник невозможно или требует слишком больших затрат. Тем не менее, в этих случаях можно использовать специализированные варианты технологии и поддерживающие их инструменты. Например, при тестировании блоков оптимизации в компиляторах разработка спецификаций функциональности такого блока в полном объеме, если и возможна, то очень трудоемка, поскольку они должны, например, выражать тот факт, что оптимизация программы действительно была проведена. В то же время, сравнить быстродействие и проверить неизменность функциональности тестовых программ специального вида довольно легко, выполняя их на конечном наборе входных значений, что дает способ построения оракулов, хотя и не столь общий, как описанный выше, но достаточный для практических целей [OPT].
2.2. Универсальная архитектура теста Гибкость технологии или инструмента, возможность использовать их в большом многообразии различных ситуаций и контекстов, определяется, в первую очередь, лежащей в основе данной технологии или данного инструмента архитектурой. Архитектура теста, используемая в UniTesK проектировалась на основе опыта проведения тестирования сложного промышленного ПО. Она нацелена на решение двух основных проблем. 125
Невозможно полностью автоматизировать разработку тестов, поскольку критерии корректности целевого ПО и стратегии проведения тестирования может предоставить только человек. Тем не менее, очень многое может и должно быть автоматизировано. Выбранная архитектура должна совмещать единообразие с возможностью тестирования ПО, относящегося к разным предметным областям, и в проектах, решающих различные задачи. Основная идея архитектуры теста UniTesK состоит в том, что разрабатывается набор компонентов, пригодный для тестирования различных видов ПО с использованием разных стратегий тестирования. Эти компоненты должны иметь четко определенные обязанности в системе и интерфейсы для взаимодействия друг с другом. Далее, информация, которую в общем случае может предоставить только разработчик тестов, концентрируется в небольшом числе компонентов с четко определенными ролями. Для каждого такого компонента разрабатывается компактное и простое представление, создание которого потребует минимальных усилий со стороны пользователя. Архитектура теста UniTesK [UniArch] основана на следующем разделении задачи тестирования на подзадачи: 1. Задача проверки корректности поведения системы в ответ на единичное воздействие 2. Задача создания единичного тестового воздействия 3. Задача построения последовательности таких воздействий, нацеленной на достижение нужного покрытия 4. Задача установления связи между тестовой системой, построенной на основе абстрактного моделирования, и конкретной реализацией целевой системы Для решения каждой из этих задач предусмотрена технологическая поддержка. Для проверки корректности реакции целевого ПО в ответ на одно воздействие используются тестовые оракулы. Поскольку генерация тестовых воздействий отделена от проверки реакции системы на них, нужно уметь оценить поведение системы при достаточно произвольном воздействии. Для этого не подходит распространенный способ получения оракулов, основанный на вычислении корректных результатов для фиксированного набора воздействий. Используются оракулы общего вида, основанные на предикатах, связывающих воздействие и ответную реакцию системы. Такие оракулы легко строятся из спецификаций программного контракта в виде пред- и постусловий интерфейсных операций и инвариантов типов, формулирующих условия целостности данных [KVEST,ADLt]. При таком подходе каждое возможное воздействие моделируется как обращение к одной из интерфейсных операций с некоторым набором аргументов, а ответ системы на него — в виде результата этого вызова. Далее будут более детально 126
рассмотрены специфика моделирования асинхронных реакций целевой системы и используемые техники специфицирования. Единичные тестовые воздействия строятся при помощи механизма перебора операций и итерации некоторого широкого множества наборов аргументов для фиксированной операции, которые дополняются фильтрацией полученных наборов по критерию покрытия, выбранному в качестве цели тестирования. Для тестирования ПО со сложным поведением, зависящим от предшествующего взаимодействия ПО с его окружением, недостаточно набора единичных тестовых воздействий. При тестировании таких систем используют последовательности тестовых воздействий, называемые тестовыми последовательностями и построенные таким образом, чтобы проверить поведение системы в различных ситуациях, определяемых последовательностью предшествовавших обращений к ней и ее ответных реакций. Для построения последовательности тестовых воздействий используется конечно-автоматная модель системы. Конечные автоматы достаточно просты, знакомы большинству разработчиков и могут быть использованы для моделирования практически любой программы. Для тестирования параллелизма или распределенных систем используется разновидность автоматов ввода/вывода [IOSMA], в которых переходы помечаются только входным или только выходным символом. Итоговый конечный автомат представлен в виде итератора тестовых воздействий. Этот компонент имеет интерфейс для получения идентификатора текущего состояния, получения идентификатора очередного воздействия, допустимого в данном состоянии, и для выполнения воздействия по его идентификатору. Подробнее об используемых автоматных моделях для тестирования параллелизма можно прочитать в [AsSM]. Тестовая последовательность строится во время тестирования динамически, за счет построения некоторого "исчерпывающего" пути по переходам автомата. Это может быть обход всех его состояний, всех его переходов, всех пар смежных переходов и т.п. Алгоритм построения такого пути на достаточно широком классе автоматов оформлен в виде другого компонента теста, обходчика. Удобное для человека описание используемой при тестировании конечноавтоматной модели мы называем тестовым сценарием. Из тестового сценария генерируется итератор тестовых воздействий. Сценарии могут разрабатываться вручную, но для многих случаев достаточно сценариев, которые можно получить автоматически на основе набора спецификаций операций, указания целевого критерия покрытия, способа итерации параметров операций и способа вычисления идентификатора состояния. Более детально методы построения тестовых последовательностей рассматриваются ниже, в соответствующем подразделе. Обходчики нескольких разных видов предоставляются в виде библиотечных классов, и пользователю нет нужды разрабатывать их самому. 127
Для того, чтобы использовать в тестировании спецификации, написанные на более высоком уровне абстракции, чем сама целевая система, UniTesK предоставляет возможность использовать медиаторы. Медиатор задает связь между некоторой спецификацией и конкретной реализацией соответствующей функциональности. При этом он определяет преобразование модельных представлений воздействий (вызовов модельных операций) в реализационное, и обратное преобразование реакций целевой системы в их модельное представление (результат, возвращаемый модельной операцией). Медиаторы удобно разрабатывать в расширении целевого языка, где описывать только сами перечисленные преобразования. Требуется дополнительная обработка полученного кода, поскольку помимо своих основных функций медиатор выполняет дополнительные действия, связанные со спецификой среды реализации и с трассировкой хода теста. Код этих действий автоматически добавляется к процедурам преобразования стимулов и реакций, описанным пользователем.
Рис. 1. Архитектура теста UniTesK. Рис. 1 представляет основные компоненты архитектуры теста, используемой UniTesK. В дополнение к этим компонентам тестовая система содержит несколько вспомогательных, отвечающих за трассировку хода тестирования, своевременную синхронизацию состояний между модельными и реализа128
ционными объектами, и пр. Эти вспомогательные компоненты не зависят от тестируемого ПО и выбранной стратегии тестирования.
2.3. Процесс построения тестов по UniTesK В приведенной ниже таблице процесс разработки спецификаций и тестов и собственно тестирования в UniTesK представлен как последовательность шагов. На практике, конечно, бывает необходимо вернуться к ранее пройденным шагам и пересмотреть уже принятые решения, но общая логика процесса — это движение от требований к получению тестов и анализу результатов тестирования. 1. Анализ функциональных требований к целевому ПО на основе имеющихся документов или знаний участников проекта, запись требований в виде формальных спецификаций.
4. Привязка полученных тестовых сценариев к конкретной реализации целевой системы. Для этого надо разработать набор медиаторов.
Спецификации
Интерфейс ПО
Медиаторы 5. Получение готовой к исполнению тестовой программы. Для того нужно оттранслировать спецификации, медиаторы и сценарии с расширения языка программирования в целостную тестовую систему на целевом языке программирования и скомпилировать ее.
Требования
Спецификации
Тестовые сценарии Спецификации
Медиаторы
Автоматическая генерация
Тестовая система
2. Формулировка требования к качеству тестирования — какой уровень тестового покрытия будет считаться достаточным, чтобы прекратить тестирование.
6. Выполнение тестовой программы, возможно, отладка спецификаций, медиаторов и тестовых сценариев.
Требования к качеству тестирования
Тестовые отчеты
7. Анализ результатов, а именн,о анализ полноты тестового покрытие и принятие решения и продолжении или прекра-щении тестирования. Оформ-ление описания ошибок.
Критерий покрытия Спецификации
Целевое ПО
Тестовая система
Автоматическое выполнение тестов и генерация отчетов
Спецификации
3. Разработка набора тестовых сценариев, обеспечивающего достижение нужного уровня покрытия. Сценарии разрабатываются на основе спецификаций и не привязаны к конкретной реализации целевого ПО или его конкретной версии.
Целевое ПО
Критерий покрытия
Тестовые отчеты
Ошибки
Тестовые сценарии
129
130
Оценка качества тестов
Представленная ниже, на Рис. 2, схема показывает процесс получения основных компонентов архитектуры тестового набора по технологии UniTesK.
Рис. 2. Получение компонентов теста по UniTesK. Теперь рассмотрим действия, которые нужно предпринимать на разных шагах технологии более подробно.
2.4. Описание функциональных требований UniTesK поддерживает автоматическую генерацию тестовых оракулов из спецификаций в виде программных контрактов. При использовании такого способа описания функциональности целевой системы, она моделируется как набор компонентов, каждый из которых имеет несколько интерфейсных операций с некоторыми параметрами. Окружение системы может вызывать интерфейсные операции и получать результаты их работы. Эти результаты определяются вызванной операцией, ее аргументами и историей взаимодействий системы с ее окружением, предшествовавших данному. Существенная информация об истории моделируется как внутреннее состояние компонентов целевой системы. Таким образом, поведение операций, вообще говоря, зависит от внутреннего состояния и может его менять. Каждая операция описывается при помощи предусловия и постусловия. Предусловие определяет условия, при которых данная операция может быть вызвана извне, причем за соблюдение этих условий ответственно окружение, клиенты данного компонента. Можно сказать, что предусловие описывает область определения операции в пространстве возможных состояний и 131
наборов ее аргументов. Постусловие устанавливает ограничения на исходное состояние, аргументы, результат операции и итоговое состояние, которые должны быть выполнены, если перед обращением к данной операции было выполнено ее предусловие. Операция может иметь параметры некоторых типов. Такие типы, типы полей модельного состояния, а также сами типы модельных компонентов называются интерфейсными типами. Для всех интерфейсных типы описывается их структура данных, которая может иметь ограничения на их целостность, выраженные в виде инвариантов. Структура данных модельных компонентов определяет возможные модельные состояния системы. Программные контракты были выбраны в качестве основной техники специфицирования, поскольку они достаточно просты, применимы для ПО из очень многих предметных областей и могут быть сделаны достаточно абстрактными или достаточно детальными по мере необходимости. Обычного разработчика ПО можно научить понимать их и пользоваться ими без особых усилий. Кроме того, программные контракты, будучи по структуре близки к архитектуре целевой системы, что делает их понятными для разработчиков, по внутреннему содержанию достаточно близки к требованиям к системе. Таким образом, во-первых, переработка требований в контракты не требует больших затрат, а, во-вторых, результат обычно не слишком близок к описанию конкретных алгоритмов, используемых в реализации, что предотвращает во многих случаях появления ошибок одного вида и в реализации, и в спецификациях. Контрактные спецификации не единственный вид спецификаций, поддерживаемый технологией UniTesK. В ее рамках возможно использование исполнимых спецификаций, явно описывающих, как вычисляется результат вызванной операции и как преобразуется внутреннее состояние компонента, к которому обратились. При этом, однако, дополнительно надо определить критерии эквивалентности модельных и реализационных результатов, которые не во всех случаях обязаны быть совпадающими. Аксиоматические спецификации часто не могут быть напрямую преобразованы в оракулы, оценивающие корректность поведения системы в ответ на произвольное воздействие. Поэтому аксиоматические спецификации используются только как дополнительные критерии проверки корректности на основе реакции системы на некоторые последовательности воздействий, и служат для построения тестовых сценариев.
2.5. Критерии тестового покрытия, основанные на спецификациях Структура программных контрактов используется в UniTesK для определения критериев покрытия спецификаций, которые необходимы, чтобы оценить качество тестирования с точки зрения требований. Для того, чтобы сделать возможным автоматическое извлечение такого рода критериев, накладываются дополнительные ограничения на структуру постусловий. А именно, вводятся дополнительные операторы для определения ветвей функциональности, 132
расстановка которых в постусловии лежит на пользователе. Ветвь функциональности соответствует подобласти в области определения операции, в которой операция ведет себя "одинаково". Для большей определенности "одинаковым" можно считать такое поведение, при котором ограничения на результат работы операции и изменение состояния описываются для всех точек подобласти одним и тем же выражением в постусловии. В графе потока управления постусловия на каждом пути от входа к любому из выходов должен находиться ровно один оператор, определяющий ветвь функциональности, причем на части пути до такого оператора не должно быть ветвлений, зависящих от результатов работы операции. Тогда, во-первых, каждый допустимый вызов данной операции может быть однозначно отнесен к одной из ветвей функциональности, и, таким образом, можно измерять качество тестирования операции как процент покрытых во время теста ее ветвей функциональности. Во-вторых, определить ветвь функциональности можно по текущему состоянию компонента и набору аргументов операции, не выполняя саму операцию, что позволяет построить фильтр, отсеивающий наборы аргументов, не добавляющие ничего к уже достигнутому покрытию. Отталкиваясь от определения ветвей функциональности в постусловии, можно автоматически извлечь более детальные критерии покрытия, основанные на структуре ветвлений в пред- и постусловиях. Наиболее детальным является критерий покрытия дизъюнктов. Он определяется всеми возможными комбинациями значений элементарных логических формул, использованных в ветвлениях. Этот критерий является аналогом критерия MC/DC [MCDC] для покрытия кода. При тестировании, нацеленном на достижение высокого уровня покрытия по дизъюнктам, возможны проблемы (аналогичные проблемам, возникающим при использовании критерия MC/DC), связанные с недостижимостью некоторых дизъюнктов в силу наличия неявных семантических связей между используемыми логическими формулами. Такие проблемы решаются при помощи явного описания имеющихся связей в виде тавтологий, т.е. логических выражений, построенных из элементарных формул и являющихся тождественно истинными в силу зависимостей между значениями формул. Помимо возможности управлять автоматически извлекаемыми из структуры спецификаций критериями покрытия, пользователь может описать свои собственные критерии покрытия спецификаций в виде наборов предикатов, зависящих от аргументов операций и состояния, и использовать их для определения целей тестирования.
2.6. Построение тестовых последовательностей UniTesK использует конечно-автоматные модели целевого ПО в виде тестовых сценариев для динамической генерации последовательностей тестовых воздействий. Сценарий определяет, что именно рассматривается как состояние автомата и какие операции с какими наборами аргументов должны быть 133
вызваны в каждом состоянии. Во время выполнения теста обходчик строит некоторый "исчерпывающий" путь по переходам автомата, порождая тем самым тестовую последовательность. Такой метод построения теста гарантирует, что состояние системы изменяется только за счет вызовов целевых операций, и только достижимые этим способом состояния будут возникать во время тестирования. Таким образом, перебор состояний осуществляется автоматически, и разработчику теста достаточно указать только нужный способ перебора аргументов вызываемых операций. При разработке сценария можно использовать некоторый критерий покрытия спецификаций в качестве целевого и определить набор состояний и переходов таким образом, чтобы обход всех переходов в получившемся автомате гарантировал достижение нужного покрытия. Для этого достаточно рассмотреть набор предикатов, определяющий элементы выбранного критерия покрытия для некоторой тестируемой операции, как набор областей в пространстве состояний и аргументов этой операции, и взять проекции полученных областей на множество состояний. Построив все возможные пересечения таких проекций для всех тестируемых операций, мы получим набор таких множеств состояний, что, вызывая любые операции в двух состояниях из одного такого множества, можно покрыть одни и те же элементы по выбранному критерию покрытия. Следовательно, все такие состояния системы эквивалентны с точки зрения выбранного критерия покрытия, и можно объявить состоянием результирующего автомата полученные множества. Стимулами в таком автомате считаются классы эквивалентности вызовов операций по выбранному критерию покрытия, т.е. покрывающие один и тот же его элемент. Может потребоваться дополнительно преобразовать полученный автомат, чтобы сделать его детерминированным, подробности см. в [FACTOR]. При проведении тестирования можно использовать автоматически сгенерированные из спецификаций фильтры, отсеивающие наборы аргументов, не дающие вклада в уже достигнутое покрытие. Наличие таких фильтров позволяет во многих случаях не тратить усилий человека на вычисление необходимых для достижения нужного покрытия аргументов, а указать в качестве перебираемого набора их значений некоторое достаточно большое множество, которое наверняка содержит нужные значения. Так UniTesK позволяет проводить тестирование, нацеленное на достижение высоких уровней покрытия, не затрачивая на это значительных ресурсов. Тестовый сценарий представляет конечный автомат в неявном виде, т.е. состояния и переходы не перечисляются явно, и для переходов не указываются конечные состояния. Вместо этого определяется способ вычисления текущего состояния и метод сравнения состояний, способ перебора допустимых воздействий (тестируемых операций и их аргументов), зависящий от состояния, и процедура применения воздействия. Хотя такое представление авто134
матных моделей необычно, оно позволяет описать в компактном виде довольно сложные модели, а также легко вносить модификации в полученные модели. Сценарий может определять состояния описываемой автоматной модели, основываясь не только на модельном состоянии, описанном в спецификациях, но и учитывая какие-то аспекты реализации, не нашедшие отражения в спецификациях. С другой стороны, можно также абстрагироваться от каких-то деталей в спецификациях, уменьшая тем самым число состояний в результирующей модели (см. [FACTOR]). Таким образом, способ построения теста может варьироваться независимо от спецификаций, и, следовательно, независимо от механизма проверки корректности поведения при единичном воздействии. Тестовые сценарии можно разрабатывать вручную, но в большинстве случаев они могут быть сгенерированы при помощи интерактивного инструмента, шаблона построения сценариев, который запрашивает у пользователя только необходимую информацию, и может использовать разумные умолчания. Шаблон построения сценариев помогает строить как сценарии, не использующие фильтрацию тестовых воздействий, так и нацеленные на достижение высокого уровня покрытия по одному из извлекаемых из спецификаций критериев. Тестовые сценарии, написанные в терминах спецификаций, тем самым определяют абстрактные тесты, которые можно использовать для тестирования любой системы, описываемой данными спецификациями. Кроме того, сценарии имеют дополнительные возможности для переиспользования при помощи ме-ханизма наследования. Сценарий, наследующий данному, может переопреде-лить в нем процедуру вычисления состояния и переопределить или пополнить набор тестовых воздействий, оказываемых на систему в каждом состоянии. Для тестирования параллелизма и распределенных систем UniTesK предполагает использование специального вида обходчиков, которые генерируют пары, тройки и более широкие наборы параллельных воздействий в каждом состоянии, и слегка расширенных спецификаций. В дополнение к спецификациям операций, моделирующих воздействия на целевую систему и ее синхронные реакции на эти воздействия, можно специфицировать асинхронные реакции системы, каждая из которых оформляется в виде операции без параметров, имеющей пред- и постусловия. Без спецификаций асинхронных реакций можно тестировать системы, удовлетворяющие аксиоме чистого параллелизма (plain concurrency axiom): результат параллельного выполнения любого набора вызовов операций такой системы такой же, как при выполнении того же набора вызовов в некотором порядке. Для систем, не удовлетворяющих этой аксиоме, можно ввести дополнительные "срабатывания", соответствующие выдаче асинхронных реакций или внутренним, не наблюдаемым извне, изменениям состояния системы, таким образом, что полученная модель уже будет "чистой" (plain). Автоматные модели, используемые для тестирования таких систем, являются некоторым обобщением автоматов ввода/вывода [IOSMA]. При проведении 135
тестирования "чистой" системы используется следующий метод проверки корректности ее поведения. Если обработанные системой воздействия и полученные от нее асинхронные реакции можно линейно упорядочить таким образом, что в полученной последовательности перед каждым вызовом или реакцией будет выполнено его/ее предусловие, а после — постусловие, то система ведет себя корректно. Фактически, это означает, что ее наблюдаемое поведение не противоречит спецификациям. Если такого упорядочения построить нельзя, значит обнаружено несоответствие поведения системы спецификациям. Помимо указанных выше возможностей, тестовые сценарии UniTesK дают пользователю возможность проводить тестирование, основанное на обычных сценариях, т.е, последовательностях воздействий, формируемых по указанному разработчиком теста правилу, корректность поведения системы при которых тоже оценивается задаваемым разработчиком способом. В качестве таких сценариев для системного тестирования можно, в частности, использовать сценарии, уточняющие варианты использования целевой системы. Другой способ построения сценариев дают аксиоматические спецификации, описывающие правильное поведение системы в виде ограничений на результаты выполнения некоторых цепочек вызовов целевых операций. Каждая такая цепочка вместе с проверкой наложенных на ее результаты ограничений может быть оформлена в тестовом сценарии в виде одного воздействия, которое будет выполняться во всех состояниях, где оно допустимо. Аксиомы алгебраического вида, требующие эквивалентных результатов от двух или нескольких цепочек вызовов, также могут быть проверены за счет оформления каждой цепочки в виде отдельного воздействия и сравнения ее результатов с результатами ранее выполненных в том же самом состоянии цепочек. Тестовые сценарии предоставляют удобный механизм для хранения промежуточных данных (в данном случае, результатов предыдущих цепочек) при идентификаторе состояния.
2.7. Определение связи спецификаций и реализации Спецификации, используемые UniTesK для разработки тестов, могут быть связаны с реализацией не прямо, а при помощи медиаторов. Это делает возможной разработку и использование более абстрактных спецификаций, которые гораздо удобнее получать из требований и можно использовать для тестирования нескольких версий целевого ПО. Таким образом, тесты становятся более абстрактными и многократно используемыми. Помимо преимуществ, перечисленных в начале данного раздела, можно указать дополнительные выгоды от такого способа организации разработки теста. Соответствие между требованиями, представленными в виде спецификаций, и тестами может отслеживаться полностью автоматически. Поддерживается ко-верификационная разработка ПО, при которой сама целевая система и тесты к ней разрабатываются одновременно и 136
параллельно, и сокращается общий срок разработки ПО с определенным уровнем качества. Появляется поддержка для более эффективной инфраструктуры распространения готовых компонентов ПО на коммерческой основе. Для функциональности, реализуемой такими компонентами можно иметь общедоступные, один раз написанные спецификации, дополненные тестовым набором, убедительно показывающим, что компонент действительно реализует указанные функции. Разработчик компонента может сопроводить свою реализацию медиаторами, связывающими ее с общедоступными спецификациями, тем самым, позволяя любому пользователю или независимому тестировщику убедиться в ее правильности. Кроме того, пользователи таких компонентов могут использовать для тестирования тестовые наборы, пополненные нужным им способом. Медиаторы можно разрабатывать вручную и определять, таким образом, довольно сложные преобразования между интерфейсом модели и интерфейсом реализации целевой системы. В простых случаях можно использовать шаблон построения медиаторов, который позволяет сгенерировать медиатор автоматически, указав спецификационный и реализационный компоненты, которые нужно связать, и определив соответствие между их операциями. Для каждой операции при этом нужно указать способ преобразования модельных аргументов в реализационные и реализационных результатов в модельные, если эти преобразования не тождественны. UniTesK позволяет использовать доступную извне информацию о состоянии реализации для построения модельного состояния. Способ тестирования, при котором модельное состояние целиком строится на основе доступной достоверной информации о состоянии реализации, независимо от вызываемых целевых операций, называется тестированием с открытым состоянием. Процедура построения модельного состояния при таком тестировании оформляется в отдельную операцию в медиаторе, автоматически вызываемую тестовой системой после каждого вызова целевой операции (если нет параллельных обращений к целевой системе или асинхронных реакций). Если же нам недоступна информация, достаточная для построения модельного состояния (или проводится тестирование параллельных обращений, или система может создавать асинхронные реакции), используется тестирование со скрытым состоянием. При таком тестировании модельное состояние после вызова некоторой операции строится на основе предшествовавшего вызову модельного состояния, аргументов и результатов данного вызова. Этот способ дает гипотетическое очередное модельное состояние при условии, что наблюдаемые результаты вызова не противоречат спецификациям. Он корректен, если ограничения, указанные в постусловии любой операции, можно однозначно разрешить относительно модельного состояния компонента после вызова. Медиаторы для такого тестирования должны содержать для каждой модельной операции построение модельного состояния после вызова этой операции. 137
2.8. Универсальное расширение языков программирования Обычно формальные спецификации записываются на специализированных языках, имеющих большой набор выразительных возможностей и строго определенную семантику. UniTesK позволяет использовать такие языки, если для каждой используемой пары (язык спецификаций, язык реализации) сформулированы четкие правила преобразования интерфейсов и реализована инструментальная поддержка такого преобразования. Однако, во многих случаях, несмотря на эти преимущества, специализированные языки формальных спецификаций тяжело использовать для тестирования из-за трудностей при определении указанных преобразований. Эти трудности связаны с несовпадением парадигм, лежащих в основе двух языков, спецификационного и языка реализации, с отсутствием в языке спецификаций аналогов понятий, широко используемых в реализации (например, указателей), с несовпадением семантики базовых типов и пр. Поэтому такая работа требует обычно больших затрат труда высококвалифицированных специалистов, хорошо знакомых с обоими языками. Кроме того, обучение такой работе также весьма трудоемко и начинает давать практические результаты только по истечении значительного времени. Для того, чтобы сделать технологию более доступной обычным разработчикам, и для облегчения разработки медиаторов UniTesK поддерживает написание спецификаций и сценариев на расширениях широко используемых языков программирования. Для этого построена единая система базовых понятий, используемых при разработке спецификаций и сценариев, таких как предусловие, постусловие, инвариант, ветвь функциональности, сценарный метод (определяющий в сценарии однородное семейство тестовых воздействий), и для каждого их этих понятий сформулированы правила дополнения языка соответствующей конструкцией. Для языка, в котором уже имеются средства для выражения понятий, аналогичных выделенным, пополнение производится только конструкциями, не имеющими аналогов. Значительное преимущество использования расширения языка целевой системы для спецификаций состоит в том, что связывать такую спецификацию с реализацией гораздо проще. При использовании для спецификаций расширения целевого языка, обучиться работе с ними может обычный разработчик, имеющий опыт работы с целевым языком. Проблема недостаточной выразительности в большинство современных объектноориентированных языков решается при помощи использования библиотек абстрактных типов. Проблема возможной зависимости смысла спецификации от платформы может решаться несколькими способами. Во-первых, можно запретить использование в спецификациях конструкций, имеющих недостаточно четкий смысл и поразному интерпретируемых для разных платформ. Во-вторых, можно рекомендовать использовать библиотеки, реализованные так, чтобы работать 138
одинаково на всех поддерживаемых платформах. В-третьих, в особо специфических случаях можно проводить удаленное тестирование, при котором тестовая система исполняется на той же платформе, на которой разрабатывались спецификации. В качестве примера мы рассмотрим спецификации функции, вычисляющей квадратный корень. Спецификации на расширениях различных языков программирования приводятся в левом столбце таблиц, представленных ниже. В правом столбце даются краткие пояснения, касающиеся структуры спецификаций.
Java specification package example;
Декларация пакета
class SqrtSpecification { specification static double sqrt ( double x ) reads x, epsilon { pre { return x >= 0; } post { if(x == 0) { branch "Zero argument";
Декларация класса
return sqrt == 0; } else { branch "Positive argument"; return sqrt >= 0 && Math.abs((sqrt*sqrt-x)/x)<epsilon;
C#
namespace Examples { specification class SqrtSpecification { specification static double Sqrt ( double x ) reads x, epsilon { pre { return x >= 0; } post { if(x == 0) { branch ZERO ("Zero argument"); return $this.Result == 0; } else { branch POS ("Positive argument");
Сигнатура операции Описание доступа на чтение/запись Предусловие Постусловие
Определение ветви функциональности Ограничения на результат
}
}
}
}
}
return $this.Result >= 0 && Math.Abs( ($this.Result * $this. Result - x)/x) < epsilon;
Декларация пространства имен Декларация класса Сигнатура операции Описание доступа на чтение/запись Предусловие Постусловие
Определение ветви функциональности Ограничения на результат
Определение ветви функциональности Ограничения на результат
C specification double SQRT ( double x ) reads x, epsilon { pre { return x >= 0.; } coverage BRANCHES { if(x == 0) return(ZERO, "Zero argument"); else return(POS, "Positive argument"); } post { if(coverage(BRANCHES)==ZERO) return SQRT == 0.; else return SQRT >= 0. && abs((SQRT*SQRT - x)/x) < epsilon; } } }
Определение ветви функциональности Ограничения на результат
} } } }
139
140
Сигнатура операции Описание доступа на чтение/запись Предусловие Описание структуры тестового покрытия Определение ветви функциональности Определение ветви функциональности Постусловие Ограничения на результат Ограничения на результат
2.9. Выполнение тестов и анализ их результатов Инструменты UniTesK поддерживают автоматическое выполнение тестов, разработанных с их помощью, и автоматический сбор трассировочной информации. После окончания работы теста на основе его трассы можно сгенерировать набор дополнительных тестовых отчетов. Эти отчеты показывают структуру автомата, выявленную в ходе тестирования, уровень достигнутого тестового покрытия для всех критериев, определенных для некоторой спецификационной операции, и информацию об обнаруженных в ходе теста нарушениях, связанных с ошибками в целевой системе или с ошибками в спецификациях, сценариях и медиаторах. Трасса теста может служить для получения дополнительной информации, например, о зафиксированных нарушениях. Так, из трассы можно узнать вид нарушения, значения аргументов вызова операции, при выполнении которого это нарушение было обнаружено, какое именно ограничение в постусловии было нарушено, и т.д. Представленная в трассе и других отчетах информация достаточна, как для отладки тестовой системы, так и для оценки качества тестирования и, зачастую, для предварительной локализации обнаруженных ошибок. Ниже приведены примеры отчетов, которые инструмент J@T, поддерживающий технологию UniTesK для программ на Java, автоматически формирует на основе трассы теста. J@T Failure Report generated: 12.12.2003 17:48:48
Report Overview
branch mark
All Failures Specifications Coverage predicate Scenarios Coverage
disjunct
Report Overview All Failures Specifications Coverage Failures Branches Marks Predicates Disjuncts Scenarios Coverage Packages Overview ru.ispras.redverst.se .java.exam AccountSpecification deposit( int ) withdraw( int )
branches
total marks
predicates
disjuncts
100% 100% (1/1) (3/3) branches marks
100% (3/3) predicates
100% (3/3) disjuncts
Single branch
Deposit on predicate1 + + - - * account with negative balance; Single branch Deposit on predicate2 + + - + * empty account; Single branch Deposit on predicate3 + + + * * account with positive balance; Single branch
identifier f1 f2 f3 f4 f5 f6 f7
142
total *
*
6
*
*
2
*
*
20
predicates meaning ( !( 0 < balance ) && !( balance == 0 ) ) ( !( 0 < balance ) && ( balance == 0 ) ) ( ( 0 < balance ) ) prime formulas meaning 0 < sum !( ( Integer.MAX_VALUE - sum ) < balance ) 0 < balance balance == 0 balance == ( @balance + sum ) reads sum reads Integer.MAX_VALUE
Рис. 4. Отчет о тестовом покрытии.
Рис. 3. Описание найденной ошибки.
hits/fails 28
f1 f2 f3 f4 f5 f6 f7 hits/fails
identifier predicate1 predicate2 predicate3
test situation Withdrawn sum is too large Withdrawal from empty account; Withdrawn sum is too large ( !( 0 < balance ) && ( balance == 0 ) ) && ( ( ( balance - sum ) < -maximumCredit ) ) true 0 < sum false 0 < balance true balance == 0 true ( balance - sum ) < -maximumCredit true balance == @balance false withdraw == 0 balance == ( @balance – sum ) withdraw == sum reads sum reads maximumCredit 141
deposit( int )
3. Сравнение с другими подходами к разработке тестов на основе моделей Хотя практически любая функциональная характеристика технологии UniTesK может быть найдена и в других технологиях и методах разработки тестов, иногда даже в более развитой форме, ни один из имеющихся подходов к разработке тестов, предлагаемый в академическом сообществе или в индустрии разработки ПО, не обладает всей совокупностью характеристик UniTesK. В кратком обзоре, помещенном в этом разделе, мы сконцентрировали внимание на методах разработки тестов, поддержанных инструментами и нацеленных на использование в промышленной разработке ПО. Таким образом, множество интересных методов и техник осталось за рамками обзора. Имеющиеся подходы к разработке тестов, в основном, используют стандартную, сложившуюся еще несколько десятилетий назад архитектуру теста. Тест в ней представляет собой набор тестовых вариантов (test cases), каждый из которых служит для проверки некоторого свойства целевой системы в определенной ситуации. В UniTesK тесты строятся в виде сценариев, каждый из которых, по существу, исполняет роль целого набора тестовых вариантов, проверяющих работу целевой системы при обращении к выделенной группе интерфейсов в различных ситуациях. В результате, в тестовом наборе UniTesK больше уровней иерархии, что удобно при тестировании больших и сложных систем. С другой стороны, тестовые варианты позволяют более эффективно воспроизводить нужные ситуации при повторном тестировании, например, на наличие ранее обнаруженной ошибки. Для регрессионного тестирования обе схемы пригодны в равной степени, поскольку при этом обычно требуется возможность прогона всего набора тестов. Автоматическое построение тестовых оракулов на основе спецификаций отличает UniTesK от инструментов, таких как JUnit [JUNIT], автоматизирующих только выполнение тестов. Вместе с тем, оно поддерживается очень многими существующими инструментами, например, следующими: iContract [iContract,iContractW], JMSAssert [JMS], JML [JML,JMLW], jContractor [jContr,jContrW], Jass [Jass,JassW], Handshake [Handshake], JISL [JISL] используют контрактные спецификации, написанные в исходном коде целевой системы в виде комментариев на расширении Java (обзоры таких систем можно найти в [CCNET] и [ORA] ) SLIC [SLIC] позволяет оформлять контрактные спецификации на расширении C с использованием предикатов временных логик Test RealTime [TRT] от Rational/IBM использует контракты и описание структуры конечно-автоматной модели целевого компонента в виде специальных скриптов
Рис. 5. Трасса в форме MSC.
Рис. 6. Трасса в виде графа состояний конечного автомата. 143
144
JTest/JContract [PARASOFT] от Parasoft и Korat [KORAT] позволяют писать предусловия, постусловия и инварианты в виде особых комментариев в Java-программах ATG-Rover [TRover] использует спецификации в виде программных контрактов-комментариев на С, Java или Verilog, которые могут содержать предикаты временных логик LTL или MTL Семейство инструментов ADL [ADLt] основано на расширениях С, С++, Java и IDL, которые используются для разработки контрактных спецификаций, не привязанных жестко к конкретному коду T-VEC [TVEC] использует пред- и постусловия, оформленные в виде таблиц в нотации SCR [SCR] От инструментов, перечисленных в первых трех пунктах, UniTesK отличает наличие существенной поддержки разработки тестов, в частности, определение критериев покрытия на основе спецификаций и механизм генерации тестовых последовательностей из сценариев. В инструменте JTest возможность автоматической генерации тестовых последовательностей заявлена, но генерируемые последовательности могут содержать не более 3-х вызовов операций, и строятся случайным образом, без возможности нацелить их на достижение высокого тестового покрытия. Инструмент Korat является одним из инструментов, разработанных в рамках проекта MulSaw [MulSaw] лаборатории информатики MIT. Он использует контракты, оформленные на JML, для генерации множества наборов входных данных одного метода в классе Java, включая и сам объект, в котором данный метод вызывается, гарантирующего покрытие всех логических ветвлений в спецификациях. Таким образом, вместо построения тестовой последовательности можно сразу получить целевой объект в нужном состоянии. С другой стороны, спецификации должны быть жестко привязаны к реализации. В частности, они не должны не допускать таких состояний целевого компонента, которые не могут возникнуть в ходе его работы, иначе много сгенерированных тестов будут соответствовать недостижимым состояниям компонента. Инструменты ADL предоставляют поддержку разработки тестов только в виде библиотеки генераторов входных данных, аналогичной библиотеке итераторов в UniTesK. ATG-Rover позволяет автоматически генерировать шаблоны тестовых последовательностей для покрытия спецификаций. Из доступной документации неясно, должны ли эти шаблоны дорабатываться вручную, чтобы превратиться в тестовые последовательности, но возможность такой доработки присутствует. T-VEC использует специальный вид спецификаций для автоматического извлечения информации о граничных значениях областей, в которых описываемая спецификациями функция ведет себя "одинаково" (ср. определение ветвей функциональности в UniTesK). Тестовые воздействия генерируются таким образом, чтобы покрывать граничные точки ветвей 145
функциональности для данной функции. Полный тест представляет собой список пар, первым элементом которых является набор аргументов тестируемой операции, а вторым --- корректный результат ее работы на данном наборе аргументов, вычисленный по спецификациям. Генерация тестовых последовательностей не поддерживается. Кроме T-VEC, нам не известны инструменты, поддерживающие, подобно UniTesK, генерацию тестов, нацеленных на достижение высокого покрытия по критериям, построенным по внутренней структуре контрактных спецификаций. Большинство имеющихся инструментов способно отслеживать покрытие спецификаций только как процент операций, которые были вызваны. Генерация тестовых последовательностей поддерживается многими инструментами, использующими модели целевой системы в виде различного рода автоматов: расширенных конечных автоматов, взаимодействующих конечных автоматов, автоматов ввода/вывода, систем помеченных переходов, сетей Петри и пр. Такие инструменты хорошо подходят для верификации телекоммуникационного ПО, при разработке которого зачастую используются формальные языки спецификаций, основанные на перечисленных представлениях ПО --- SDL [SDL,ITUSDL,ITUSDLN], LOTOS [LOTOS], Estelle [Estelle], ESTEREL [ESTEREL,ESTERELL] или Lustre [Lustre]. Большинство этих инструментов использует в качестве спецификаций описание поведения системы на одном из указанных языков, трансформируя его в автоматную модель нужного вида. Часть таких инструментов использует, помимо спецификаций поведения системы, сценарий тестирования, называемый обычно целью теста (test purpose) и заданный пользователем в виде последовательности сообщений, которой обмениваются компоненты ПО (MSC), или небольшого автомата (см., например, [TPA,TPB,CADPO,TGV]). Другая часть использует явно описанные автоматные модели для генерации тестовых последовательностей, нацеленных на достижение определенного уровня покрытия согласно какому-либо критерию (см. [TorX,SDLt,EST]). UniTesK, как уже говорилось, поддерживает построение тестовых последовательностей и из заданных пользователем сценариев, и на основе автоматной модели системы, интегрируя оба подхода. Наиболее близки к UniTesK по поддерживаемым возможностям инструменты GOTCHA-TCBeans [UMBTG,GOTCHA] (один из инструментов генерации тестов, объединяемых в рамках проекта AGEDIS [AGEDIS,AGEDISW]), и AsmL Test Tool [ASMT,ASMTW]. Оба они используют автоматные модели целевого ПО. Для GOTCHA-TCBeans такая модель должна быть описана на расширении языка Murphi [Murphi], AsmL Test Tool использует в качестве спецификаций описание целевой системы как машины с абстрактным состоянием (abstract state machine, ASM, см. [ASMI,ASMB]). Объединяет все три подхода использование разных видов моделей для построения теста, что позволяет строить более эффективные, гибкие и масштабируемые тесты, а также иметь больше компонентов для повторного 146
использования. В UniTesK это модель поведения в виде спецификаций и модель тестирования в виде сценария, в GOTCHA-TCBeans и других инструментах проекта AGEDIS, — автоматная модель системы и набор тестовых директив, управляющих процессом создания тестов на ее основе, в последних версиях AsmL Test Tool — ASM-модель системы и множество наблюдаемых величин, наборы значений которых определяют состояния для построения тестовой конечного автомата, используемого последовательности. В указанных инструментах используются техники уменьшения размера модели, аналогичные факторизации в UniTesK. Инструмент GOTCHATCBeans может применять частный случай факторизации, при котором игнорируются значения некоторых полей в состоянии исходной модели [PROJ]. AsmL Test Tool может строить тестовую последовательность на основе конечного автомата, состояния которого получаются редукцией полного состояния машины до набора значений элементарных логических формул, используемых в описании ее переходов [FfASM]. Основными отличиями UniTesK от GOTCHA-TCBeans и AsmL Test Tool являются поддержка расширений языков программирования для разработки спецификаций, использование контрактных спецификаций, автоматизация отслеживания покрытия спецификаций и использование фильтров для получения тестовых воздействий, нацеленных на его повышение.
4. Опыт использования UniTesK Работы над инструментами для поддержки технологии UniTesK начались в конце 1999 года. К тому времени уже было проведено несколько проектов, где технология KVEST использовалась для разработки тестов и регрессионного тестирования крупных промышленных систем компании Nortel Networks, производителя цифрового телекоммуникационного оборудования. Примерами систем Nortel Networks, к которым применялся KVEST были: Ядро операционной системы реального времени (размер около 250 тысяч строк, язык реализации ПРОТЕЛ, близок к С). Система хранения и быстрого поиска сообщений. Утилиты базисного уровня телефонных сервисов. Распределенная система управления сообщениями P2P. Первой была готова для использования реализация UniTesK для программ на языке C — CTesK. Упрощенный вариант инструментов для поддержки этой технологии был готов к концу 2000 года. К середине 2001 они уже активно использовались в исследовательском проекте по гранту Microsoft Research. Целью проекта было тестирование реализации стека интернет-протоколов нового поколения. IPv6. Кроме того, ставилась задача проверки пригодности UniTesK для тестирования задач нового класса — реализаций телекоммуникационных протоколов. К концу 2001 года проект был завершен. 147
Были найдены серьезные ошибки в реализации, способные привести к нарушению работы произвольного узла в сети на основе IPv6. Поскольку данная реализация тестировалась одновременно несколькими командами тестировщиков в разных странах мира, и никто не обнаружил этих ошибок, была показана высокая результативность UniTesK. В рамках данного проекта был впервые опробован новый механизм тестирования распределенных и асинхронных систем на основе автоматных моделей в виде IOSM. В 2003 году был проведен пилотный проект применения CTesK для тестирования ПО реального времени (алгоритмы управления навигационными устройствами, ГосНИИАС). Несмотря на сжатые сроки проекта удалось найти серьезную ошибку в алгоритме. В середине 2002 года была готова первая коммерческая версия инструмента J@T, инструмента разработки тестов для Java программ*. По состоянию на конец 2003 кода проведено несколько пилотных проектов с использованием J@T: Система ведения информации по клиентам и сделкам для банка, построенная по трехзвенной архитектуре с использованием технологии EJB (Luxoft). Подсистема создания запросов и преобразования данных в распределенном банковском Web-приложении (Tarang) Подсистема связи с СУБД в библиотеке классов для разработки многоуровневых бизнес-приложений (VisualSoft) Подсистема контроля времени работы клиентов в биллинговой системе (VebTel). Все перечисленные пилотные показали высокую результативность технологии. В рамках всех проектов удалось найти ошибки Часть ошибок владельцы кода определили как очень серьезные. Например, была найдена ситуация, когда результаты незавершенных транзакций сбрасывались в базу данных. При этом некоторые из проектов проводились в чрезвычайно сжатые сроки — 1-2 дня. В 2001 группа RedVerst начала совместные научные исследования с компанией Интел. Целью исследований была адаптация технологии тестирования на основе моделей к задачам тестирования оптимизирующих компиляторов. Сначала эксперименты проводились на свободно распространяемых компиляторах (gcc и Open64). Уже первые опыты показали, что для компилятора gcc, например, удается добиться полноты тестового покрытия операторов реализации около 90-95%, что для промышленного тестирования является очень высоким показателем. Затем опыты были перенесены на последнее поколение коммерческих компиляторов, разрабатываемых Интел для 64-битной платформы Itanium. Результативность адаптированной технологии UniTesK была подтверждена и там. К середине 2003 года на основе опыта проведенных исследований и экспериментов был разработан набор программных инструментов, который *
Имеется возможность использования J@T для тестирования программ на C++.
148
позволяет строить тесты для компиляторов и других текстовых процессоров. Эти инструменты были опробованы на задачах генерации пакетов протокольных сообщений. Надо отметить, что «адаптация» UniTesK к задачам тестирования компиляторов потребовала решения ряда принципиально новых задач и разработки новых технологических приемов. Так были решены задача описания модельного языка, являющегося упрощением целевого языка компилятора, задача построения итераторов конструкций модельного языка — модельных блоков, задача построения тестового оракула для анализа корректности оптимизаторов. Инструмент для тестирования компиляторов вошел в набор инструментов для поддержки разработки тестов по технологии UniTesK. Тем самым было показано, что концептуально схема построения тестов на основе моделей оказалась достаточно общей. К концу 2003 года была завершена первая версия инструмента Ch@se, инструмента разработки тестов для .NET приложений. Это очередная реализация технологии UniTesK, теперь на базе расширения языка C#. Полный список проектов, проводимых с использованием технологии UniTesK, а также описания результатов этих проектов, можно найти на сайте группы спецификации, верификации и тестирования ИСП РАН [RedVerst].
5. Заключение. Открытые проблемы и направления дальнейшего развития Опыт разработки и использования UniTesK, как и работы других исследователей в области тестирования на основе моделей, показывает, что данное направление является весьма перспективным. Каковы же главные проблемы, которые мешают более широкому распространению тестирования на основе моделей? Их можно разделить на три основные группы: методические — как разрабатывать спецификации и тесты? технические — как унифицировать методы разработки спецификаций и тестов и инструменты, которые поддерживают эти работы? организационные — как внедрить новые методики и инструменты в реальные процессы разработки ПО? Сложность успешного решения перечисленных проблем возрастает от первой группы (методика) к последней (организационная перестройка). В подтверждение этого тезиса можно сослаться на опыт многих групп, использующих методы тестирования на основе спецификаций в промышленных приложениях. За исключением единичных случаев всегда удается найти подходящий способ моделирования, который дает хорошие 149
результаты как в плане качества тестирования, так и плане достижения хороших стоимостных показателей. Тем самым показано, что неразвитость теории и методики не является сдерживающим фактором распространения данного подхода. Сейчас еще нет общего согласия по поводу нотаций и методов, при помощи которых ведется разработка моделей и тестов на их основе, нет унифицированной, общепринятой архитектуры тестирующей системы, отдельные инструменты для статического и динамического анализа программ и представления результатов анализа еще далеки от унификации. Тем не менее потребность в унификации уже назрела. Наиболее известным продвижением в области унификации является разработка документа UML Testing Profile [UML-TP], подготовленного в рамках программы MDA (Model Driven Architecture, [MDA]). Вместе с тем следует отметить, что авторы UML Testing Profile, возможно, пытаясь найти компромисс пригодный для всех участников консорциума, предлагают архитектуру, нацеленную больше на ручную разработку тестов. Этот подход в некоторой степени может быть использован при разработке тестов на основе спецификаций сценариев использования, но он становится ограничивающим фактором, если в качестве модели целевого ПО берутся автоматные модели или спецификации ограничений, разработанные по методу Design-by-Contract. Следствием такого одностороннего подхода является непонимание потенциальных преимуществ использования спецификаций ограничений, и, в частности, языка OCL (Object Constraint Language), в промышленном программировании. Тем самым, проблема унификации представляется не только технической. Важно найти унифицированный подход, который позволил бы на базе единой концепции разрабатывать тесты на основе разных видов моделей с использованием ручных, автоматизированных и автоматических технологий. Организационные проблемы на данный момент являются наиболее острыми [Robinson, Manage]. Как уже отмечалось выше, новая технология тестирования должна достаточно хорошо интегрироваться с имеющимися процессами разработки, и не требовать долгой и дорогой переподготовки персонала. Есть ли шанс найти для методов разработки тестов на основе моделей возможности сочетаться с традиционными методами разработки таким образом, что это позволит ввести новые технологии без ломки уже сложившихся процессов? По-видимому, абсолютно безболезненным внедрение не будет, и причиной этого являются не столько технические проблемы, сколько проблемы персонала, причем как технического, так и управляющего. В настоящее время при промышленной разработке ПО широко используется подход к разработке тестов и тестированию как вспомогательной деятельности, не требующей
Верификационного набора в терминах UniTesK — совокупности компонентов модели и производных от них компонентов тестирующей программы, рассматриваемой вместе со связями между всеми компонентами.
150
навыков программирования, соответственно, в качестве тестировщиков используется, в основном, персонал без знания языков программирования и без базовых программистских умений. Пытаясь упростить проблемы организации взаимодействия команд разработчиков и тестировщиков, руководители проектов ориентируют тестировщиков только на системное тестирование, что влечет практическое отсутствие модульного и компонентного. В этом случае появляется иллюзия, что тестировщики, имея большой запас времени, могут создать качественные тесты. В реальности же разработка обычно затягивается, и к моменту приемо-сдаточных испытаний система в состоянии продемонстрировать работоспособность на ограниченном количестве наиболее вероятных сценариев, но нуждается в серьезных доработках на большинстве нестандартных сценариев использования. Очевидно, что «сломать» негативные тенденции нельзя, они могут быть изжиты только вследствие эволюционных изменений. Сейчас такими эволюционными шагами могут стать дополнительные работы, которые поручаются проектировщикам и разработчикам. Эти дополнительные работы войдут в обиход реальных процессов разработки только тогда, когда их выполнение окажет положительный эффект на основную деятельность проектировщиков и программистов. Поэтому сейчас средства автоматизации тестирования на основе моделей имеет смысл вписывать в среду разработки, тем самым привлекая к тестированию не только профессиональных тестировщиков, но и разработчиков. Для того чтобы расширить сообщество пользователей методов тестирования на основе моделей надо развивать формы обучения этим методам. Все инструменты UniTesK сопровождаются не только обычной пользовательской документацией, но и материалами для обучения. Предлагаются две формы обучения: традиционная университетская форма и форма интенсивного тренинга. Университетский курс требует от 15 до 30 часов занятий, тренинг требует 3-4 учебных дня по 8 академических часов каждый день. Материалы для университетов также как и лицензии на инструменты UniTesK для использования в образовательных целях предоставляются бесплатно. Также бесплатно предоставляются примеры спецификаций и тестов для разнообразных приложений. Основной стратегической целью дальнейших работ над UniTesK является построение полномасштабных индустриально применимых технологий тестирования на основе моделей для всех видов приложений, разрабатываемых в промышленности. Для успешного развития технологий тестирования на основе моделей нужно одновременно поддерживать их эволюцию в трех направлениях: наращивать
Многие считают, что разработчик не в состоянии тестировать свою программу. Однако, в случае использования моделей по структуре отличающихся от реализации (например, спецификаций ограничений), такое совмещение вполне возможно.
151
функциональность технологий, наращивать сопряженность этих технологий с современными процессами разработки и наращивать удобство их использования. Особенно важно увеличивать удобство использования технологий для решения наиболее часто встречающихся задач. Исследования по расширению области применимости подхода к тестированию на основе моделей должны проводиться по целому ряду направлений 1. Разработка полномасштабных технологий тестирования для всех компонентов таких видов приложений, как компиляторы, интерпретаторы, СУБД и др., функции которых связаны с обработкой запросов на хорошо структурированных формальных языках. 2. Автоматизация тестирования приложений через графический пользовательский интерфейс. 3. Разработка технологий полномасштабного тестирования распределенных систем, из которых наиболее широко встречаются сейчас многоуровневые приложению в архитектуре клиент-сервер приложений-сервер данных. 4. Тестирование компонентов, имеющих очень сложную функциональность и очень ограниченный интерфейс: планировщики задач, сборщики мусора, менеджеры транзакций и пр. 5. Тестированию приложений с элементами искусственного интеллекта: распознавание образов, выбор стратегии достижения цели в неопределенной ситуации, нечеткая логика, интеллектуальные агенты, и пр. Помимо решения задач собственно тестирования для привлечения внимания к технологиям тестирования на основе моделей необходимо искать подходящие метрики качества ПО, которые позволили бы продемонстрировать преимущества этого подхода. На данный момент многие метрики, используемые в промышленности для оценки качества ПО и состояния процесса тестирования, подходят для традиционной разработки тестов вручную, но приводят к парадоксам при попытке их использования в проектах, где тесты строятся автоматизировано на основе моделей. Кроме того, необходимо искать пути повышения прозрачности связей между используемыми моделями и требованиями к ПО, а также метрики переиспользуемости, позволяющие объективно оценить влияние изменений в требованиях к ПО, в требованиях к качеству тестирования, в архитектуре целевого ПО, в используемых технологиях разработки и пр. на изменения в тестах. Разработка и апробация таких метрик в промышленных проектах позволит повысить значимость технологий, нацеленных на повышение качества ПО, что, в свою очередь придаст новый импульс работам по автоматизации тестирования и по тестированию на основе моделей.
Литература 1. [ADLt] M. Obayashi, H. Kubota, S. P. McCarron, and L. Mallet. The Assertion Based Testing Tool for OOP: ADL2, available via http://adl.opengroup.org/
152
2. [AGEDIS] I. Gronau, A. Hartman, A. Kirshin, K. Nagin, and S. Olvovsky. A Methodology and Architecture for Automated Software Testing. Available at http://www.haifa.il.ibm.com/projects/verification/gtcb/papers/gtcbmanda.pdf 3. [AGEDISW] http://www.agedis.de/ 4. [ASMB] E. Börger and R. Stark. Abstract State Machines: A Method for High-Level System Design and Analysis. Springer-Verlag, 2003. 5. [ASMI] Y. Gurevich. Evolving Algebras: An Attempt to Discover Semantics. In Current Trends in Theoretical Computer Science, eds. G. Rozenberg and A. Salomaa, World Scientific, 1993, pp. 266–292. 6. [ASMT] W. Grieskamp, Y. Gurevich, W. Schulte, and M. Veanes. Testing with Abstract State Machines. In R. Moreno-Diaz and A. Quesada-Arencibia, eds., Formal Methods and Tools for Computer Science (Proceedings of Eurocast 2001), Universidad de Las Palmas de Gran Canaria, Canary Islands, Spain, February 2001, pp. 257–261. 7. [ASMTW] http://research.microsoft.com/fse/asml/ 8. [AsSM] И. Бурдонов, А. Косачев, В. Кулямин. Асинхронные автоматы: классификация и тестирование, Труды ИСП РАН, 4:7-84, 2003. 9. [ASSUM] S. Fujiwara and G. von Bochmann. Testing Nondeterministic Finite State Machine with Fault Coverage. IFIP Transactions, Proceedings of IFIP TC6 Fourth International Workshop on Protocol Test Systems, 1991, Ed. by Jan Kroon, Rudolf J. Heijink, and Ed Brinksma, 1992, North-Holland, pp. 267–280. 10. [ATS] http://www.atssoft.com 11. [BP] G. v. Bochmann and A. Petrenko. Protocol Testing: Review of Methods and Relevance for Software Testing. In Proceedings of ACM International Symposium on Software Testing and Analysis. Seattle, USA, 1994, pp. 109–123. 12. [CADPO] H. Garavel, F. Lang, and R. Mateescu. An overview of CADP 2001. INRIA Technical Report TR-254, December 2001. 13. [CCNET] M. Barnett and W. Schulte. Contracts, Components, and their Runtime Verification on the .NET Platform. Technical Report TR-2001-56, Microsotf Research. 14. [DBCA] Bertrand Meyer. Applying `Design by Contract'. IEEE Computer, vol. 25, No. 10, October 1992, pp. 40–51. 15. [DBCE] Bertrand Meyer. Eiffel: The Language. Prentice Hall, 1992. 16. [DBCO] Bertrand Meyer. Object-Oriented Software Construction, Second Edition. Prentice Hall, 1997. 17. [DETFSM] И. Б. Бурдонов, А. С. Косачев, В. В. Кулямин. Неизбыточные алгоритмы обхода ориентированных графов. Детерминированный случай. Программирование, 2003. 18. [EST] W. Chun, P. D. Amer. Test case generation for protocols specified in Estelle. In J. Quemada, J. Mañas, and E. Vázquez, editors. Formal Description Techniques, III, Madrid, Spain, North-Holland 1990, pp. 191–206. 19. [Estelle] ISO/TC97/SC21. Information Processing Systems — Open Systems Interconnection — Estelle — A Formal Description Technique based on an Extended State Transition Model. ISO 9074:1997, International Organization for Standardization, Geneva, Switzerland, 1997. 20. [ESTEREL] G. Berry. The Foundations of Esterel. In Proof, Language and Interaction: Essays in Honour of Robin Milner, G. Plotkin, C. Stirling, and M. Tofte, editors, MIT Press, 1998. 21. [ESTERELL] F. Boussinot and R. de Simone. The Esterel language. Proc. IEEE, vol. 79, pp. 1293–1304, Sept. 1991.
153
22. [FACTOR] И. Б. Бурдонов, А. С. Косачев, В. В. Кулямин. Применение конечных автоматов для тестирования программ. Программирование, 26(2):61–73, 2000. 23. [FfASM] W. Grieskamp, Y. Gurevich, W. Schulte, and M. Veanes. Generating Finite State Machines from Abstract State Machines. In Proc. of ISSTA'2002. Also: Microsoft Research Technical Report MSR-TR-2001-97. 24. [FMEAD] http://www.fmeurope.org/databases/fmadb088.html 25. [GOTCHA] http://www.haifa.il.ibm.com/projects/verification/gtcb/documentation.html 26. [Handshake] A. Duncan and U. Hlzle. Adding Contracts to Java with Handshake. Technical Report TRCS98-32, University of California, Santa Barbara, 1998. 27. [iContract] R. Kramer. iContract — The Java Design by Contract Tool. In Proceedings of TOOLS26: Technology of Object-Oriented Languages and Systems, pp. 295–307. IEEE Computer Society, 1998. 28. [iContractW] http://www.reliable-systems.com/ 29. [IOSMA] P. Zafiropulo, C. H. West, H. Rudin, D. D. Cowan, and D. Brand. Towards Analysing and Synthesizing Protocols. IEEE Transactions on Communications, COM28(4):651–660, April 1980. 30. [ITUSDL] ITU-T, Recommendation Z.100: Specification and Description Language (SDL), ITU-T, Geneva, 1996. 31. [ITUSDLN] ITU-T, Recommendation Z.100 Annex F1: SDL formal definition — General, 2000. 32. [Jass] D. Bartetzko, C. Fisher, M. Moller, and H. Wehrheim. Jass — Java with assertions. In K. Havelund and G. Rosu, editors, Proceeding of the First Workshop on Runtime Verification RV'01, Vol. 55 of Electronic Notes in Theoretical Compter Science, Elsevier Science, July 2001. 33. [JassW] http://semantik.informatik.uni-oldenburg.de/~jass 34. [Jatva] Igor B. Bourdonov, Alexey V. Demakov, Andrew A. Jarov, Alexander S. Kossatchev, Victor V. Kuliamin, Alexander K. Petrenko, Sergey V. Zelenov. Java Specification Extension for Automated Test Development. Proceedings of PSI'01. LNCS 2244, pp. 301–307. Springer-Verlag, 2001. 35. [jContr] M. Karaorman, U. Holzle, and J. Bruno. jContractor: A reflective Java library to support design by contract. Technical Report TRCCS98-31, University of California, Santa Barbara. Computer Science, January 19, 1999. 36. [jContrW] http://jcontractor.sourceforge.net/ 37. [JISL] P. Muller, J. Meyer, and A. Poetzsch-Heffter. Making executable interface specifications more expressive. In C. H. Cap, editor, JIT'99 Java-Informations-Tage 1999, Informatik Aktuell. Springer-Verlag, 1999. 38. [JML] A. Bhorkar. A Run-time Assertion Checker for Java using JML. Technical Report 00-08, Department of Computer Science, Iowa State University, 2000. 39. [JMLW] http://www.cs.iastate.edu/~leavens/JML.html 40. [JMS] http://www.mmsindia.com/JMSAssert.html 41. [JUNIT] http://www.junit.org/index.htm 42. [KORAT] C. Boyapati, S. Khurshid, and D. Marinov. Korat: Automated Testing Based on Java Predicates. Proc. of ISSTA 2002, Rome, Italy. Jul 2002. 43. [KVEST] I. Bourdonov, A. Kossatchev, A. Petrenko, and D. Galter. KVEST: Automated Generation of Test Suites from Formal Specifications. FM'99: Formal Methods. LNCS 1708, Springer-Verlag, 1999, pp. 608–621. 44. [LOTOS] ISO/IEC. Information Processing Systems — Open Systems Interconnection — LOTOS — A Formal Description Technique based on the Temporal Ordering of
154
45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65.
66.
Observational Behaviour. ISO/IEC 8807:1989, International Organization for Standardization, Geneva, Switzerland, 1989. [Lustre] N. Halbwachs, P. Caspi, P. Raymond, and D. Pilaud. The synchronous data flow programming language LUSTRE. Proc. IEEE, vol. 79, pp. 1305–1320, Sept. 1991. [LY] D. Lee and M. Yannakakis. Principles and Methods of Testing Finite-State Machines. A survey. Proceedings of the IEEE, Vol. 84, No. 8, 1996, pp. 1090–1123. [MCDC] J. J. Chilenski and S. P. Miller. Applicability of modified condition/decision coverage to software testing. Software Engineering Journal, pp. 193–200, September 1994. [MSRIPreport] http://www.ispras.ru/~RedVerst/RedVerst/White Papers/MSRIPv6 Verification Project/Main.html [MulSaw] http://mulsaw.lcs.mit.edu/ [Murphi] http://verify.stanford.edu/dill/murphi.html [NDFSM] И. Б. Бурдонов, А. С. Косачев, В. В. Кулямин. Неизбыточные алгоритмы обхода ориентированных графов. Недетерминированный случай. Программирование, 2003. В этом номере. [Manage] D.Stidolph, J.Whitehead. Managerial Issues for the Consideration and Use of Formal Methods, LNCS No.2805, 2003, pp.170-186.] [MDA] http://www.omg.org/mda/ [OPT] A. Kossatchev, A. Petrenko, S. Zelenov, and S. Zelenova. Using Model-Based Approach for Automated Testing of Optimizing Compilers. In Proccedings of Intl. Workshop on Program Undestanding, Gorno-Altaisk, 2003. [ORA] L. Baresi and M. Young. Test Oracles. Tech. Report CIS-TR-01-02. Available at http://www.cs.uoregon.edu/~michal/pubs/oracles.html [PARASOFT] http://www.parasoft.com [Parnas] D. Peters and D. Parnas. Using Test Oracles Generated from Program Documentation. IEEE Transactions on Software Engineering, 24(3):161–173, 1998. [PROJ] G. Friedman, A. Hartman, K. Nagin, T. Shiran. Projected state machine coverage for software testing. Proc. of ISSTA 2002, Rome, Italy. Jul 2002. [RedVerst] http://www.ispras.ru/groups/rv/rv.html [Robinson] H. Robinson. Obstacles and opportunities for model-based testing in an industrial software environment. In proceedings of 1-st ECMDSE, 2003 [SCR] C. Heitmeyer. Software Cost Reduction. Encyclopedia of Software Engineering, Two Volumes, John J. Marciniak, editor, ISBN: 0-471-02895-9, January 2002. [SDL] J. Ellsberger, D. Hogrefe, and A. Sarma, SDL — Formal Object-Oriented Language for Communicating Systems, Prentice Hall, 1997. [SDLt] C. Bourhfir, E. Aboulhamid, R. Dssouli, N. Rico. A test case generation approach for conformance testing of SDL systems. Computer Communications 24(3-4): 319–333 (2001). [SLIC] T. Ball and S. Rajamani. SLIC: A specification language for interface checking (of C). Technical Report, MSR-TR-2001-21, Microsoft Research, January 2002. [TGV] J.-C. Fernandez, C. Jard, T. Jeron, and C. Viho. An experiment in automatic generation of test suites for protocols with verification technology. In Special Issue on Industrially Relevant Applications of Formal Analysis Techniques, J. F. Groote and M. Rem, editors, Elsevier Science publisher, 1996. [TorX] J. Tretmans, A. Belinfante. Automatic testing with formal methods. In EuroSTAR'99: 7th European Int. Conference on Software Testing, Analysis and Review, Barcelona, Spain, November 8-12, 1999. EuroStar Conferences, Galway, Ireland. Also:
155
67. 68. 69. 70. 71. 72. 73. 74. 75.
156
Technical Report TRCTIT-17, Centre for Telematics and Information Technology, University of Twente, The Netherlands. [TPA] J. Grabowski, D. Hogrefe, R. Nahm. Test case generation with test purpose specification by MSCs. In O. Faergemand and A. Sarma, editors, 6th SDL Forum, pages 253–266, Darmstadt, Germany, North-Holland 1993. [TPB] C. J. Wang, M. T. Liu. Automatic test case generation for Estelle. In International Conference on Network Protocols, pages 225–232, San Francisco, CA, USA, 1993. [TRover] http://www.time-rover.com [TRT] http://www.rational.com [TVEC] http://www.t-vec.com [UMBTG] E. Farchi, A. Hartman, and S. S. Pinter. Using a model-based test generator to test for standard conformance. IBM Systems Journal, volume 41, Number 1, 2002, pp. 89–110. [UML-TP] UML Testing Profile. http://www.omg.org/docs/ptc/03-07-01.pdf [UniArch] I. Bourdonov, A. Kossatchev, V. Kuliamin, and A. Petrenko. UniTesK Test Suite Architecture. Proc. of FME 2002. LNCS 2391, pp. 77-88, Springer-Verlag, 2002. [UNITESK] http://unitesk.ispras.ru
Оперативная интеграция данных на основе XML: системная архитектура BizQuery* К.В. Антипин, А.В. Фомичев, М.Н. Гринев, С.Д. Кузнецов, Л.Г. Новак, П.О. Плешачков, М.П. Рекуц, Д.Р. Ширяев Аннотация. При возрастающем интересе к решению проблемы интеграции распределенных и разнородных источников данных виртуальный подход представляется перспективным и многообещающим. В своей общей постановке эта проблема исключительно сложна, и до сих пор ее решению уделялось недостаточное внимание. Однако быстрое развитие XML – многофункционального формата представления данных – и языков запросов к XML-данным, таких как XQuery, позволяет по-новому взглянуть на старую проблему. В статье содержится описание общей архитектуры BizQuery – системы виртуальной интеграции, основанной на модели данных XML. В системе локальные источники единообразно отображаются на глобальную схему как ее представления в терминах XML и UML на основе использования декларативных языков XQuery и UQL. Обсуждаются вопросы отображения схем, оптимизации, декомпозиции и выполнения запросов в системе виртуальной интеграции. Ключевые слова: виртуальная интеграция данных, XML, XQuery, UML, оптимизация запросов, декомпозиция запросов, обработка запросов, трансформация схем
1. Введение Интеграция разнородных гетерогенных данных является одной из старейших задач в области разработки баз данных и информационных систем. Кратко, проблема может быть сформулирована следующим образом. Предположим, имеются несколько гетерогенных источников данных, которые каким-то образом связаны на логическом уровне. Имеется задача предоставить программное обеспечение, которое обеспечивало бы возможность унифицированного доступа к этим данным, как будто бы они имели единое логическое и
*
Проект выполнялся исследовательской группой MODIS Института системного программирования РАН (http://www.ispras.ru/groups/modis/modis.html ) в сотрудничестве с международной компанией ATS (www.atssoft.com) при поддержке РФФИ (гранты 02-01-01088-а и 02-07-90300-в).
157
физическое представление. Мы не будем обосновывать очевидную важность этой проблемы. Существуют два фундаментальных подхода к решению этой проблемы. Первый подход связан с построением хранилищ данных, когда интегрируемые данные из разных источников трансформируются в соответствии с целевой моделью данных и помещаются в одну локальную базу данных. По поводу этого подхода имеется обширная литература, современное состояние дел описывается, например, в [1]. Второй подход связан с понятием виртуальной интеграции гетерогенных источников данных, когда данные не материализуются в локальной базе данных, а используется промежуточное программное обеспечение, которое транслирует пользовательские запросы в подзапросы к источникам и формирует окончательный результат. Краткий обзор эволюции систем, использующий виртуальный подход, включая мультибазы данных [2] и федеративные базы данных [3], может быть найден в [4]. Подход этих систем был связан, прежде всего, с интеграцией данных с четкой структурой (хотя структура могла быть разная). Следующим этапом было возникновение систем интеграции на базе медиаторов [5], которые создавались на основе полуструктурированных данных [6]. Возникновение XML [7] и сопутствующих технологий (XSLT [8], XQuery [9]) вызвало всплеск новых разработок по тематике виртуальной интеграции [10], [11] и т.д. Система виртуальной интеграции BizQuery на основе технологий XML [7] и UML [12], обсуждаемая в этой статье, является результатом работы исследовательской группы, которая на протяжении последних четырех лет занимается вопросами исследования и разработки методов управления XML-данными. Основные возможности BizQuery заключаются в следующем: интегрированный доступ к нескольким источникам данных, которые могут быть реляционными или содержать XML-данные; использование XML как для внутреннего представления данных, так и для представления результата; представление глобальной схемы интегрированных данных как в терминах UML, так и в терминах XML; возможность формулировки запросов к интегрированным данным с использованием декларативных языков запросов UQL (разработка группы [4]) и XQuery в терминах UML и XML соответственно; развитая обработка запросов, включая оптимизацию запросов; декомпозицию запросов на частичные запросы, адресуемые к индивидуальным источникам данных; формирование окончательного результата с потенциальным выполнением соединений и трансформаций данных. Основная цель проекта BizQuery состояла в проведении исследований по проблематике подхода виртуальной интеграции и реализации “приближенной к жизни” системы виртуальной интеграции на основе XML-технологий. 158
Участники проекта пытались показать, что создание практической системы на основе XML технологий с учитом прошлого опыта разработки систем виртуальной интеграции вполне возможно. В статье рассматривается общая архитектура системы и концепции, которые были заложены в ее основу, объясняется, почему были выбраны именно такие подходы к решению задачи. Основная часть статьи организована следующим образом. В разделе 2 описывается общая архитектура системы BizQuery. В разделах 3 и 4 обсуждаются детали двух основных компонентов системы — BizQuery Mapper и BizQuery Integration Server. В разделе 5 приводятся некоторые результаты, демонстрирующие производительность системы при ее испытаниях на тестовых наборах данных и запросов. Раздел 6 является заключением статьи.
Рис 1. Структура системы: (a) – подготовительная фаза; (b) – рабочая фаза
2. Архитектура и структура системы В этом разделе рассматривается архитектура системы BizQuery и поясняется назначение основных компонентов. Прежде всего, выделяются две фазы использования системы: подготовительная фаза (Рис. 1(a)) и рабочая фаза, на которой система обрабатывает запросы к интегрируемым данным (Рис. 1(b)). 159
Прежде чем адресовать запросы интеграционной системе, необходимо выполнить ряд подготовительных действий, таких как создание глобальной схемы инте-грируемых данных в терминах UML и XML, сбор информации о схемах инте-грируемых источников и построение отображения схем источников на глобальную схему. Эти подготовительные действия происходят при выполнении подготовительной фазы. Метаданные, созданные на этом этапе, помещается в BizQuery Repository, и затем они используется во время выполнения запросов. Необходимо заметить, что во время развертывания системы происходит работа только с метаданными, то есть со схемами источников и глобальной схемой, а не с данными.
2.1. Фаза развертывания системы BizQuery предоставляет два интерфейса доступа к данным: в терминах глобальной UML-схемы и в терминах глобальной XML-схемы. Процесс внедрения начинается с конструирования глобальной UML-схемы, которая служит для моделирования предметной области и представляет собой диаграмму классов UML. При конструировании этой схемы во внимание должны приниматься одновременно два фактора. Во-первых, схема должна соответствовать требованиям будущих пользователей. Во-вторых, схема должна быть адекватной доступным или предполагаемым источникам данных, которые требуется интегрировать. За отслеживание этих факторов отвечает специалист, выполняющий подготовительную фазу. Затем эта схема автоматически преобразуется в XML-документ в формате XMI [13], который представляет собой глобальную XML-схему. Необходимо отметить, что глобальная XML-схема является ключом для функционирования системы, не важно, каким образом эта схема была произведена. Иначе говоря, для интеграции данных в терминах XML совершенно не обязательно создавать UML-схему, если есть возможность сразу предоставить XML-схему. От интегрируемых источников на этом этапе требуется только схема хранимых данных. Поскольку для системы интеграции нужна, прежде всего, структурная информация об источниках, для хранения схемы использовался формат DTD. В настоящее время происходит миграция на Relax NG[14]. Для XMLисточников схема данных должна быть предоставлена вручную, для реляционных источников схема получается автоматически средствами системы. Завершающий и наименее тривиальный этап фазы развертывания состоит в построении отображения схем локальных источников на глобальную XMLсхему. Выполнение этого процесса поддерживается компонентом системы BizQuery Mapper, который обсуждается в разд. 3.
2.2. Архитектура времени выполнения Подсистема BizQuery времени выполнения содержит два основных компонента: BizQuery Integration Server (BQIS) and User Interface Management Server (UIMS). BQIS отвечает за обработку запросов, сформулированных на 160
языках UQL или XQuery. Однако все UQL-запросы транслируются в XQueryзапросы, и реальное выполнение запроса производится в терминах XML. Эта трансляция возможна благодаря наличию метаданных, поскольку, с одной стороны, эти метаданные описывают исходную модель, а с другой стороны, сами представляются в формате XML. В прямо сформулированный или полученный из UQL-запроса XQuery-запрос подставляются представления локальных источников, хранимые в BizQuery Repository (заметим, что в результате этой подстановки запрос переформулируется в терминах схем локальных источников, и структура запроса существенно усложняется). После этого запрос оптимизируется логическим оптимизатором путем применения правил перезаписи, что приводит к значительному упрощению и “улучшению” структуры переформулированного запроса. Это один из наиболее важных шагов обработки запроса. Обсуждение применяемых методов содержится в разд. 4. Далее, оптимизированный запрос декомпозируется в набор частичных запросов (по прежнему на XQuery), каждый из которых формулируется в терминах локальной схемы соответствующего локального источника данных (по одному частичному запросу на один локальный источник). Каждый частичный запрос транслируется соответствующей “оберткой” (wrapper) на язык запросов, понимаемый локальным источником (в настоящее время поддерживаются обертки для SQL и XQuery). Трансляция на XQuery тривиальна, но пере-формулировка произвольного XQuery-запроса к реляционным данным в SQL-запрос не очень проста. Этот вопрос обсуждается в статье позже. После декомпозиции запрос разбивается на набор частичных запросов к локальным источникам и так называемую “межисточниковую часть” (т.е. часть запроса, для выполнения которой нужны данные одновременно от нескольких локальных источников), которая должна выполняться самой системой интеграции, в случае BizQuery за это отвечает компонент, называемый XQuery Execution Engine. Выше мы привели лишь краткую характеристику основных компонентов BQIS и шагов обработки запросов, адресованных к системе интеграции. Детали приводятся в разд. 4. BQIS реализует API для взаимодействия клиентских приложений с интеграционным сервером посредством адресации XQuery и UQL запросов, то есть реализует низкоуровневый интерфейс доступа к данным, который, вообще говоря, не пригоден для конечных пользователей. Компонент UIMS призван сгладить разрыв между пользователем и BQIS. Он предоставляет три графических интерфейса пользователя доступа к данным в терминах UML. Catalogs обеспечивает навигационный интерфейс доступа к данным, предоставляя пользователю возможность просматривать существующие экземпляры классов UML-модели и переходить по ссылкам от одного экземпляра к другому. Два других интерфейса — Forms и Graphic Map — декларативные. Они позволяют перемещаться по UML-модели и накладывать 161
условия на атрибуты экземпляров класса. В обоих случаях в результате действия пользователя генерируется UQL-запрос, который адресуется BQIS, а полученный результат отображается на экране. Поскольку пользователь оперирует только понятиями UML-модели, выразительных средств UQL достаточно для формулирования запроса. UIMS реализован в виде Web-приложения и обладает развитыми возможностями настройки, благодаря использованию XSLT. Графический интерфейс пользователя генерируется автоматически по UML-модели, хранящейся в BizQuery Repository.
2.3. Декларативные языки запросов системы BizQuery В соответствии с двумя уровнями интеграции данных (XML и UML), поддерживаются два языка запросов интегрированных данных, а именно XQuery и UQL. Язык XQuery, развиваемый консорциумом W3C, был выбран как будущий стандарт языков запросов XML-данных. В системе BizQuery пользователь с помощью XQuery может оперировать двумя типами сущностей: виртуальными документами, которые стоят за глобальной XML схемой (посредством указания ключевого слова virtual в функции document, например document("virtual:foo.xml")), и реальными документами, которые представляют собой действительно существующие документы XML-источников или таблицы реляционной базы данных (посредством указания ключевого слова real, например document("real:sql/foo")). В первом случае пользователь оперирует виртуальным документом или представлением, за которым стоят запросы к реальным документам. Во втором случае пользователь работает с сущностями интегрируемых источников (поскольку вся обработка данных производится в терминах XML, реляционные таблицы путем тривиального отображения представляются в виде XML документов). В ходе работы над средствами манипулирования данными была осознана потребность в создании языка запросов, который бы оперировал в терминах UML-модели. Этим языком стал UQL. Он служит для выборки экземпляров класса (т.е. объектов, которые соответствуют структуре, определенной на UML) построенной диаграммы классов (глобальной UML-схемы в случае BizQuery). В основу UQL был положен язык OCL [12], который является частью спецификации UML, с несколько измененным и синтаксисом и семантикой. Основное назначение OCL состоит в определении ограничений данных, соответствующих модели (диаграмме классов), в терминах этой UML-модели. Коротко говоря, UQL позволяет запрашивать экземпляры классов посредством накладывания условий на атрибуты, перемещения по связям между экземплярами классов и использования кванторов всеобщности и существования. Более подробное описание UQL см. в [4]. 162
Вот пример UQL-запроса: “Найти все открытые аукционы (экземпляры класса open_auction), в которых цена больше 40, и покупатель имеет годовой доход не меньше 50000”. context model-id("1803"): extent(closed_auction)=> select(c|c.price>"40" and c!buyer@person=>exist(p|p.income>="50000"))
3. BizQuery Mapper Как отмечалось выше, основная задача фазы развертывания состоит в построении отображения локальных источников данных на глобальную XML схему. Понятно, что глобальная схема данных может быть, вообще говоря, произвольной, и отображение локальных источников на нее является нетривиальным: документы могут подвергаться сложным трансформациям, на их основе могут строиться новые документы, которые затем вновь подвергаются трансформациям и т.д. Прежде, чем рассказывать про BizQuery Mapper — компонент системы, который занимается решением поставленной задачи, обсудим возможные способы построения отображения между схемами. В общем смысле эта задача может быть переформулирована следующим образом. Пусть имеются некоторые данные, соответствующие схеме A. Как преобразовать эти данные, чтобы они соответствовали схеме B? Имеется несколько методов решения этой проблемы: 1. Написание программы. Можно написать программу на языке общего назначения, например, таком как C или Java, которая преобразует данные, соответствующие схеме A, в данные, соответствующие схеме B. 2. Преобразование вручную. Пользователь может написать запросы на языке запросов, которые применяются к данным, представленным в схеме A, и возвращают данные в представлении, соответствующем схеме B. Этот метод, как и все последующие, обладает тем преимуществом перед первым методом, что запросы могут подвергаться оптимизации. 3. Преобразования с использованием высокоуровневых операций. В этом случае от пользователя требуется описать преобразования схемы A в терминах операций над деревьями, а не узлами, как принято в XML. После этого выражения высокоуровневой алгебры деревьев транслируются в запросы на языке запросов, которые применяются к данным. Результаты запросов должны соответствовать схеме B. 4. Сопоставление схем. В этом подходе предполагается, что сама система отыскивает узлы, соответствующие один другому, и пользователь получает возможность более точного выполнения отображения. В результате формируется запрос на языке запросов. 163
5.
Автоматическое преобразование с использованием высокоуровневых операций. Этот метод представляет собой вариант метода 3, но преобразование производится автоматически на основе семантики и статистики данных. 6. Автоматическое сопоставление схем. Этот метод является вариантом метода 4, но он полностью автоматизируется. В соответствии с приведенной классификацией BizQuery Mapper базируется преимущественно на методе 3 и, частично, на методе 4. Основным соображением при выборе подхода было то, что у пользователя не должно быть принципиальных ограничений при построении отображения одной схемы на другой. При этом он должен иметь относительно удобный интерфейс и манипулировать высокоуровневыми терминами. Алгоритмы сопоставления схем являются приятным, но не обязательным дополнением. От пользователя не должны требоваться такие дополнительные сведения, как описание семантики данных или статистика. Итак, схема B получается из схемы A итеративным путем, посредством последовательного применения функций трансформации. Операции трансформации замкнуты относительно множества схем, то есть представляют собой алгебру. Единственным ограничением является то, что результирующая схема должна быть принципиально выводимой из исходной. На практике это означает, что в трансформациях не должно быть зависимости по данным; например, ситуация, где содержимое элемента становится именем нового элемента, недопустима. Ниже приведен список функций трансформации (в основу была положена не минимальность набора, а удобство использования): 1. Простые преобразования 2. Преобразование соединения 3. Преобразование корня 4. Вертикальная проекция 5. Горизонтальная проекция 6. Базовые конструкторы 7. Реструктуризация 8. Преобразования объединения 9. Сложные конструкторы. С помощью приведенных операций, которые манипулируют поддеревьями, а не узлами или последовательностями узлов XML-документа, многие запросы, такие, как получить исходный документ, в котором атрибут по определенному пути удваивается, выражаются проще, чем на XQuery. Тем не менее, отображение, построенное в высокоуровневых терминах, переводится в XQuery — целевой язык системы интеграции, микрооперации которого проще оптимизировать и выполнять. 164
BizQuery Mapper, обеспечивающий описанную выше функциональность, реализован в виде отдельного компонента, который предоставляет удобный графический интерфейс в стиле drag-and-drop для проведения трансформаций.
4. BizQuery Integration Server В этом разделе обсуждается компонент BizQuery, отвечающий за выполнение XQuery- и UQL-запросов. Он состоит из следующих частей: синтаксический анализатор языков UQL и XQuery, транслятор UQL-запросов в запросы на языке XQuery, оптимизатор, подсистема выделения подзапросов, подсистема выполнения XQuery-запросов и подсистема оберток для связи с источниками данных. Не секрет, что при построении систем виртуальной интеграции приходится сталкиваться с существенными ограничениями производительности таких систем, и как следствие, время ожидания ответа пользователем может быть неудовлетворительным. В качестве основных причин можно указать отсутствие актуальной статистики распределения данных и отсутствие структур данных, позволяющих оптимизировать доступ к данным (то есть индексов). Определенные проблемы связаны также с задержкой передачи данных по сети и их последующим преобразованием во внутренний формат для обработки. Эти проблемы возникают из-за того, что виртуальная интеграционная система не материализует интегрируемые данные. По всей видимости, системы виртуальной интеграции никогда не смогут достигнуть производительности систем, основанных на хранилищах данных, однако они вполне могут быть пригодны в тех случаях, когда действительно необходимы актуальные данные. В ходе работы над ядром BizQuery Integration Server были выделены три составляющие ядра, которые, вероятно, являются ключевыми для эффективной обработки запросов (перечислены в порядке убывания важности). 1. Логическая оптимизация на основе перезаписи запросов (преобразование и упрощение); 2. Декомпозиция запросов (выделение максимального частичного подзапроса, адресованного к локальному источнику); 3. Потоковая обработка на стороне сервера и, по возможности, на уровне источников данных. Далее эти составляющие рассматриваются подробнее, и поясняется, почему они являются ключевыми.
4.1. Логическая оптимизация Значимость оптимизатора запросов для СУБД трудно переоценить: разница во времени выполнения исходного запроса и оптимизированного запроса может различаться на порядки. В настоящее время во многих промышленных СУБД 165
используется так называемая оценочная оптимизация (cost-based optimization), то есть выбор оптимального плана выполнения запроса из множества возможных планов производится на основе оценки стоимости выполнения операции. Оптимальным считается тот план, совокупная стоимость операций которого является наименьшей. Другой метод оптимизации основан на правилах эквивалентного преобразования запросов на основе эвристик с целью получения нового запроса, который является эффективнее первого. Такой вид оптимизации носит название оптимизации на основе правил (rule-based optimization), или перезаписи запросов (query rewriting). Именно этот подход применяется для оптимизации в BizQuery. Это связано со следующими основными причинами: в виртуальной интеграционной системе отсутствует статистика, на основе которой можно было бы оценить стоимость операций (данные в источниках могут изменяться без ведома системы интеграции); обычно пользовательский запрос адресуется к виртуальному документу (т.е. к представлению), после выполнения подстановки тела представления содержит много лишней информации и, таким образом, поддается существенному упрощению. Особенно важен последний пункт, так как в зависимости от сложности виртуального документа размер запроса может отличаться на порядки. Перечислим список целей, достигаемых посредством перезаписи запросов в системе BizQuery: сокращение объема запроса после подстановки тела представления; “выталкивание” (push down) предикатов (как можно более раннее применение предикатов) и устранение избыточных вычислений (например, конструирования элементов до обработки путевых выражений); повышение уровня декларативности запроса (например, путем нахождения конструкций, эквивалентных соединениям); частичная перезапись запроса, содержащего вызовы рекурсивных функций, в запрос без рекурсии (с использованием схемы данных) с последующей оптимизацией; преобразование запроса в более “целенаправленную” форму на основе информации из схемы с возможным устранением избыточных просмотров данных (например, замена метасимвола в путевом выражении именем некоторого XML-элемента). Необходимо заметить, что поскольку в XQuery отсутствует явное понятие соединения, потребовалось ввести такую логическую (и физическую) операцию, что привело к созданию расширенной модели данных XQuery. Обычно соединение выражается через FLWR-выражение (что навязывает конкретный алгоритм выполнения — соединение путем использования вложенных циклов), и поэтому выделение соединения в виде отдельной операции повышает декларативность запроса, так как становится возможным 166
использовать другие, зачастую более эффективные алгоритмы. Тем не менее, наличие упорядоченности в XQuery понижает уровень значимости этой декларативности (например, из-за того, что нельзя произвольным образом изменять порядок выполнения соединений). Этап логической оптимизации на основе перепизаписи крайне важен еще и по следующей причине. Результатом переписывания запроса является запрос вполне определенного (“нормализованного”) вида. Условно, дерево запроса можно поделить на три части: в листьях дерева расположены операции выборки данных с накладываемыми на данные условиями; в центре дерева находятся операции соединения; верхняя часть запроса состоит преимущественно из трансформаций данных (рис. 2a). Подобная нормализация запроса играет важнейшую роль на этапе декомпозиции запросов, который будет рассматриваться ниже.
Рис. 2. Схема XQuery-запроса: (a) — после нормализации; (b) — после декомпозиции запроса Подробнее правила перезаписи XQuery-запросов обсуждаются в [15].
4.2. Декомпозиция запросов Задача декомпозиции запроса состоит в том, что требуется разбить запрос на части таким образом, что определенные части будут выполняться на стороне источников данных, а оставшаяся часть – на стороне интеграционной системы. В зависимости от типов интегрируемых источников существуют две диаметрально противоположные позиции по этому вопросу. Одна позиция связана с рассмотрением источников, которые предоставляют крайне ограниченные выразительные средства для формулирования запросов, например, имеют в качестве интерфейса HTML-формы [16]. Другая позиция подразумевает, что в источниках поддерживаются развитые, декларативные языки запросов. Система BizQuery ориентирована на второй случай. Более точно, как отмечалось ранее, BizQuery ориентируется на два типа источников — реляционные системы с интерфейсом SQL и системы, поддерживающие язык XQuery. Тогда задача декомпозиции запроса сводится к выделению “максимального” частичного запроса к источнику. Другими словами, 167
источникам адресуются максимально возможные компоненты исходного запроса, которые они в состоянии выполнить. Например, если в исходном запросе имеются такие потребляющие много ресурсов операции, как соединение или сортировка, относящиеся к одному источнику, то они отдаются в источник при условии, конечно, что источник в состоянии их выполнить. Преимущества выделения максимального подзапроса состоят в следующем: Параллельное выполнение максимальных частей исходного запроса (части исходного запроса, адресуемые различным источникам, могут выполняться параллельно). Развитые источники данных зачастую способны выполнять запросы быстрее, чем интеграционная система, поскольку в них имеется более полная информация о хранимых данных (например, развитая структура индексов). В типичных случаях размер передаваемого по сети результата частичного запроса намного меньше общего размера документа, хранимого в соответствующем источнике данных (в частности, по причине наличия в частичном запросе условий выборки). Итак, в случае BizQuery задача разбивается на нахождение в дереве запроса максимальных поддеревьев, относящихся к одному источнику, и перевод их на язык запросов, поддерживаемый источником. Оставшаяся часть дерева запроса содержит операции, для выполнения которых требуются данные из разных источников (для краткости будем называть такие операции “кроссдоменными”), и эти операции должны быть выполнены на стороне интеграционной системы (рис. 2b). Необходимо заметить, что для полноценного выделения частичных запросов крайне важно, чтобы запрос находился в нормальной форме, о которой говорилось выше (рис. 2a). Поскольку листья дерева запроса представляют собой выражения XPath, можно гарантировать возможность их выполнения в источниках данных, поддерживающих соответствующий язык запросов. Выше по дереву находятся операции соединения и полусоединения, которые тоже могут быть переданы для выполнения источникам данных, если их операнды черпаются только из одного источника данных. Таким образом, на стороне интеграционной системы приходится выполнять только те операции соединения и полусоединения, которые являются кроссдоменными (в том числе, если они прямо или косвенно опираются на результаты других кроссдоменных операций). Если в дереве запроса существует хотя бы одна кроссдоменная операция, которая должна быть выполнена до уровня трансформации, то трансформация тоже выполняется на стороне интеграционной системы. Приведем пример декомпозиции запроса. Предположим, что имеется запрос, содержащий обращения к двум документам одного реляционного источника (схемы документов представлены в табл. 1 в виде DTD); запрос выдает данные об отделах, в которых имеются сотрудники моложе 20 лет. 168
for $d in document(“real:sql1/deps”)/table/tuple where some $e in document(“real:sql1/emps”)/table/tuple[age < 20] satisfies $d/id = $e/dep_id return element dep {$d/name, element additional {$d/address}} document(“real:sql1/deps”)
document(“real:sql1/emps”)
Табл. 1. Схемы документов источников данных в виде DTD Запрос содержит полусоединение (определяется разделами for и where) двух документов одного источника, которое может быть выполнена на стороне источника, а также трансформацию, не поддерживаемую реляционным источником. Ниже показан подзапрос к источнику sql1. select * from deps where (exists (select * from emps where deps.id = emps.dep_id and emps.age < 20)) Заметим, что представленную ранее нормальную форму XQuery-запроса можно подвергнуть определенной критике. Очевидно, что существует ряд простых трансформаций, которые могут быть выполнены ранее операций соединения (например, вертикальная проекция на стороне реляционного источника). Однако для выполнения таких трансформаций не требуется слишком много ресурсов, и их выполнение на стороне интеграционной системы не сильно сказывается на производительности. Значительно важнее выделить именно “тяжелые” операции, такие как соединения и сортировки.
запрос содержит трансформации, не поддерживаемые источником (например, реляционные источники способны выполнять крайне ограниченный набор трансформаций). По этим причинам в состав BizQuery входит полнофункциональный процессор подмножества языка XQuery. Введенная разработчиками явная операция соединения реализована в виде физической операции, что позволило повысить производительность системы. Была адаптирована итераторная модель (называемая также моделью “topdown”) выполнения запросов [17], которая широко применяется в реляционных СУБД. Это позволяет не материализовывать промежуточные результаты после вычисления каждой операции. На самом деле, такой подход к организации обработки запросов имеет далеко идущие последствия. Для многих пользовательских запросах в результате получается не единичный документ, а последовательность из нескольких (часто однотипных) XML элементов. Особенно это характерно для UQL-запросов, в результате которых получается последовательность элементов — экземпляров класса. Часто, особенно при использовании графического интерфейса, пользователю достаточно получить в качестве ответа на запрос первые n XML-элементов и иметь возможность в дальнейшем просмотреть оставшиеся элементы. Это подход соответствует понятию курсора, широко применяемому в реляционных СУБД, и позволяет существенно сократить время отклика системы на запрос пользователя. Строго говоря, в XQuery-процессоре был реализован так называемый потоковый или конвейерный подход к организации вычислений. В контексте того, что XQuery является функциональным языком (по крайней мере, его подмножество, поддерживаемое в BizQuery), это выразилось в реализации “ленивой” семантики (lazy semantics) XQuery. Вообще говоря, это является расхождением со спецификацией, так как по стандарту XQuery является языком со строгой семантикой (strict semantics). Однако применение ленивой семантики ни в коей мере не сокращает класс вычислимых запросов: если запрос вычислим в системе, использующей строгую семантику, то он вычислим и в системе с ленивой семантикой. Обратное утверждение неверно: некоторые запросы, не вычислимые в соответствии со спецификацией, могут быть вычислены системой BizQuery.
4.3. XQuery-процессор После стадии декомпозиции исходное дерево запроса преобразуется в физический план выполнения запроса, листья которого представляют собой подзапросы в терминах источников. При этом физический план, вообще говоря, может быть достаточно сложным для выполнения. Это связано преимущественно со следующими причинами: исходный запрос содержит кроссдоменные операции (например, соединение); 169
5. Анализ производительности В этом разделе представлены результаты тестирования производительности системы BizQuery. Насколько известно авторам, в открытом доступе сегодня не существует средств тестирования производительности систем, подобных BizQuery. Поэтому пришлось воспользоваться средством для тестирования XML СУБД — пакетом XMark [18] и адаптировать его для BizQuery. 170
Документ, соответствующий DTD XMark auctions, был разбит на части, которые были распределены по трем источникам — одному XML-источнику и двум реляционным. В качестве XML-источника выступала программа QuiP [19] компании Software AG, представляющая собой XQuery-процессор над файловой системой. В качестве реляционного источника использовалась СУБД Oracle 8i. Следует заметить, что QuiP не является полноценной СУБД, а также является прототипом. Поэтому производительность этого программного средства была невысокой, что повлияло на распределение данных. Кроме того, чтобы представить определенные части исходного документа в виде реляционных таблиц, пришлось упростить эти части (например, путем избавления от вложенности элементов). В результате первый реляционный источник содержал 5 таблиц, суммарное количество картежей которых превышало 1,8 миллиона. Второй реляционный источник содержал 3 таблицы с более чем 4,2 миллионами кортежей. Суммарный объем XML-файлов, по которым строились реляционные таблицы, превышает 700Mb. XML-источник содержал 4 файла, общим объемом 5,8Mb. В табл. 2 показаны запросы, для которых приводятся результаты измерения. Q1 Q2
Номер запроса Q1 Q2 Q3 Q4
Размер результата (в Kb) 23 12 3673 27
Общее время работы источников 5,984 82,485 67,907 52,766
Время работы BizQuery 0,078 1,796 3,093 0,938
Общее время выполнения запроса 6,062 84,281 71,000 53,704
Табл. 3. Результаты тестирования производительности BizQuery
for $x in document("real:sql1/item")/table/tuple where $x/QUANTITY="5" and $x/location="Germany" return $x for $y in document("real:sql2/interest")/table/tuple for $z in document("real:sql2/people")/table/tuple[business= "yes" and city="Moscow"]
Q3 Q4
Запрос Q1 адресуется реальному документу item (таблице реляционного источника 1) и просто налагает условие на данные. Запрос Q2 содержит два соединения, одно из которых выполняется между документами одного источника, а второе соединение — кроссдоменное — между разными реляционными источниками. Запрос Q3 показывает возможность построения виртуального документа closed_auctions.xml целиком. И, наконец, запрос Q4 выполняет соединение между виртуальным документом item.xml и реальным документом mailbox из второго реляционного источника. Результаты выполнения представлены в табл. 3.
for $x in document("real:sql1/categories")/table/tuple [name="all"] where $y/ref_category=$x/id_category and $y/ref_person= $z/id_person return ($x, $z) document("virtual:closed_auction.xml") for $v in document("virtual:item.xml")/item[location= "United States"] for $z in document("real:sql1/mailbox")/table/tuple[mail_date="12/11/99"] where $v/id=$z/ref_item return element {name($v)} {$v/*[not empty(./text())]}
Табл. 2. XQuery-запросы, использованные при тестировании Для измерения производительности использовалась следующая конфигурация. BizQuery Integration Server работал на Pentium-IV 1500Mhz c 512Mb RAM. Для XML-источника данных (QuiP) использовалась такая же машина. Оба сервера реляционных СУБД (Oracle) работали на машинах одинаковой конфигурации — Pentium-III 733Mhz с 256Mb RAM. Все машины работали под управлением Windows 2000. 171
Во всех четырех запросах, вне зависимости от общего времени выполнения, чистое время работы BizQuery (включающее оптимизацию и, если необходимо, выполнение кроссдоменных операций) относительно невелико. Это обеспе-чивается посредством перезаписи запросов (особенно в случае запроса Q4, где производится соединение виртуального документа с реальным) и декомпозиции запросов, которая приводит к выделению наиболее дорогостоящей части запроса и передачи ее для выполнения источнику. Заметим, что общее время выполнения запроса можно было бы снизить, введя дополнительные индексы в источниках, однако рассмотрение данного вопроса выходит за рамки статьи. Ограниченный объем статьи не позволяет также привести примеры работы логического оптимизатора по существенному упрощению запросов, содержащих сложные трансформации (особенно те запросы, которые генерируются автоматически). Эти примеры чрезвычайно объемны.
6. Заключение В статье представлена архитектура системы виртуальной интеграции данных BizQuery, основанной на модели данных XML/XQuery, которая позволяет обращаться к данным как в терминах XML, так и в терминах UML. Обсуждены разработанные средства построения отображения глобальной схемы на локальные схемы источников. Рассмотрена роль декларативных языков запросов UQL и XQuery в системе BizQuery. Представлены средства автоматического построения пользовательского интерфейса по описанию модели интегрируемых данных в виде диаграммы классов UML. Обсуждена проблема 172
производительности систем виртуальной интег-рации, и были выделены три ключевых задачи, от решения которых зависит пригодность системы для пользователя с точки зрения времени ожидания ответа на запрос. Эти задачи были детально проработаны, и предложены решения. Правильность подхода подтверждена экспериментальными результатами. Проблема виртуальной интеграции данных была и остается исключительно сложной проблемой в области управления данными. Развитие технологии XML обеспечивает простую возможность унифицированного представления всех видов данных, но в то же время порождает ряд новых проблем, включающих более сложные методы оптимизации и выполнения запросов. При работе над проектом BizQuery авторы стремились обозначить эти проблемы и предложить их решения. Это позволило создать эффективную систему виртуальной интеграции данных и доказать практическую применимость подхода.
15. Grinev, M., Kuznetsov S.: Towards an Exhaustive Set of Rewriting Rules for XQuery Optimization: BizQuery Experience, 6th East-European Conference on Advances in Databases and Information Systems (ADBIS), LNCS 2435 (2002) 340-345 16. Levy, A., Rajaraman, A., Ullman J. D.: Answering Queries Using Limited External Query Processors, PODS (1996) 227-237 17. Graefe, G.: Query Evaluation Techniques for Large Databases, ACM Computing Surveys 25(2) (1993) 73-170 18. XMark — An XML Benchmark Project, http://www.xml-benchmark.org 19. QuiP. Software AG’s prototype of XQuery, http://developer.softwareag.com/tamino/quip/
Литература 1. A Selection of Papers on Datawarehousing, Computer, Vol. 14, No. 12 (2001) 2. Batini, C., Lenzerini, M., and Navathe, S.: A Comparative Analysis of Methodologies for Database Schema Integration, ACM Computer Surveys 18(4) (1986) 323-364 3. Sheth, A., Larson, J.: Federated Database Systems for Managing Distributed, Heterogeneous, and Autonomous Databases, ACM Computing Surveys 22(3) (1990) 183-236 4. Grinev, M., Kuznetsov, S.: UQL: A Query Language on Integrated Data in Terms of UML, Programming and Computer Software, Vol. 28, No. 4 (2002) 189-196 5. Wiederhold, G.: Mediators in the Architecture of Future Information Systems, IEEE Computer 25(3) (1992) 38-49 6. Chawathe, S., Garcia-Molina, H., Hammer J., Ireland, K., Papakonstantinou, Y., Ullman, J., Widom, J.: The TSIMMIS Project: Integration of Heterogeneous Information Sources, IPSJ (1994) 7-18 7. Extensible Markup Language (XML) 1.0, W3C Recommendation, 2nd edition (2000) http://www.w3.org/TR/2000/REC-xml-20001006 8. XSL Transformations (XSLT) 2.0, W3C Working Draft 15 November 2002, http://www.w3.org/TR/2002/WD-xslt20-20021115/ 9. XQuery 1.0: An XML Query Language, W3C Working Draft 15 November 2002, http://www.w3.org/TR/2002/WD-xquery-20021115/ 10. The Tukwila Data Integration System, University of Washington, http://data.cs.washington.edu/integration/tukwila/ 11. Xperanto Project, IBM Almaden Research Center, http://www.almaden.ibm.com/software/dm/Xperanto/index.shtml 12. Unified Modeling Language (UML), Specification Version 1.4, http://www.omg.org/technology/documents/formal/uml.htm 13. XML Metadata Interchange (XMI), Version 1.2 http://www.omg.org/technology/documents/formal/xmi.htm 14. RELAX NG Specification, Committee Specification 3 December 2001, http://www.oasis-open.org/committees/relax-ng/spec-20011203.html
173
174
Композиционный подход к построению программных приложений визуализации* В.А. Семенов, Е.В. Алексеева, С.В. Морозов, О.А. Тарлапан Аннотация. В статье предлагается подход к построению программных приложений визуализации с использованием формально специфицируемых правил преобразования информационных моделей друг в друга. Визуализация рассматривается как процесс отображения прикладной модели на ее визуальные представления. Подход позволяет формально связать прикладную и визуальную модели, специфицировать сценарий визуализации в виде композиции отображений и затем генерировать требуемые визуальные сцены для конкретных наборов прикладных данных путем выполнения сценария. Будучи реализованным, подход позволяет визуализировать сложные междисциплинарные данные с применением разнообразных, настраиваемых в ходе работы приложения методик в строгом соответствии со специфицируемыми правилами. В результате программные приложения выигрывают в выразительности, а также приобретают дополнительную надежность, гибкость и возможность многократного использования в новых прикладных контекстах. Обсуждаются различные возможности для эффективной реализации подхода. Они связаны с использованием предложенного декларативного языка потоков данных EXPRESS-F и описываемой инструментальной среды разработки приложений визуализации общего назначения. Применение подхода иллюстрируется на примере приложения, предназначенного для макетирования архитектурно-строительных проектов с использованием технологий виртуальной реальности. Ключевые слова: STEP, EXPRESS, IFC, VRML97, X3D.
1. Что такое визуализация? Введение Что такое визуализация? Ответ на этот вопрос довольно нетривиален. Имеется множество частных примеров «правильной» визуализации, но до сих пор нет методического понимания, что же из того, что составляет хорошую визуализацию, являлось бы привлекательным для естественных моделей, человеческого восприятия и внутреннего зрения. Множество людей определяли понятие визуализации различными способами [1]. *
Работа поддержана РФФИ, гранты 01-01-00239, 03-01-06422
175
Рене Декарт (1637): «Воображение или визуализация, и, в частности, использование диаграмм, играет значительную роль в научных исследованиях». Александр фон Гумбольд (1811): «Все, что относится к мере и количеству, может быть представлено геометрическими образами. Статистические проекты, которые обращаются к органам чувств, не утомляя разум, обладают преимуществом привлечения внимания к большему числу важных фактов». Маккормик и др. (1987): «Визуализация — это вычислительный метод. Она преобразует символические образы в геометрические, позволяя исследователям наблюдать их моделирование и вычисление. Визуализация предлагает метод для наблюдения невидимого. Она обогащает процесс научного открытия и способствует глубоким и непредвиденным проникновениям в суть вещей. … Много лет тому назад Ричард Хамминг заметил, что: «цель вычислений — это понимание, а не числа». Цель визуализации заключается в усилении существующих научных методов путем обеспечения нового научного понимания через визуальные методы». Роговиц (1993): «Визуализация — это процесс отображения численных значений в воспринимаемое познаваемое пространство». Кроме исторических проблем эволюции знаний, причина неоднозначности взглядов заключается в разнообразии исследуемых проблематик, существенных различиях моделей, подлежащих визуализации, и широком наборе методов и техник, которые бы потенциально подходили для достижения подобных целей. Тем не менее, интересно заметить, что все эти определения сводятся к трансформированию или отображению данных в некоторые воспринимаемые представления, допускающие четкую зрительную интерпретацию. Следовательно, отображение данных в зрительно связанные образы может рассматриваться как основной принцип визуализации в целом и ее многочисленных приложений в частности. Действительно, традиционный конвейер визуализации может быть представлен как композиция отображений, соответствующих общеизвестным стадиям подготовки исходных прикладных данных, их визуализации, моделирования производных визуальных сцен, в частности, с использованием технологии виртуальной реальности, и, наконец, рендеринга и отображения сцен [2]. Здесь под прикладными данными понимается произвольная структурированная типи-зированная информация, используемая в различных областях промыш-ленности, бизнеса и науки. На первой стадии конвейера исходные данные проходят предварительную обработку для исключения возможной избы-точности, а также для их улучшения и обогащения. При этом не имеет значения, выполняются ли эти отображения над данными, принадлежащими той же самой информационной модели, или разным. Стадия визуализации соответствует отображению данных из одной символической модели в другую, имеющую явное визуальное содержание, такое как пространство, время, форма, звук, и т.д. На следующей стадии полученное 176
визуальное представление может быть дополнительно преобразовано в сцены моделирования виртуальной реальности, непосредственно поддерживаемые популярными Интернет-браузерами и интерфейсами (API) графических программных систем. На заключительной стадии происходит формирование и отображение изображений моделируемых сцен, что соответствует отображению визуальной сцены в генерируемые цифровые изображения, которые и являются конечной целью процесса визуализации. Таким образом, все стадии могут рассматриваться как отображения одних данных в другие. Под более пристальным взглядом каждая из этих стадий может быть также представлена как композиция отображений, выполняющих частичные преобразования типизированной информации. Каждое отображение реализует некоторое правило, согласно которому типизированные информационные элементы, принадлежащие одной модели, должны быть трансформированы в соответствующие элементы другой модели. Из-за высокой степени интеграции и сложности разработанных в последнее время многопрофильных информационных моделей, содержащих тысячи взаимосвязанных типов данных, программирование приложений визуализации оказывается трудной задачей, поскольку требует обработки значительной части подобной всеобъемлющей информации. Чтобы визуализировать прикладные данные эффективно и адекватно выбранным аспектам изучаемой проблемы, методы и сценарии визуализации должны опираться на подходящую визуальную метафору. Очевидно, что такие программы могут быть очень сложны и нуждаются в более строгой структуризации, а также в предусмотренных средствах адаптации и расширения с использованием некоторого общего формализма, содержательного для приложений визуализации. Другая мотивация выработки формализма и следования ему при разработке программных приложений связана с требованием согласованного управления прикладными данными и их визуальными представлениями, существенным для интерактивных систем. В таких приложениях изменения визуальных сцен, вызванные реакциями пользователя, должны передаваться через все стадии конвейера визуализации в обратном порядке, чтобы привести прикладные данные в соответствие с их визуальным образом. Для достижения такой цели могут применяться композиции обратных преобразований. Например, при проектировании здания архитектор манипулирует визуальными примитивами, такими как ломаные, поверхности, твердые тела, цветовые палитры, непосредственно отображаемыми в графическом контексте приложения. Но эти манипуляции интерпретируются и обрабатываются как операции над прикладными данными, представляющими стены, окна, перекрытия, крыши и так далее, значимыми в этой прикладной области. Подобным образом, при изучении и исследовании магнитных, электрических, гравитационных полей посредством манипулирования визуальными сценами, геофизик фактически восстанавливает прикладные данные, соответствующие значимым в геологии свойствам горизонтов, скважин, областей и т.д. 177
ИСХОДНЫЕ НАБОРЫ БИЗНЕС-ДАННЫХ
ПРЕДОБРАБОТКА Интерполяция, фильтрация, сглаживание, и т.д.
ВИЗУАЛИЗАЦИЯ Отображения в пространство, время, форму, звук, и т.д.
МОДЕЛИРОВАНИЕ СЦЕН
ВИЗУАЛЬНОЕ УПРАВЛЕНИЕ Обратная связь, интерактивность, и т.д.
Преобразование в VR сцены, графические API, и т.д.
РЕНДЕРИНГ Геометрические преобразования, отсечение, освещение, и т.д.
ЦЕЛЕВЫЕ ИЗОБРАЖЕНИЯ
Рис. 1. Представление традиционного конвейера визуализации как композиции отображений Упомянутые выше обстоятельства побудили нас взглянуть на дисциплину визуализации через призму парадигмы композиции отображений, для того чтобы выработать формальный подход к программированию приложений визуализации и предложить конструктивные способы его реализации. В разделе 2 описан формальный подход к определению синтаксиса и семантики отображений. При этом мы следуем объектно-ориентированному моделированию информации, относящейся к прикладной и визуальной предметным областям. В разделе 3 представлены декларативный язык EXPRESS-F и инструментальная среда разработки приложений визуализации общего назначения, реализующие формализованный подход. В разделе 4 178
приводятся некоторые иллюстрирующие его примеры приложений визуализации. Особое внимание в данных примерах уделяется практическим преимуществам предлагаемого подхода, которые кратко резюмируются в заключительном разделе.
2. Формальный подход Представим подход к визуализации, рассмотрев сначала понятия, представляющие информационную метамодель, подходящую для специфицирования прикладной и визуальной предметных областей. Язык моделирования данных EXPRESS используется здесь с тем, чтобы проиллюстрировать вводимую концепцию и подтвердить ее применимость по отношению к другим языкам и реализационным платформам. Затем приступим к формализации отображений, устанавливающих взаимосвязь между визуальной и прикладной моделями, а также налагающих правила, согласно которым визуальные образы могут быть однозначно соотнесены с исходными прикладными данными. Формализация подхода следует методу, используемому в семантическом анализе языков [3, 4]. Для рассматриваемого подхода не имеет принципиального значения, какой именно язык используется в качестве средства его реализации. В частности, как декларативные, так и исполняемые объектно-ориентированные языки, например, UML, BON, OPEN, C++, Java, Eiffel, C#, потенциально подходят для спецификации и реализации приложений визуализации с использованием представленного ниже подхода.
2.1. Объектно-ориентированная метамодель Итак, определим объектно-ориентированную метамодель как структуру M (C , , AttrC , RuleC ) со следующим значением: C — множество классификаторов, которые представляют различные типы объектов. Иерархия подтипов, порождаемая отношениями обобщения/специализации классификаторов, используется в качестве основы для встраиваемого механизма полиморфизма; — частичный порядок на C, отражающий иерархию типов объектов и специализацию классификаторов; AttrC — множество атрибутов или, точнее, множество сигнатур операций a c : c s , a c : c s c для функций доступа к значениям атрибутов. Каждый атрибут объекта типа s C может представлять свойство ассоциации с объектами того же типа c C ; RuleC — множество ограничений, на основе которых определяются поведенческие характеристики объектов. Они могут определять количество, тип и организацию атрибутов, а также налагать
179
ограничения на их значения. Формально, данные правила являются множеством сигнатур операций rc : c boolean . Предполагается, что атрибуты бывают основных типов S D , отображаемых в основную область семантики D, сложных типов S D , отображаемых в многозначную область семантики D , а также типов классов C. Способом, аналогичным алгебраической спецификации, предоставим сигнатуру M ( S D S D C , , D D AttrC RuleC ) , где D , D являются множествами операций, определенных над основными и сложными типами. Здесь частичный порядок расширяет порядок классификаторов и обобщает отношения специализации между всеми типами данных. Сигнатура, сформированная подобным способом, описывает типы и символы операций, принадле-жащие к информационной модели M, а также содержит исходное множество синтаксических элементов, над которыми могут быть определены выражения Expr ({vars } sS D S D C ) с переменными, индексируемыми данными типами. Множество объектов со значениями атрибутов и установленными между ними ассоциациями определяет состояние модели M . В рамках нашего обсуждения, состояние M является множеством прикладных или визуальных объектов в зависимости от семантики модели предметной области M. Для краткости пропустим более глубокую формализацию и перейдем к рассмотрению синтаксиса и семантики языка информационного моделирования EXPRESS [5], чтобы проиллюстрировать введенную метамодель. Отметим лишь, что в настоящее время язык EXPRESS используется в качестве стандартного средства спецификации моделей данных для различных отраслей науки и промышленности.
2.2. Язык моделирования EXPRESS Итак, EXPRESS определяет основные типы {Real, Integer, Number, Boolean, Logical, String, Binary} S D , соответствующие простым типам данных с общепринятой семантикой. Сложные типы {Generic Aggregate, Bag, Set, List, Array, Enumeration, Select, Defined} S D соответствуют различным типам множеств, перечисляемым типам, выборкам и переопределенным типам, которые допускают определение производных и вложенных структур данных. Возможная дополнительная специализация типов не препятствует дальнейшему обсуждению. На Рис. 2 представлена общая классификация имеющихся в языке EXPRESS типов. Типы, отмеченные жирным курсивом, соответствуют его исходным типам. Стрелки показывают отношения наследования между ними. Виртуальные типы, отмеченные обычным шрифтом, используются только для того, чтобы единообразно классифицировать конструкции языка и представить типы, определяемые пользователем. 180
{+: Binary Binary Binary; blength: Binary Integer; []: Binary Integer 0|1, [:]: Binary Integer Integer Binary }
GENERIC
SIMPLE
CONSTRUCTED
ENUMERATION
LOGICAL
NUMBER
STRING
BOOLEAN
REAL
INTEGER
NAMED
SELECT
BINARY
AGGREGATE
GENERIC AGGREGATE
DEFINED
ENTITY
BAG OF GENERIC
SET OF GENERIC
LIST OF GENERIC
ARRAY OF GENERIC
BAG
SET
LIST
ARRAY
Рис. 2. Классификация исходных типов, имеющихся в языке EXPRESS Простыми типами данных являются Boolean, Logical, Number (включая конкретные подтипы Real и Integer), String и Binary. Синтаксис простых типов и их свойства описываются сигнатурой D ( S D , D ) , где S D — множество типов данных, а D — множество операций. Интерпретация простых типов является обычной, но каждое множество расширяется специальной величиной , обозначающей неопределенное значение. Тип s S D отображается в область семантики Ds функцией I : s Ds следующим образом: I (Boolean) = {true, false} {} , I (Logical) = {true, false, unknown} {} , I (Real) = R {} , I (Integer) = Z {} , I (String) = A* {} , где A — конечный алфавит, A * — множество всех последовательностей над алфавитом A , и I (Binary) = {0,1}* {} .
Над простыми типами определено множество операций. Существует несколько групп операторов: {+, -, *, /, **: Number Number Number; +, -, abs: Number Number } {div, mod: Integer Integer; odd: Integer Logical } {sin, cos, tan, asin, acos, atan, exp, log, log2, log10, sqrt: Number Real } {format: Number String String; value: String Number } {and, or, xor: Logical Logical Logical; not: Logical Logical } {+: String String String, like: String String Logical; length: String Integer; []: String Integer A, [:]: String Integer Integer String} 181
{=, <>, <=, >=, <, >: Number Number Logical, Logical Logical Logical, String String Logical, Binary Binary Logical}. Семантику данных операций легко истолковать. В частности, это арифметические операции над числовыми операндами типов Number, Real, Integer и стандартные математические функции; преобразование чисел в строковое представление и обратно; логические операции над логическими операндами типов Logical или Boolean; конкатенация, сопоставление с образцом, индексация, выделение подмножества над операндами типов String и Binary, а также операции сравнения, определенные для всех простых типов. Некоторые операции имеют тот же самый перегруженный символ в качестве имени и могут различаться только по типам своих аргументов. Созданные типы, которыми могут являться перечисление либо выборка, расширяют множество основных типов. Область определения перечисляемого типа Enumeration задается упорядоченным множеством значений, представленных уникальными именами I ( Enumeration(ai , i 1...n)) {ai A* , i 1...n} {} . На литералы перечисляемого типа ссылаются как на элементы перечисления. Порядок элементов перечисления предопределяется их относительными позициями. Данное упорядочение дает в результате операции сравнения, определенные между значениями, относящимися к одному и тому же перечисляемому типу: {=, <>, <=, >=, <, >: Enumeration Enumeration Logical }. Выбираемый тип данных Select определяет производный тип, представляемый списком других исходных типов. Экземпляр выбираемого типа данных является экземпляром одного из типов, заданных в списке выбора. Допускается, что экземпляр данных принадлежит одному из нескольких возможных типов. Другими словами, область определения значений для подобного типа является объединением областей определения типов в его списке: I ( Select ( s i , i 1...n)) I ( s1 ) ... I ( s n ) {} . Многозначные выражения в EXPRESS описываются агрегатными типами. Агрегации используются для представления упорядоченных и неупорядоченных коллекций данных каких-либо основных, предопределенных сложных и объектных типов. Они конструируются путем указания типа для их элементов. Эти коллекции могут иметь фиксированные или переменные размеры, хранить уникальные или дублированные представления элементов, а также могут допускать неопределенные элементы, что дает в результате разреженные структуры данных. Так, тип данных Array (массив) представляет собой структуру с фиксированным размером, где существенной является индексация элементов. Опционально массивы могут допускать, что не все их элементы имеют значение. Свойство уникальности массивов означает, что каждый элемент отличается от любого другого в одном и том же экземпляре массива. Тип данных List (список) представляет упорядоченную коллекцию идентичных элементов. 182
Список может хранить любое количество элементов, допуская или, опционально, не допуская их дублирование. Тип данных Bag (мультимножество) является коллекцией элементов, в которой порядок не является важным и допускается дублирование. И, наконец, Set (набор) является коллекцией элементов, в которой порядок не является важным и дублирование элементов не допускается. Количество элементов в списках, мультимножествах, наборах может изменяться в зависимости от определения их границ. Важно, что агрегатные типы могут быть вложенными, таким образом давая в результате многомерные структуры данных. { +, -, *: Aggregate( s1 ) Aggregate( s2 ) Aggregate(s) }
2.3. Определение семантики отображений При условии, что заданы информационные модели прикладной и визуальной предметных областей, схема отображения может быть определена как система R M S M T ( M S , M T , Map, , PrMap , Ps Map , Link Map , AttrMap , QrMap , Qs Map ) , где: M S , M T — модели исходной и целевой предметных областей. Предполагается, что они могут различаться, пересекаться или совпадать. Если модели совпадают, то схема соответствует некоторому RM S MT
преобразованию модели M S саму в себя;
Aggregate( s2 ) Logical } { in: s Aggregate(s) Logical, query: Aggregate(s) Logical Expression { =, <>, <=, >=: Aggregate( s1 )
Aggregate(s) } { []: Aggregate(s) Integer s }
Map — множество двунаправленных типов отображений m(l1 ,..., l k , l1,..., l l, l1,..., l n) Map с входными, смешанными и выходными связями l1 ,..., l k , l1,..., l l, l1,..., l n Link Map , принадлежащими соответствующим
типам исходной и/или целевой s1 ,..., s k , s1,..., sl, s1,..., s n S DS S DS C S S DT S DT CT .
{ sizeof, hiindex, loindex, hibound, lobound: Aggregate(s) Integer } { insert: List(s) s Integer List(s), remove: List(s) Integer List(s)}. Операторы над множествами +, -, * определяются для объединения, вычитания и пересечения коллекций совместимых типов s1 , s 2 . Операторы сравнения, включая операторы подмножества и надмножества <=, >=, предназначены для установления отношений равенства и общности между совместимыми коллекциями экземпляров. Оператор принадлежности in проверяет некоторое значение на наличие в агрегации. Выражение запроса query вычисляет логическое условие отдельно для каждого элемента агрегации и возвращает агрегацию, содержащую те элементы, для которых логическое выражение истинно. Оператор индексирования [] извлекает из агрегации отдельный элемент. Операции sizeof, hiindex, loindex, hibound, lobound возвращают, соответственно, количество элементов в агрегации, верхний и нижний индексы элементов массива, верхнюю и нижнюю границы списков, мультимножеств и наборов. Операции insert и remove определяются дополнительно, чтобы упростить манипулирование специфическими агрегациями — списками. Наконец, определенный (Defined) тип данных является пользовательским расширением стандартных типов, при этом он дает возможность определить дополнительные семантические ограничения, налагаемые на специфицируемые данные: I ( Defined ( s )) I ( s ) {} . Множества, выборки и определенные типы могут быть вложенными, поэтому в EXPRESS допустимо составление более сложных типов. В нетривиальных прикладных и визуальных моделях данных невозможно избежать подобных сложных структур.
183
отображение m представляется m f : m s1 ... s k s1 ... sl s1,..., sl, s1,..., s n
для
парой прямой
моделей Каждое сигнатур функции,
отображающей исходные объекты в целевые, и mb : m s1 ... sl s1 ... s n s1 ,..., s k , s1,..., sl для обратной функции. Связи играют роль формальных параметров как для функций отображений, так и для других операций, определяемых для концепта отображения. Каждое отображение определяет, какие комбинации типов параметров, включая основные, сложные и объектные типы, могут привести к генерации результатов или восстановлению исходных данных, а также как это может быть выполнено на основе предусловий PrMap , постусловий Ps Map и операций над атрибутами AttrMap . Здесь предполагается, что целевая сцена всегда может быть получена из всеобъемлющей исходной информации, а исходные данные могут реконструироваться при изменениях целевой сцены; — частичный порядок на Map, отражающий отношения обобщения/специализации между отображениями; PrMap ,
Ps Map
—
множества
предусловий
prm : m s1 ... s k s1 ... sl boolean и постусловий ps m : m s1 ... sl s1 ... s n boolean для выявления потенциальных случаев, когда прямое и обратное преобразования должны действительно выполняться. Они также могут применяться для контроля правильности и непротиворечивости результатов; AttrMap — множество операций над атрибутами a m : m s , a m : m s m
для функций доступа к их значениям. Каждый атрибут отображения типа 184
s Map представляет свойство ассоциации, задаваемое значением типа m Map . Таким образом, отображения могут связываться друг с другом;
QrMap ,
Qs Map
—
множества
качественных
правил
qrm : m s1 ... s k s1 ... s number , qs m : m s1 ... sl s1 ... s number для априорной и апостериорной оценки результатов, получаемых при выполнении отображений. Здесь полагается, что степень качества и пригодности результатов может быть выражена типом, для которого определены операции сравнения. Важно, что порядок типов исходной и целевой моделей индуцирует частичный порядок на отображениях. Отображения m(l1 ,..., l k , l1,..., l l, l1,..., l n) Map , ln) Map могут быть связаны соотношением m m , if m ( l1,..., lk , l1,..., ll, l1,...,
представление, однако в общем случае не требуется обязательного существования обратных отображений. В последующем обсуждении рассмотрим данный подход только на примерах прямых отображений, допуская, что подобным образом могут применяться и обратные преобразования. Рассмотрим основные принципы и механизмы, существенные для введенного понятия отображения. Они имеют значение для построения широкого класса приложений с использованием композиционного подхода к программированию. Обсудим данные принципы, следуя приведенному ниже примеру. SCHEMA ConstructiveSolidGeometry ENTITY Solid ABSTRACT SUPERTYPE OF (ONEOF(Sphere, Cube, Cylinder, Cone, Torus, Polyhedron, Box, Half_Space)); DERIVE is_bounded: BOOLEAN := ?; bounding_box: Box := ?; area_of: REAL := ?; volume_of: REAL := ?; boundary_representation: Polyhedron := ?; END_ENTITY;
k k , l l , n n , si s i для i 1,..., k , si si , для i 1,..., l , и si s i для i 1,..., n . Следствием частичного порядка на Map являются условия на идентификаторы данных, которые могут участвовать в отображениях. Если идентификаторы данных удовлетворяют отображению m и m m , то они удовлетворяют и отображению m. Это означает, что тот же самый набор данных или популяция объектов могут обрабатываться при вычислении родственных отображений. Естественный отбор приводит к применению того отображения, которое наиболее подходит к конкретному набору данных по сигнатуре функции отображения. С этой целью типы данных и связей отображений могут сравниваться методом, схожим с лексикографическим сравнением строк, с тем, чтобы произвести качественную оценку и принять окончательное решение, основанное на вычисляемой мере. Конечно, могут быть другие зависимые от приложения способы определения функций оценки качества для отображений.
Схема
отображения
RM S MT
допускает
содержательную
ENTITY Box SUBTYPE OF (Solid); Xmin: REAL; Xmax: REAL; Ymin: REAL; Ymax: REAL; Zmin: REAL; Zmax: REAL; DERIVE SELF\Solid.is_bounded: BOOLEAN := TRUE; SELF\Solid.bounding_box: Box := SELF; SELF\Solid.area_of: REAL := …; SELF\Solid.volume_of: REAL := …; … END_ENTITY;
реализацию
R M S M T : M S M T , преобразующую состояние модели M S в состояние
модели M T или, иначе говоря, преобразующую популяции объектов, относящихся к модели M S , в популяции объектов, принадлежащих модели M T . Если модель M S семантически означает некоторую прикладную модель, а M T — некоторую визуальную модель, то данная реализация будет соответствовать процессу визуализации. Более того, будучи схемой двунаправленного отображения, R M S M T может допускать реализацию
ENTITY Polyhedron SUBTYPE OF(Solid); faces: SET [4:?] OF Face; edges: SET [6:?] OF Edge; vertices: SET [4:?] OF Vertex; DERIVE euler_number: INTEGER := SIZEOF(vertices)+SIZEOF(faces)SIZEOF(edges);
R M S M T : M T M S , воспроизводящую исходные прикладные данные в
соответствии с изменяющейся визуальной сценой. Иногда приложения визуализации предусматривают интерактивные возможности, основанные на манипуляциях объектами визуальной сцены и их преобразованиях в исходное 185
186
… WHERE Euler_rule: (euler_number <= 2) AND (euler_number MOD 2 = 0); END_ENTITY; … END_SCHEMA;
MAP_SCHEMA SetTheoreticGeometry; SOURCE ConstructiveSolidGeometry; TARGET ConstructiveSolidGeometry; MAP CSGOperation ABSTRACT SUPERTYPE OF (ONEOF(CSGUnion, CSGIntersection, CSGSubtraction)); tolerance: REAL; IN operand1: Solid; operand2: OPTIONAL Solid; OUT result: Solid; DERIVE may_intersect: BOOLEAN := IntersectBoxes(operand1.bounding_box, operand2.bounding_box); … END_MAP; MAP CSGSubtraction SUPERTYPE OF (ONEOF (Box_Subtraction, Half_Space_Subtraction)) SUBTYPE OF(CSGOperation); FORWARD CallCSGSubtraction(SELF); PRE_CONDITION CallCSGSubtractionPrecondition(SELF); POST_CONDITION CallCSGSubtractionPostcondition(SELF); PRE_ESTIMATE CallCSGSubtractionPreestimate(SELF); POST_ESTIMATE CallCSGSubtractionPostestimate(SELF); END_MAP;
POST_CONDITION … PRE_ESTIMATE … POST_ESTIMATE … END_MAP; MAP Half_Space_Subtraction SUBTYPE OF(CSGSubtraction); IN SELF\CSGOperation.operand2: OPTIONAL Half_Space; FORWARD … PRE_CONDITION … POST_CONDITION … PRE_ESTIMATE … POST_ESTIMATE … END_MAP; … END_MAP_SCHEMA;
2.3.1. Принцип A. Наследование отображений Будучи классифицированными, сами отображения могут быть представлены типами объектов в рамках рассмотренной выше объектно-ориентированной метамодели. Частичный порядок на Map отражает иерархию типов отображений. Определим наследование отображений как механизм, регулирующий права преемственности для атрибутов, связей, пред-, постусловий и оценок качества в базовых и наследуемых отображениях, аналогично операции наследования, обычно применяемой в рамках объектно-ориентированного подхода. Атрибуты и связи интерпретируются как данные, инкапсулируемые отображениями, условия и оценки качества — как их методы. CSGOperations Solid[*Solid]->Solid
CSGUnion Solid[Solid]->Solid
CSGIntersection Solid[Solid]->Solid
CSGSubtraction Solid[Solid]->Solid CSGBoxSubtraction Box[Box]->Solid
MAP Box_Subtraction SUBTYPE OF(CSGSubtraction); IN SELF\CSGOperation.operand1: Box; SELF\CSGOperation.operand2: OPTIONAL Box; FORWARD … PRE_CONDITION …
Рис. 3. Пример иерархии отображений для выполнения операций CSG
187
В примере на языке EXPRESS объявление схемы ConstructiveSolidGeometry вводит примитивы типа Solid, такие как Sphere, Cube, Cylinder, Cone, Torus, Polyhedron, Box, Half_Space, используя конструкцию ENTITY. Полиморфные методы is_bounded, bounding_box, area_of, volume_of, 188
boundary_representation объявляются в абстрактном супертипе Solid как вычисляемые (DERIVE) атрибуты и наследуются конкретными типами. Правила WHERE определяют условия, при которых экземпляры типов ENTITY являются семантически верными с точки зрения непротиворечивости значений их явных и вычисляемых атрибутов. Например, условие Euler_rule налагает известное ограничение Эйлера для непротиворечивого представления полиэдральных тел типа Polyhedron.
2.3.2. Принцип B. Структурная специализация и поведенческий полиморфизм В схеме отображений SetTheoreticGeometry, использующей модель ConstructiveSolidGeometry посредством объявлений SOURCE и TARGET, определяются отображения типа CSGOperation, такие как CSGUnion, CSGIntersection, CSGSubtraction, реализующие теоретико-множественные операции над произвольными твердотельными геометрическими примитивами и их сборками. Фрагмент иерархии отображений, иллюстрирующий выполнение данных операций, представлен на рисунке 3. Кроме атрибута tolerance, соответствующего численной точности выполняемой операции, абстрактное отображение CSGOperation определяет входные связи operand1, operand2 и выходную связь result, соответственно, отмечаемые метками разделов IN и OUT. Семантически входные связи имеют отношение к операндам операции конструктивной твердотельной геометрии (CSG), а выходная связь — к ее результату. Опциональный статус, назначенный связи operand2, показывает, что второй операнд не является обязательным и может быть пропущен без потери целостности данных отображения. Допуская более содержательную реализацию на уровне конкретных операций, могут быть также определены специализированные (наследуемые) отображения. Например, отображение Box_Substraction специализирует отображение CSGSubstraction в результате наследования его свойств. Одновременно оно переопределяет входные связи путем объявления их типа как Box вместо Solid и предусматривает более эффективные реализации методов выполнения отображения, вычисления пред-, постусловий, оценок качества, выделяемых в теле отображения ключевыми словами FORWARD, PRE_CONDITION, POST_CONDITION, PRE_ESTIMATE, POST_ESTIMATE. Таким образом, в результате наследования отображений могут уточняться типы их атрибутов и связей, а также полиморфно переопределяться их поведенческие свойства.
2.3.3. Принцип C. Агрегатные отображения Иногда в приложениях необходимо иметь возможность последовательно применить совпадающие или очень близкие по сигнатурам функций преобразования и объединить конечные результаты в соответствии с некоторой процедурой. Для этого родственные отображения могут быть сгруппированы с использованием агрегатных конструкций BAG, SET, ARRAY 189
или LIST, синтаксически подобных языковым конструкциям EXPRESS. Следующий пример иллюстрирует возможности определения агрегатных отображений. Заметим, что данный пример выглядит похожим на спецификацию EXPRESS, за исключением того, что CSGOperation и CSGOperationList являются типами отображений, а не типами данных. TYPE CSGOperationList = LIST [1:?] OF CSGOperation; END_TYPE; LOCAL Union_Op: CSGUnion; Intersect_Op: CSGIntersection; Subtract_Op: CSGSubtraction; Complex_Op: CSGOperationList := [Union_Op, Intersect_Op, Subtract_Op]; solid1, solid2: Polyhedron; resulting_solids: LIST[1:?] OF Polyhedron; END_LOCAL; Complex_Op.operand1 := solid1; Complex_Op.operand2 := solid2; Complex_Op.result := resulting_solids; Complex_Op.FORWARD(); Solid Solid CSGOperationList LIST MAP
CSG Union
CSG Intersection
CSG Subtraction
…
Solid LIST
Рис. 4. Пример агрегатного отображения для множественного выполнения операций CSG Семантика объявления агрегатного отображения соответствует определению производного отображения, основанного на назначенном типе. Каждый экземпляр агрегатного отображения представляет собой контейнер экземпляров основного отображения, связи которых непосредственно соединяются со связями агрегатного отображения. Это означает, что все экземпляры отображений, включенные в агрегатное, совместно используют его общие связи. Выполнение агрегатного отображения состоит в последо-вательном выполнении агрегируемых экземпляров основного отображения в порядке, предопределенном заданным агрегатным типом языка EXPRESS и его 190
допустимым интервалом размера. Агрегатное отображение может получать доступ к данным через входные связи, обновлять их через смешанные связи и накапливать выходные результаты путем последовательного выполнения отдельных экземпляров агрегируемых отображений. Типы входных и смешанных связей агрегатного отображения совпадают с соответствующими типами основного отображения. Типы выходных связей являются заданными EXPRESS агрегациями выходных связей его основного отображения. Таким образом, агрегатное отображение совместно использует общие связи с вложенными отображениями и объединяет их частные поведенческие свойства. В вышеприведенном примере экземпляр Complex_Op агрегатного отображения CSGOperationList объединяет экземпляры Union_Op, Intersect_Op, Subtract_Op конкретных отображений CSGUnion, CSGIntersection, CSGSub-traction.. Структура данного агрегатного отображения показана на Рис. 4. В результате выполнения экземпляр агрегатного отображения Complex_Op принимает на входе твердотельные геометрические операнды solid1, solid2, применяет теоретико-множественные операции над операндами и генерирует выходные результаты как агрегацию полиэдров resulting_solids. Существенно, что созданное агрегатное отображение может впоследствии применяться к другим наборам данных и их потокам.
2.3.4. Принцип D. Выборочные отображения Выборочное отображение — это конструкция, схожая с агрегатным отображением, за исключением того, что для получения выходных результатов должно применяться только одно из базовых отображений. Критерии выбора могут быть различными в зависимости от целей приложения. Поэтому, кроме конструкции SELECT, семантически означающей, что любой из экземпляров включенных базовых отображений может быть применен для получения результатов, вводится конструкция PRE_SELECT, выполняющая выбор по априорным оценкам и конструкция POST_SELECT, выполняющая все базовые отображения и выбирающая наилучший результат среди полученных с использованием апостериорных оценок. Допускается, что для критериев выбора могут быть использованы и другие возможности, и поддерживаемый набор селективных конструкций может быть значительно расширен. Для представленных конструкций предлагаются типовые реализации оценок качества, которые могут быть приняты по умолчанию в случаях, когда программист не предоставляет собственную реализацию. Реализация по умолчанию для априорных оценок состоит в определении максимального различия уровней специализации для формальных и фактических входных параметров отображения. При использовании такого критерия выбирается базовое отображение, наиболее близкое по сигнатуре функции фактическим параметрам. Это достаточно общий и конструктивный метод, поскольку он позволяет выбрать то отображение, которое является 191
наиболее подходящим и, следовательно, эффективным для конкретной комбинации входных параметров. Для апостериорных оценок могут быть использованы другие методы, которые определяют степень специализации выходных результатов отображения и их соответствие целевой схеме. Базовое отображение выбирается как наилучшее, если все сгенерированные выходные результаты принадлежат целевой схеме и занимают самые низкие позиции в иерархии типов, соответствующие наиболее специализированным основным, сложным и объектным типам. Здесь пропущены подробности того, как можно алгебраически выразить итоговые оценки качества и как их можно вычислить, используя словарь метаинформации. В следующем примере предполагается, что оценочные функции для отображений вычитания CSGSubtraction, Half_Space_Subtraction, Box_Subtraction выбраны по умолчанию. Тогда определенный тип отображения Selecti-veSubtraction содержит всю функциональность, связанную с совместным управлением собранными в нем экземплярами базовых отображений, их выбо-ром в соответствии с контекстом приложения и последующим выполнением. Заметим, что реализации функций для базовых отображений могут варьиро-ваться по уровню численной точности, эффективности, надежности, принимая во внимание, что алгоритмические реализации операций CSG над произволь-ными полиэдрами, политопами и каноническими твердыми телами сущес-твенно различаются. Тем не менее, будучи примененным, отображение Selec-tiveSubtraction выбирает и выполняет базовое отображение, наиболее подхо-дящее для конкретных связанных с ним CSG операндов, как показано на Рис. 5. TYPE SelectiveSubtraction = PRE_SELECT (CSGSubtraction, Half_Space_Subtraction, Box_Subtraction); END_TYPE; LOCAL Op1: CSGSubtraction; Op2: Half_Space_Subtraction; Op3: BoxSubtraction; Complex_Op: SelectiveSubtraction; solid1, solid2, solid3: Solid; END_LOCAL; Insert(Complex_Op, Op1, 1); Insert(Complex_Op, Op2, 2); Insert(Complex_Op, Op3, 3);
192
В самом деле, CSG операция operand1 operand2 может быть представлена как operand1\(operand1\operand2), и, следовательно, отображение CSGIntersection может быть реализовано как зависимое от CSGSubtraction. Для этого определение CSGIntersection включает объявление связи auxiliary_map с отображением CSGSubtraction и использует ее при вычислении отображения. В примере, представленном на Рис. 6, для того, чтобы создать конкретный экземпляр отображения CSGIntersection, необходимо заблаговременно сконструировать экземпляр отображения CSGSubtraction и присвоить его этой связи. Существенно, что различные реализации зависимого отображения CSGIntersection могут быть получены в результате присвоения различных версий операции CSGSubtraction. Это можно легко сделать, не переписывая спецификации для данных отображений.
Complex_Op.operand1 := solid1; Complex_Op.operand2 := solid2; Complex_Op.result := solid3; Complex_Op.FORWARD(); Solid
Solid SelectiveSubtraction SELECT MAP
CSG Subtraction
HalfSpace Subtraction
Box Subtraction
…
Solid
Рис. 5. Пример выборочного отображения для выполнения операций CSG в зависимости от специализации типов операндов Для краткости, как и при обсуждении предыдущего принципа, не станем акцентировать внимание на возможных проблемах несоответствия связей базовых отображений, собранных внутри производных агрегатных и выборочных отображений. Единственное замечание состоит в следующем. Производные отображения могут использовать только те связи, которые явно встречаются в объявлении базовых отображений или их предков. Связи, определенные на более низких уровнях иерархии отображений, рассматриваются как необязательные и игнорируются. Связи, совместно используемые родственными базовыми отображениями, включаются в общий набор производных отображений. Таким образом, разрешается проблема несоответствия. Тем не менее, для наиболее общего случая композиции отображений подход предусматривает специальную конструкцию.
2.3.5. Принцип E. Зависимые отображения Зависимое отображение — это тип обычных отображений, определяемых с использованием конструкции MAP. Ключевое отличие заключается в объявлении некоторых из его связей как экземпляров типа MAP. Причина поддерживать данный вид отображений состоит в необходимости параметризовывать реализации производных отображений другими базовыми отображениями. Например, мы могли бы определить операцию CSGIntersection как отдельно реализованное отображение, наследуемое от абстрактного отображения CSGOperation с новой функциональностью для условий, оценок и функций отображения. Существует и другая возможность реализовать операцию CSGIntersection, используя уже определенное отображение CSGSubtraction. 193
MAP CSGIntersection SUBTYPE OF(CSGOperation); INOUT auxiliary_map: CSGSubtraction; FORWARD … END_MAP; Solid Solid
Box Analyzer MAP
CSGOperation CSG Subtraction
Parametrized Operation MAP
Solid
Рис. 6. Пример зависимого отображения для параметризации операций CSG
2.3.6. Принцип F. Составные отображения Структурная компоновка более сложных отображений из уже определенных — один из основных принципов предлагаемого подхода. В соответствии с декларативными возможностями, основанными на расширениях языка EXPRESS, данный принцип может быть реализован посредством конструкции COMPOSITE_MAP. Подобно обычным отображениям, определяемым декларацией 194
MAP, конструкция COMPOSITE_MAP допускает явное объявление собственных атрибутов и связей. Но принципиальное различие заключается в способах того, как реализуются функции условий, оценок и отображений. Для обычных отображений реализации таких функций обеспечивает программист. Для составного отображения подобные функциональные реализации не используются, однако программист специфицирует его структуру как упорядоченное множество экземпляров взаимосвязанных друг с другом отображений. Будучи структурированными, составные отображения могут применяться как для прямых, так и для обратных преобразований данных. В следующем примере составное отображение CSGAssemblyAnalysis предназначено для визуального представления пересекающихся твердых тел в виде сборки отдельных частей (см. рисунок 7). Данное отображение включает объявления внутреннего атрибута tolerance, определяющего точность проводимых вычислений, связей operand1, operand2, соответствующих входным операндам, и связей result1, result2, result3, через которые operand1\operand2, воспроизводятся результаты CSG операций operand1 operand2, и operand2\operand1, соответственно. COMPOSITE_MAP CSGAssemblyAnalysis; tolerance: REAL; IN operand1: Solid; operand2: OPTIONAL Solid; OUT result1: Solid; result2 : OPTIONAL Solid; result3 : OPTIONAL Solid; STRUCTURE map1: SelectiveSubtraction; Op1: CSGSubtraction(tolerance); Op2: Half_Space_Subtraction(tolerance); Op3: BoxSubtraction(tolerance); Insert(map1, Op1, 1); Insert(map1, Op2, 2); Insert(map1, Op3, 3); map2: SelectiveSubtraction; … map3: SelectiveSubtraction; … map4: Transform3D; … map5: Transform3D; … FLOW operand1 TO map1.operand1; 195
operand2 operand1 operand2 operand1
TO TO TO TO
map1.operand2; map2.operand2; map2.operand1; map3.operand1;
map1.result TO map3.operand2; map1.result TO map4.operand; map2.result TO map5.operand; map3.result TO result2; map4.result TO result1; map5.result TO result3; END_MAP; Solid1
Solid2 CSGAssemblyAnalysis MAP
CSG Subtraction
CSG Intersection
Transform 3D
ResultSolid1
CSG Subtraction
Transform 3D
ResultSolid2
ResultSolid3
Рис. 7. Пример составного отображения для выполнения сложных операций CSG Для этого отображение компонуется из отдельных базовых отображений, экземпляры которых конструируются в разделе, отмеченном ключевым словом STRUCTURE. Чтобы исключить неопределенность результатов, вызванную возможными циклическими зависимостями между базовыми отображениями, их экземпляры должны перечисляться в порядке, соответствующем фактической последовательности их выполнения. Экземпляры отображений связываются друг с другом в разделе FLOW посредством оператора TO, который присваивает выходные результаты одного преобразования входам другого и, таким образом, играет роль ветви потока данных, проходящих через общую структуру составного отображения. Существуют простые правила, согласно которым базовые отображения могут быть однозначно взаимосвязаны и скомпонованы внутри производных отображений. Эти правила — следующие: 196
связь, являющаяся источником данных (входные и смешанные связи составного отображения, а также смешанные и выходные связи базовых отображений), может быть присвоена связям, являющимся получателями данных (смешанные и выходные связи составного отображения, а также входные и смешанные связи базовых отображений); тип связи-получателя должен быть родственным (обобщенным или специализированным) типу связи-источника. Аналогично языку EXPRESS, специализация типов может охватывать соответствующие отношения между простыми типами данных, определяемыми пользователем объектными и созданными типами, а также накладывать дополнительные правила на соединение связей; одна и та же связь-источник может быть присвоена нескольким связям-получателям, но каждой связи-получателю может быть присвоена только одна связь-источник.
2.3.7. Принцип G. Композиционный сценарий Наконец, представим сценарий, главное отображение, с которого должно начинаться выполнение всей схемы. Будем считать, что схема отображения может содержать только один сценарий. Сценарий включает встроенные входные и выходные связи INPUT, OUTPUT предопределенного типа LIST[0:?] OF GENERIC, объявления атрибутов, используемых в сценарии в качестве локальных переменных, раздел STRUCTURE, содержащий упорядоченный список экземпляров отображений и раздел FLOW для спецификации потока данных через составляющие отображения. SCENARIO(INPUT,OUTPUT: LIST[0:?] OF GENERIC) STRUCTURE map1 : Map1(constructor); … mapN : MapN(constructor); FLOW INPUT TO map1.operand1; … mapN.result TO OUTPUT; END_SCENARIO; Входная связь INPUT используется для назначения сценарию набора входных данных, специфицируемых на языке моделирования EXPRESS и поставляемых в некотором мета-формате, а выходная связь OUTPUT используется для того, чтобы сохранить сгенерированные результаты в этом же представлении. Детали организации мета-формата относятся к вопросам реализации, обсуждаемым в следующем разделе.
197
Как и составные отображения, сценарий выполняется путем последовательного вызова функций отдельных отображений в порядке их перечисления и передачи входных, промежуточных и выходных данных от источников к получателям в соответствии с назначенными потоками данных. Тот же самый сценарий может использоваться как для прямого, так и для обратного отображения данных. Единственное требование состоит в том, чтобы все определенные в нем простые отображения были двунаправленными, то есть, для них должны быть заданы функции FORWARD и BACKWARD. В обратных преобразованиях роли входных и выходных связей, пред- и постусловий, пред- и постоценок, соответственно, меняются местами. Таким образом, после того, как определен композиционный сценарий, нет необходимости указывать какие-либо еще процедуры, и программа отображения может быть немедленно выполнена.
3. Реализация подхода Предложенный и проиллюстрированный выше подход допускает конструктивную реализацию в контексте семейства стандартов STEP (ISO 10303 — стандарт для представления данных об изделии и обмена этими данными) [5]. Язык моделирования данных EXPRESS является одной из частей (а именно, частью 11), определяемой и регулируемой в рамках STEP, который был разработан с целью описания моделей продуктов для таких отраслей промышленности как машиностроение, автомобилестроение, аэрокосмическая индустрия, судостроение, архитектура, нефте-газодобыча, электротехника и электроника. Согласно определениям STEP, EXPRESS — это язык абстрактных схем, который обеспечивает спецификацию объектов, принадлежащих некоторой предметной области, элементов информации, имеющих отношение к этим объектам, и накладываемых на них ограничений. Не являясь исполняемым языком, EXPRESS не предусматривает спецификацию организации и представления элементов информации. Эти вопросы регулируются другими частями STEP, определяющими мета-форматы обменных файлов (часть 21 — формат кодирования открытым текстом, часть 28 — XML формат), абстрактный API для работы со специфицированными на EXPRESS данными, называемый стандартным интерфейсом доступа к данным (SDAI, часть 22), а также ряд представлений SDAI на популярных языках программирования, таких как C++, C, Java (части 23, 24, 27). Следовательно, разумно ожидать, что данный подход в сочетании с языком EXPRESS хорошо бы подошел для специфицирования визуализации сложных многопрофильных моделей продуктов в вышеупомянутых ключевых отраслях промышленности. Нам видится несколько возможностей реализации композиционного подхода. Прежде всего, он может быть реализован с использованием представленных расширений языка EXPRESS, образующих новый язык спецификаций, называемый в дальнейшем EXPRESS-F. Являясь расширением EXPRESS, язык 198
EXPRESS-F позволяет специфицировать как сами данные, так и их потоки в контексте выполняемых отображений. Сочетая парадигмы объектноориентированного программирования и потоков данных, язык предусматривает различные возможности для спецификации простых отображений, а также для составления из них более сложных сценариев. Ранее парадигма потоков данных успешно применялась при разработке широкого класса приложений визуализации [6, 7], что дало основания использовать ее и в настоящей работе. Спецификации отображений, написанные на языке EXPRESS-F, могут интерпретироваться непосредственно, а также могут транслироваться на популярные исполняемые языки. В этом смысле язык EXPRESS-F, как и язык EXPRESS, нейтрален по отношению к возможным платформам реализации. Для построения программ на основе обсуждаемого подхода предложена и разработана инструментальная среда общего назначения. Данная среда — это система классов для представления произвольных модельно-ориентированных данных и отображений, для их интроспекции во время запуска с использованием словарей метаданных, а также для выполнения определяемых отображений и композиционных сценариев. Таким образом, общая функциональность среды включает: Управление метаданными, относящимися к исходной и целевой моделям данных и к схеме их отображения друг в друга; Экспорт/импорт модельно-ориентированных данных; Асинхронный доступ к совместно используемым данным через программные интерфейсы; Составление сценариев во время работы, проверку их непротиворечивости и выполнение; Решение задач геометрического моделирования с использованием специализированной библиотеки отображений. Инструментальная среда совместима со SDAI, регламентированным стандартом STEP, и предоставляет все декларируемые в нем возможности для экспорта/импорта данных, специфицируемых на языке EXPRESS. Так, среда поддерживает все предусматриваемые SDAI классы, такие как сессия, транзакция, репозиторий, экземпляр схемы, модель, набор объектов, экземпляр приложения, а также все классы, необходимые для воспроизведения схемозависимых типов данных, основанных на иерархии исходных типов EXPRESS, показанной на Рис. 2. Последние определяются для версий раннего и смешанного связывания в рамках SDAI. В дополнение к типам данных, среда управляет представлениями отображений, специфицированных на языке EXPRESS-F. С этой целью она поддерживает иерархию классов отображений, изображенную на Рис. 8 и предусматриваемую языком EXPRESS-F.
199
GENERIC MAP
SIMPLE MAP MAP
SELECTIVE MAP
AGGREGATIVE MAP
SELECT_MAP
COMPOSED MAP
SCENARIO
COMPOSED MAP
SCENARIO
BAG OF MAP
SET OF MAP
LIST OF MAP
ARRAY OF MAP
BAG_MAP
SET_MAP
LIST_MAP
ARRAY_MAP
Рис. 8. Иерархия классов отображений инструментальной среды Среда также использует и расширяет словари метаданных SDAI для интроспекции данных и отображений, а также предоставляет средства управления метаданными, включая загрузку схем, специфицированных на языках EXPRESS и EXPRESS-F, навигацию по словарям и конструирование объектов с использованием фабрик. Словари метаданных являются ключевыми компонентами ядра инструментальной среды, которые позволяют реализовать широкий набор вышеперечисленных функций. Существенно, что составление сценариев, их проверка на непротиворечивость и выполнение могут совершаться в режиме реального времени, предоставляя конечным пользователям возможности как использовать встроенные сценарии, так и определять новые непосредственно во время сеанса работы с приложением. Чтобы упростить разработку программных компонентов, типичных для большинства приложений визуализации, инструментальная среда предлагает готовые к использованию библиотеки отображений для решения задач геометрического моделирования. В частности, данные библиотеки реализуют преобразования над каноническими геометрическими примитивами и теоретико-множественные операции над произвольными полиэдрами.
200
разработанный альянсом International Alliance for Interoperability (IAI) [8], а в качестве целевой модели — язык моделирования виртуальной реальности (VRML), спроектированный и реализованный консорциумом Web3D [9, 10].
STEP-compliant Visualization Framework Standard Data Access Interface
SDAI Extensions
SDAI Population
4.1. Информационный стандарт IFC
Schema Instance
Model
Entity Extent
Scenario
Composed Map
…
…
SDAI Parameter Data Application Instance
Entity Instance
SDAI Instance
…
Map Instance
AggrMap Instance
Rule
…
Map
Link
SelectMap Instance …
SDAI Dictionary Schema
Entity
Type
Condition
…
SDAI Session Session
Transaction
Repository
…
Application
…
Рис. 9. Компонентная организация инструментальной среды
4. Приложение Предложенный подход и разработанная среда использовались и тестировались при создании программного приложения, предназначенного для виртуального строительства. Приложение ориентируется на актуальные потребности строительной индустрии в средствах макетирования архитектурностроительных проектов и моделирования процессов строительства с использованием технологий виртуальной реальности. Данные средства должны способствовать пониманию особенностей проекта между различными заинтересованными сторонами, включая заказчиков, архитекторов, инженеров, экономистов, менеджеров, принимающих участие в совместном проекте, с целью исключить возможные ошибки проекта еще на подготовительных этапах, устранить препятствия на пути его реализации и, в конечном итоге, улучшить сроки и качество его реализации. Следуя данному подходу, при создании приложения виртуального строительства необходимо определить исходную и целевую информационные модели, надлежащим образом описывающие прикладную и визуальную предметные области. Использование в качестве моделей существующих промышленных стандартов позволило бы при этом обеспечить интероперабельность приложения и придать ему практическую ценность. В силу этих причин построенное приложение использует в качестве исходной модели международный информационный стандарт Industry Foundation Classes (IFC), 201
Главная миссия IAI состоит в достижении интероперабельности между строительными компаниями во всем мире посредством предоставления универсальной основы для согласованного совместного использования информации. С момента основания IAI в 1995 году членство в нем возросло до более 600 компаний из более чем 20 стран. IAI продвигает спецификации IFC, которые позволяют компаниям по разработке программного обеспечения создавать новое поколение интероперабельных приложений для архитектурностроительной индустрии. Сейчас IFC получил широкое распространение внутри этого сообщества. IAI использует методологию STEP и язык EXPRESS для определения и реализации всеобъемлющей многопрофильной информационной модели, включающей в себя множество аспектов и дисциплин, образующих архитектурно-строительную индустрию. В ходе разработки и согласования спецификаций под управлением IAI были подготовлены их отдельные версии: IFC 1.5.1, IFC 2.0, IFC 2x, IFC 2x2. Начиная с первой версии, спецификации IFC претерпевали существенные изме-нения, заключающиеся в совершенствовании структуры всей модели и в выделении таких предметных областей, как архитектура, электроаппаратура, отопление, вентилирование и кондиционирование воздуха, управление строительством, управление оборудованием. Высокая степень интеграции и сложность модели IFC при этом значительно возрастали. В таблице 1 приведена некоторая статистика, показывающая динамику увеличения числа используемых типов данных и наложенных на них ограничений для модели IFC. По-видимому, подобная динамика продолжится и в ожидаемой версии IFC 3.0. Версия IFC Созданные типы Определенные типы Типы объектов Ограничения Общее количество типов и ограничений
IFC 1.5.1 59 36 186 122 403
IFC 2.0 103 54 290 168 615
IFC 2x 139 89 370 207 805
IFC 2x2 202 110 623 293 1228
Таблица 1. Статистика использования исходных типов и ограничений в семействе стандартов IFC
202
4.2. Информационный стандарт VRML
o
В течение последнего времени язык моделирования виртуальной реальности (VRML) получил распространение в ряде отраслей науки, образования и промышленности, а также признан Internet сообществом в качестве стандартного языка для описания интерактивных трехмерных миров внутри всемирной паутины. Текущие версии стандарта (VRML97 и X3D) предусматривают расширенный репертуар объектов для трехмерного геометрического моделирования и мультимедиа, развитые поведенческие механизмы, улучшенные форматы кодирования и программные интерфейсы приложения. Являясь расширением VRML97, версия X3D добавляет известные возможности, такие как новые типы сенсоров, геопространственные объекты, гуманоиды, NURBS-формы, поддержку формата XML, интерфейс авторизации сцен и профиль для совместимости с MPEG4. Поскольку как VRML97, так и X3D модели определяются неформальным методом, для данных стандартов были разработаны EXPRESS схемы с тем, чтобы согласовать исходную и целевую модели, а также унифицировано управлять ими в рамках инструментальной среды. Фрагмент иерархии объектных типов в рамках схемы, разработанной на языке EXPRESS для информационной модели VRML97, представлен на Рис. 10. VRML97Node o ChildNode BindableNode BackgroundNode o Background Fog NavigationInfo Viewpoint GroupingNode Anchor Billboard Collision Group LOD Switch Transform LightNode DirectionalLight PointLight SpotLight 203
o
GeometryNode Box Cone Cylinder ElevationGrid Extrusion IndexedLineSet IndexedFaceSet PointSet Sphere Text SensorNode EnvironmentalSensorNode ProximitySensor VisibilitySensor PointingDeviceSensorNode TouchSensorNode o TouchSensor DragSensorNode o CylinderSensor o PlaneSensor o SphereSensor KeyDeviceSensorNode
Рис. 10. Фрагмент иерархии объектных типов модели VRML97 Подробные спецификации разработанных на языке EXPRESS схем для информационных моделей VRML97 и X3D могут быть найдены на странице http://www.ispras.ru/~step.
4.3. Основанный на отображениях сценарий для виртуального строительства Очевидно, что визуализация такой многогранной информации, как IFC данные, в VRML-совместимой среде виртуальной реальности является нетривиальной задачей и требует для реализации применения специального программного подхода. Принимая во внимание сложность моделей IFC и VRML, а также необходимость применения разнообразных методов и сценариев визуализации, использование предлагаемого подхода представляется достаточно перспективным. Дополнительная мотивация использования данного подхода заключается в том, что довольно часто сценарий должен формироваться пользователем непосредственно во время работы, чтобы визуально воспроизвести те аспекты, которые важны для решаемой задачи на текущей 204
o o o o o o
стадии анализа данных. Разработанная инструментальная среда предоставляет для этого необходимые средства, что является ее серьезным преимуществом. Для применения предлагаемого подхода и инструментальной среды следует разработать сценарии, значимые для решения проблем виртуального строительства. Рассмотрим некоторые их примеры, типичные для приложений визуализации.
IfcRoot o IfcObject IfcProduct IfcElement o IfcBuildingElement IfcWall IfcWallStandardCase IfcColumn IfcBeam IfcSlab IfcWindow IfcDoor IfcStair IfcStairFlight IfcRamp IfcRampFlight IfcRoof IfcBuildingElementProxy
Эта процедура может быть реализована путем использования выборочного отображения IfcMaterialMap, которое основывается на предопределенном отображении AbstractMaterialMap и его производных StandardMaterialMap, CADMaterialMap. MAP AbstractMaterialMap ABSTRACT SUPERTYPE OF (ONEOF (StandardMaterialMap, CADMaterialMap … )); IN element: IfcElement; OUT material: Material; END_MAP; MAP StandardMaterialMap SUBTYPE OF AbstractMaterialMap; ascribed_element: STRING; PRE_ESTIMATE: return LEVEL_DIFF(ascribed_element, TYPEOF(element)); END_MAP;
(Material1) (Material2) (Material3) (Material4)
(Material5)
205
(Material6)
Рис. 11. Фрагмент иерархии объектных типов модели IFC и назначенные материалы
4.3.1. Задача A (Назначение визуальных свойств) Чтобы отобразить архитектурно-строительный проект наиболее эффектным и исчерпывающим способом, пользователи часто используют физически содержательные метафоры и назначают различным типам архитектурных, отделочных, электрических, транспортных и других элементов материалы, визуальные свойства которых соответствуют их реальным физическим свойствам. Фрагмент иерархии типов элементов, встречающихся в моделях IFC, представлен на Рис. 11. Естественно, поскольку коллекция таких элементов может насчитывать сотни типов, пользователи не всегда способны различить назначенные материалы и адекватно идентифицировать элементы. Возможное решение состоит в назначении материалов широким категориям элементов в соответствии с предпочтениями пользователей. Но в этом случае необходимо разработать сценарий, согласно которому следует выбирать тот материал, который в наилучшей степени соответствует конкретному типу элемента.
IfcOpeningElement IfcFurnishingElement IfcElectricalElement IfcTransportElement IfcEquipmentElement IfcDistributionElement
TYPE UserMaterialMap = PRE_SELECT (StandardMaterialMap); END_TYPE; TYPE IfcMaterialMap = PRE_SELECT (CADMaterialMap, UserMaterialMap); END_TYPE; Априорная оценка для отображения StandardMaterialMap связана с вычислением разницы в уровнях специализации типов фактических элементов, поступающих в экземпляр отображения через входную связь element, и типов элементов ascribed_element, которым назначены материалы. Напомним, что отображение UserMaterialMap функционирует как селектор экземпляров StandardMaterialMap по критерию, реализуемому функциями оценок. Это означает, что в соответствии с приведенным на Рис. 11 назначением материалов, для каждого конкретного элемента отображение выберет визуальное свойство, наиболее подходящее по его типу. Например, для стандартных стен будет выбран Material4, для нестандартных — Material3, для окон — Material5, для других строительных элементов
206
(колонн, балок, перекрытий) — Material2, для электрических элементов — Material6 и Material1 — для всех остальных категорий элементов. Clipping Planes Half Space
4.3.2. Задача B (Обработка альтернативных геометрических моделей)
IFC Elements
IFC CSG to Polyhedron SELECT MAP
IFC CSG to Polyhedron SELECT MAP
Polyhedron
Geometry Form
IFC Swept Solid MAP
IFC Boolean Clipping MAP
IFC Transform Represent MAP
IFC Time Series MAP
CSG Subtraction MAP
IFC Material SELECT MAP
Time
образом, вложенные выборочные отображения допускают гибкую реализацию более сложных и практически значимых сценариев визуализации.
Material
IFC Material SELECT MAP CAD Material MAP
User Material SELECT MAP
…
IFC Bounding Box MAP
…
User Material SELECT MAP Standard Standard Standard Material Material Material MAP MAP MAP (IfcWall) (IfcDoor) (IfcSlab)
…
VRML MAP
VRML Scene
Рис. 12. Сценарий виртуального строительства с использованием IFC данных Назначение визуальных свойств может показаться тривиальной проблемой, которая могла бы решаться путем применения полиморфных методов в иерархии IFC классов. Но это не совсем так по следующим причинам. Прежде всего, невозможно предвидеть все вероятные приложения и случаи использования, в которых могут участвовать IFC данные. Поэтому иерархия IFC типов должна реализовываться в виде библиотеки, ответственной за представление данных, но не за их обработку. Вторая причина заключается том, что пользователю необходимо назначать визуальные свойства динамически во время сеанса работы приложения, и, следовательно, они не могут быть жестко встроены в реализацию классов. Третья причина состоит в многообразии критериев выбора, которые могут не совпадать с анализом типов в рамках имеющейся иерархии наследования и должны быть реализованы особым способом. Например, в сценарии, представленном на Рис. 12, селектор материала UserMaterialMap участвует в другой, внешней, процедуре выбора, основанной на отображении MaterialMap. Оно комбинирует техники выбора с использо-ванием отображения CADMaterialMap, которое назначает материалы тем элементам, которым уже были приписаны некоторые визуальные свойства, например, в ходе работы CAD приложения. Таким 207
Следующая задача, которую можно считать типовой для приложений визуализации, связана с использованием альтернативных геометрических моделей для представления элементов промышленного проекта, например, кон-структивной твердотельной модели или модели граничного представления. В ряде случаев, элементы могут задаваться несколькими моделями одновре-менно. Это означает, что следует реализовать некоторую стратегию преобра-зования и выбора моделей. Как и в предыдущем случае, такая стратегия должна определяться пользователем и может изменяться при выполнении приложения. Например, IFC 2x элементы могут геометрически представляться как параллелепипеды, тела, образованные движением контура или отсечением, тела, заданные граничным представлением, а также как объекты, представленные одной из перечисленных выше моделью с дополнительно наложенными геометрическими преобразованиями. Несколько моделей может использоваться одновременно с учетом разнообразия приложений и задач, решаемых пользователями. В представленном сценарии отображение IfcCSGtoPolyhedronMap реализует стратегию преобразования и выбора моделей с использованием базовых отображений IfcSweptSolidMap, IfcBooleanClippingMap, IfcTransformedRepresentationMap, IfcBoundingBoxMap, соответствующих различным геометрическим моделям. При подобной реализации пользователь может управлять сценарием обработки и визуализации моделей. С другой точки зрения, часто степень детализации предоставленных геометрических данных и сложность их преобразований могут быть чрезмерно высоки, чтобы обеспечить возможность интерактивной работы пользователя. В таких случаях критерии качества базовых преобразований могут быть переопределены в соответствии со сложностью необходимых вычислений. Базовые преобразования определяются как простые специфицируемые программистом отображения. Так, согласно Рис. 13, отображение IfcSweptSolidMap извлекает из IFC данных геометрическую модель тела, образованного движением контура, и генерирует в качестве выхода полиэдр. Для этого оно реконструирует контур и траекторию движения, представленные каноническими геометрическими формами, с использованием отображений IfcProfileMap и IfcExtrusionMap соответственно. Последние выбирают и применяют экземпляры отображений ExtrudedCurveMap, RevolvedCurveMap, и CompositeProfileMap, RectangleProfileMap, CircleProfileMap в зависимости от фактических типов геометрических данных. Отображение SweptSolidToPolyhedronMap, 208
используя кривые контура и траектории, генерирует выходное геометрическое представление в виде полиэдра. IFC Extrusion
IFC Profile
полупространства опционально определяются пользователем. Рис. 15 и 16 представляют примеры использования таких методик.
IFC Swept Solid MAP IFC Boolean Clipping MAP
IFC Extrusion SELECT MAP
IFC Profile SELECT MAP
Extruded Curve MAP
Composite Profile MAP
Revolved Curve MAP
…
Extrusion Curve
Rectangle Profile MAP
Circle Profile MAP
IFC Element
IFC Half Space Solid
IFC Half Space Solid MAP
IFC CSG to Polyhedron SELECT MAP IFC Swept Solid MAP
…
IFC Boolean Clipping MAP
IFC Transform Represent MAP
IFC Bounding Box MAP
…
Profile Curve Polyhedron
Swept Solid to Polyhedron MAP
Half Space C
Polyhedron Subtraction MAP
Polyhedron Polyhedron
Рис. 13. Пример простого отображения для визуализации твердых тел, полученных движением контура по заданной траектории
Рис. 14. Пример реализации простого отображения для визуализации отсеченных твердых тел
Другой пример реализации простого отображения IfcBooleanClippingMap приведен на Рис. 14. Оно предназначено для вычитания полупространства из твердого тела, представленного одной из описанных выше геометрических моделей. Его реализация основана на использовании предопределенных отображений IfcCSGtoPolyhedronMap и IfcHalfSpaceMap. Важно отметить, что зависимые отображения IfcCSGtoPolyhedronMap и IfcBooleanClippingMap используют друг друга для преобразования рекурсивно определяемой геометрической модели IFC в каноническую полиэдральную форму. Аналогичным образом реализуется отображение IfcTransformedRepresentationMap, которое выполняет стандартные трехмерные преобразования над геометрическими данными, представленными в одной из описанных выше альтернативных форм. Таким образом, отображения могут использовать друг друга для обработки сложных рекурсивно определяемых геометрических моделей. Вернемся к сценарию виртуального строительства, представленному на Рис. 13. Данный сценарий содержит также отображение CSGSubtractionMap для отсечения визуализируемого здания с целью предоставить лучшую панораму деталей проекта, обычно скрываемых вложенными архитектурными формами и конструкциями. В сценарии отсекающие плоскости и 209
Рис. 15. Пример визуализации проекта здания с использованием отсекающих плоскостей 210
Рис. 16. Пример визуализации проекта здания с использованием полупространственных отсечений Сценарий может анимировать процесс виртуального строительства путем использования соответствующих IFC данных о проекте. С этой целью отображение IfcTimeSeriesMap анализирует последовательность действий в рамках строительного проекта и назначает соответствующим элементам временные интервалы, в течение которых они должны быть включены в визуализируемую сцену. Отображение VRMLMap группирует геометрические формы, материалы и временные интервалы, полученные отображениями сценария, и генерирует результаты в виде статических или динамических VRML сцен. Рис. 17 показывает последовательность кадров, демонстрирующую участникам проекта, как должен осуществляться процесс строительства, какие недостатки и препятствия могут потенциально возникнуть при его реализации и что следует сделать, чтобы устранить их еще на предварительных стадиях. Таким образом, рассмотренные сценарии могут эффективно использоваться при решении проблем виртуального строительства. Данные сценарии применялись при разработке IFC2VRML конвертера, предназначенного для моделирования процессов проектирования и строительства зданий с использованием технологии виртуальной реальности. Приложение может быть загружено через Internet со страницы http://www.ispras.ru/~step. 211
Рис. 17. Пример последовательности кадров фильма, демонстрирующего процесс виртуального строительства
5. Заключение Проведенные исследования показывают, что композиционный программный подход может успешно применяться при построении приложений визуализации, к которым предъявляются повышенные требования гибкости, надежности, многократного использования. В частности, его использование представляется перспективным для приложений, оперирующих со сложной междисциплинарной информацией на основе сценариев, определяемых и настраиваемых пользователями непосредственно в ходе рабочей сессии. 212
Подход допускает эффективную реализацию с использованием предложенного декларативного языка потоков данных EXPRESS-F и описанной инструментальной среды разработки приложений визуализации общего назначения. Ориентация на актуальные международные стандарты представления промышленной информации STEP и моделирования виртуальных миров VRML/X3D делает представленные программные решения естественным выбором при построении приложений визуализации промышленной продукции с использованием технологий виртуальной реальности в среде Интернет/Интранет. Разработанное приложение для виртуального макетирования архитектурностроительных проектов доказывает состоятельность и осуществимость предлагаемого подхода, а также обуславливает его внедрение в другие предметные области науки и промышленности. Литература 1. D.A. Duce, D.J.Duke. Interaction, Cognition and Visualization. In P.Palanque, R.Bastide, editors, Proceedings of Eurographics Workshop on Design, Specification andVerification of Interactive Systems, Springer-Verlag,Wien, NewYork,1995, pp.1-20. 2. W.Felger, M.Fruhauf, M.Gobel, R Gnatz, G.R.Hofmann. Towards a Reference Model for Scientific Visualization Systems. In M.Grave, Y.Le Lous, W.T. Hewitt, editors, Proceedings of Eurographics Workshop on Visualization in Scientific Computing, Springer-Verlag,Wien, NewYork,1994, pp. 63-74. 3. R.Breu, U.Hinkel, C.Hofman, C.Klein, B.Paech, B. Rumpe, and V. Thurner. Towards a Formalization of the Unified Modeling Language // In ECOOP’97 — 11th European Conference on Object-Oriented Programming, Proceedings, ed. M.Aksit and S.Matsuoka, LNCS 1241, Springer-Verlag, 1997, pp.344-366. 4. M.Richters and M.Gogolla. On Formalizing the UML Object Constraint Language OCL // In ER’98 — 17th Int. Conf. Conceptual Modeling, Proceedings, ed. Tok-Wang Ling, LNCS 1507, Springer, 1998, pp. 449-464. 5. ISO 10303: Industrial Automation systems and integration — Product data representation and exchange. ISO 10303-11:1994, Description methods: The EXPRESS language reference manual. ISO 10303-21:1994, Implementation methods: Clear text encoding of the exchange structure. ISO 10303-22:1998, Implementation methods: Standard data access interface. ISO 10303-28:2003, Implementation methods: XML representations of EXPRESS schemas and data. 6. Klimenko S., Nikitin I., Burkin V., Semenov V., Tarlapan O., Hagen H. Visualization in string theory. // ACM Computers & Graphics, vol. 24, num. 1, 2000, pp.23-30. 7. Semenov V., Morozov S., Tarlapan O., Belyaeva A. Component-based development of scientific computing applications in OpenMV environment. // Proceedings of 16th IMACS World Congress, Lausanne, Switzerland, August 21–25, 2000, ed. Deville M., Owens R., ISBN 3-9522075-1-9. 8. Industry Foundation Classes, Release 2. The International Alliance for Interoperability, 1999, URL: http://www.iaiweb.lbl.gov. 9. The Virtual Reality Modeling Language. International Standard ISO/IEC 14772-1:1997. 10. Web3D Consortium, URL: http://www.web3d.org.
213
О роли аппарата эмоций как системообразующего фактора в адаптивных системах управления* А.А. Жданов Аннотация. Обосновывается роль аппарата эмоций организма, как основного системообразующего фактора, определяющего строение и функционирование нервной системы и ее имитационных моделей. Показывается, что такой аппарат является: источником внутренней активности, целевой функцией управления, средством качественного оценивания общего текущего состояния и отдельных элементов знаний – образов и действий, внутренними часами системы, а также каналом передачи оценок качества информации при общении. Предлагается математический формализм основных функций аппарата эмоций.
В работах П.К. Анохина по теории функциональных систем было введено понятие системообразующего фактора (результата системы), под которым понимался полезный приспособительный эффект в соотношении «организм – среда», достигаемый при реализации системы [1]. На роль такового в функциональной системе предлагался «полезный приспособительный результат» - будущее, ожидаемое состояние системы. Нам представляется, что такое понимание системообразующего фактора является лишь частичным. Действительно, остается непонятным: а) что ставит системе цели, б) какие цели могут быть поставлены перед системой, в) почему система должна прилагать усилия к достижению этих целей, г) для достижения каких именно целей приспособлена нервная система организма? Мы предлагаем расширить и конкретизировать представление о системообразующем факторе, организующем и направляющем функционирование такой системы, как организм животного, и на эту роль предлагаем его аппарат эмоций [2]. Рассмотрим основные функции и возможности аппарата эмоций.
1. Эмоции – источник внутренней активности системы Когда создается любая машина, всегда предусматривается источник ее движущей энергии, должный приводить в движение части этой системы для достижения цели, поставленной перед нею. Выбор источника энергии для построения конкретной машины, зависит от сторонних обстоятельств. *
Источник энергии должен использовать некоторый подходящий естественный процесс, протекающий в определенном направлении. В машине создается механизм преобразования энергии в требуемую от данной машины работу, а также механизм контроля и регулирования расходования энергии. Так, естественное «стремление» электронов от отрицательного к положительному полюсу источника электрического напряжения используется как движущая сила для всех электрических приборов. Следует различать цели, которые ставил перед машиной ее создатель, и «внутренние» целевые функции, непосредственно приводящие машину в действие. Так часы идут не потому, чтобы давать информацию о времени, а потому, что их шестерни подталкивает пружина. Отключим источник энергии, и функционирование любой машины останавливается, так как отключается его основная непосредственная «мотивация». В живой организм его «создателем» также должен был быть введен некий источник «энергии» внутренней активности. Это должна быть универсальная «движущая сила», заставляющая активно действовать любой организм, независимо от его сложности, возраста и интеллекта. Здесь также следует различать две цели: цель «создателя» организма, и целевую функцию, «зашитую» в конструкции организма. Мы не знаем, кто или что в Природе создавало живые организмы, был ли это творческий целенаправленный акт, либо результат самоорганизации материи. Мы не знаем и истинных целей феномена жизни, а можем только строить гипотезы, предполагая, например, что целью организмов является сбор и накопление информации о мире, или эволюционный поиск удачных форм жизни, или некоторое преобразование мира. Однако в иерархической системе целей обязательно должны присутствовать две: а) выживание организма, как целостной системы, способной длительное время сохранять в биологическом мозге накопленные знания и способствовать их логически непрерывному развитию, и б) последовательное накопление знаний, необходимых для выживания организма. Выживанию способствует прогнозирование будущих событий, основанное на накопленных эмпирических знаниях, и совершение упреждающих действий, обеспечивающих переход в благоприятные для выживания состояния. Обе этих цели требуют активного поискового характера поведения. Мы видим в аппарате эмоций следующий механизм, задающий активное поведение. В аппарате эмоций, прежде всего, имеет место множество объектов, раздражение которых сопровождается приятными, либо неприятными для организма ощущениями, включая самые предельные их степени (Рис. 1). Это множество ощущений и их носителей-объектов упорядочено по степени этого качества – «приятности» ощущения. Пусть в каждый момент времени выделен один и только один из этих объектов, который назовем эмоциональной оценкой текущего состояния системы, и обозначим как S(t). Соответственно, эта оценка может принимать одно из следующего множества возможных значений
S= {s1, s2, … , sz,… , sZ},
Работа выполнена при поддержке гранта РФФИ № 03-01-00323
215
216
где, например, s1=”-5”, s2,=“-4”, … , sZ=“5”. Значение S(t)=szS функционально зависит от совокупности эмоциональных оценок pz,j множества распознанных в текущий момент образов Oj. Здесь возможные значения эмоциональных оценок образов также могут быть равны p1,j= ”-5”, p2,j,= “-4”, …, pZ,j = “5”. В множестве образов, которые система уже научилась распознавать, что составляет ее «Память образов», распознанные в текущий момент образы пометим символом «1», т.е. если образ Oj распознан в момент t, то будем писать Oj(t)=1, а если не распознан, то будем писать Oj(t)=0. Эмоциональная оценка pz,j образа является атрибутом образа. Пусть функция, определяющая оценку S(t), есть, например, просто средняя величина от эмоциональных оценок всех распознанных в текущий момент образов, округленная до ближайшего значения из множества S. Такой аппарат можно представить в виде своего рода термометра, показывающего среднюю текущую «эмоциональную температуру тела». Мотивация
Вычислитель среднего от оценок, распознанных в текущий момент образов
Максимально хорошая эмоция «5» «4» «3» «2» «1» «0» «-1» «-2» «...» «-3» «-4» «-5»
Текущее эмоциональное состояние
Максимально плохая эмоция Рис. 1. Модель аппарата эмоций. Одна из его функций состоит в вычислении оценки текущего эмоционального состояния объекта – одной из множества возможных эмоциональных оценок. Другая его функция есть задание универсальной мотивации – постоянного стремления управляющей системы к повышению эмоционального состояния. Жестко «зашьем» в управляющую систему целевую функцию максимизировать эмоциональную оценку текущего состояния системы S(t). Другими словами, организм должен бояться и бежать неприятных эмоциональных оценок, и стремиться к приятным оценкам. Средством 217
достижения этой цели должно быть только инициирование актуаторов, которыми располагает организм. Эти актуаторы должны воздействовать не непосредственно на аппарат эмоций (в отличие от известной экспериментальной крысы, получившей возможность нажимать на педаль и возбуждать свой центр приятных ощущений через вживленный в него электрод, чем она и занималась до смерти), но на окружающую среду, обеспечивая возможные способы взаимодействия данного организма со средой. И только вызвав в среде появление таких объектов, процессов или явлений, воздействующих на сенсоры системы, которые будут распознаны этой же системой как образы, вместе с их атрибутами - определенными эмоциональными оценками, нервная система сможет тем самым повлиять на эмоциональную оценку текущего состояния. Тем самым, природа заставила организм, стремящийся лишь к получению приятных ощущений и к избежанию неприятных, взаимодействовать со средой, что приводит к накоплению новых знаний о свойствах системы «среда-организм», и повышает шансы организма на выживание. Если отключить аппарат эмоций, то организм перестанет что-либо делать, поскольку у него полностью пропадет мотивация к активности, и он погибнет в полном безразличии. Очевидно, что природе следует позаботиться о том, чтобы нервной системе были приятны те воздействия среды, которые объективно полезны для организма, способствуют его выживанию и накоплению знаний, а вредные воздействия были бы неприятны. Эта задача решается в природе естественным отбором. Успешнее выживают организмы, у которых образы получают более адекватные оценки, а при неправильных оценках, организм стремится к вредным воздействиям и погибает. Описанный механизм побуждения к активности через аппарат эмоций является универсальным и в целом не зависит от конкретного содержания образов. Обычно при рассмотрении функциональных систем говорят о наличии определенных «мотиваций», как о стремлении удовлетворить определенные «потребности», которые тут же перечисляются, например, потребность к сытости, к размножению и еще несколько других. Однако описанное нами стремление к получению положительных эмоциональных оценок и к избежанию отрицательных оценок является более общим. Так, неважно, какой образ вызвал резко отрицательную оценку – от срабатывания рецепторов в пустом желудке или от падения курса акций на финансовой бирже, нервная система будет стараться инициировать действия, направленные на вытеснение неприятных ей эмоциональных оценок, а единственным способом для нее является совершение воздействий на среду и такое изменение ее состояния, которое вызовет вытеснение неприятных образов.
2. Выработка эмоциональных оценок образов Вначале следует сказать о понятии образа. Всякая нервная система получает информацию из окружающей ее среды через специализированные сенсоры – рецепторы, в виде стандартизованных бинарных сигналов, представленных 218
нервными импульсами (не будем здесь рассматривать восприятие информации нервной системой через другие возможные каналы – химические вещества или полевые воздействия). Практически вся поверхность тела, отделяющая его от окружающей среды, а также многие внутренние участки тела организма снабжены рецепторными клетками, суммарное число которых огромно. Нервная система не сможет справиться с таким объемом входных данных без их конвергенции, агрегирования и обобщения. Обобщение входной информации осуществляют нейроны, соединенные в конвергентные сети. При этом, сети выделяют также существенную для управления информацию, что осуществляется в процессе автоматической кластеризации сигналов (в поиске статистически зависимых, коррелирующих компонент) в закономерные паттерны – образы. Каждый нейрон, на наш взгляд, пропускает дальше по сети только ту информацию, которая для него не случайна, т.е. представляет собой паттерн – образ, который этот нейрон научился распознавать. При этом в отношении каждого отдельного образа можно говорить, что он либо еще не сформирован, либо уже сформирован, а об уже сформированном образе можно говорить, что он либо распознан в текущий момент, либо не распознан. Некоторые образы важнейших для организма данного биологического вида явлений и состояний являются сформированными изначально к моменту рождения (например, образ голода), или формируются по прецедентам (образ родителя для некоторых животных). Остальные образы формируются в процессе жизни. Итак, пусть нервная система оперирует информацией в виде образов. Конечными выходными сигналами нервной системы, как сети нейронов, являются сигналы, инициирующие актуаторы. Такие сигналы, являющиеся результатом решения, принятого нервной системой, будем называть действиями. Зависимость образов и действий, найденная нервной системой, есть ее знания, отражающие функциональные свойства системы «среда-организм». Однако эти знания нельзя использовать для управления без задания целей и критериев, т.е. без окрашивания данной информации в разные цвета качества, что и делает аппарат эмоций. Пусть сформирован некоторый новый образ Oj. Эмоциональную оценку pz,j для этого образа нервная система может формировать в процессе одновременного наблюдения за эмоциональной оценкой текущего состояния системы S(t) в моменты, когда данный образ Oj(t)=1 распознан или в некоторых окрестностях этих моментов времени. Если каждый раз при распознавании данного образа оценка S(t) падает, это является основанием для приписывания этому образу низкой оценки, и, соответственно, наоборот. Конкретно, оценка pz,j образа Oj может быть равна среднему арифметическому от оценок S(t) в моменты, когда данный образ распознан, т.е. когда Oj(t)=1. Практически, сразу после формирования образа его оценка нейтральна, но с накоплением статистики она может измениться. Оценка каждого вновь сформированного образа в свою очередь начинает участвовать в выработке эмоциональной оценки текущего состояния системы S(t), поэтому наше состояние начинает определяться и вкладом новых сформи219
рованных нами образов. Этот итерационный процесс формирования оценок образов начинается с оценок образов, изначально сформированных в организме, т.е. переданных ему по наследству от предков данного вида, и приспосо-бленных к усредненным условиям существования организмов данного вида. Эмоциональные оценки образов, во всяком случае - ярко выраженные оценки, по-видимому, достаточно инерционны и долго хранятся в памяти нервной системы.
3. Выраженные эмоциональные оценки Эмоциональные оценки как отдельных образов, так и общего текущего состояния носят сравнительно объективный характер и могут существенно отличаться для разных организмов даже одного вида. Такие оценки не слишком удобны для принятия решений, особенно при общении с себе подобными. Поэтому можно наблюдать существование дополнительной шкалы относите-льных оценок, используемых как для непосредственного управления, так и при общении между организмами. Назовем такого рода оценки выраженными эмоциональными оценками и будем обозначать такие оценки символом B(t). Формально упорядоченная шкала оценок B(t) подобна шкале оценок S(t), с той разницей, что она содержит меньше оценок, т.е. они более грубы, однако имеют (в первую очередь у людей) уже словесное выражение. Так, можно весьма правдоподобно определить эту шкалу следующим множеством оценок: B= {b1, b2, … , bh,… , bH}, где b1= ”невыносимо плохо”,b2= “очень плохо”, b3= “плохо”, b4= “так себе ”, b5= “хорошо”, b6= “очень хорошо”, b7= “прекрасно”, b8 = “недостижимо прекрасно”. В каждый текущий момент t инициирована только одна из оценок B(t) = bh B. Существует некоторое пропорциональное отображение из множества S в множество B, : S B, такое, что всегда текущая оценка S(t) отображается в текущую оценку B(t). Однако не все множество S может быть испытано нервной системой данного индивида к текущему моменту, но только оценки из диапазона [Smin, Smax]. Поэтому отображение переводит Smin в b1, а Smax в bH, что дает индивиду возможность пользоваться всем диапазоном оценок B. Такая шкала объясняет некоторые эффекты различного индивидуального восприятия явлений. Например, пусть индивид всю жизнь находился в очень благоприятных условиях и узнал только диапазон оценок [Smin1, Smax1], а другой инди-вид жил в плохих условиях и узнал только оценки из диапазона [Smin2, Smax2], пусть Smin2 < Smin1 и Smax2 < Smax1. Тогда один и тот же образ с оценкой pz,j может оцениваться первым индивидом, например, оценкой b= “плохо”, а вторым индивидом – оценкой “очень хорошо”. Другой эффект – если у некоторого индивида вдруг упала оценка Smin, то благодаря отображению произойдет переоценивание образов, и оценки всех образов автоматически возрастут, то, что оценивалось как плохое, станет хорошим, в том числе и оценка текущего состояния индивида. 220
4. Роль эмоциональных оценок в принятии управляющих решений Алгоритм принятия решений, основанный на эмоциональных оценках, описан нами в [2-4]. Его идея состоит в следующем. В каждый текущий момент подсистема распознавания образов сообщает нервной системе, какие образы распознаны ею в текущий момент. Тем самым в базе знаний управляющей системы отделяются те ее области, которые адекватны данной ситуации, т.е. выделяется множество действий, которые вообще можно совершить в данной ситуации, согласно знаниям, накопленным нервной системой. В этих отделенных областях базы знаний нервной системой отыскиваются действия, которые обещают привести систему «среда-организм» в состояния, имеющие максимальные из возможных в данной ситуации эмоциональные оценки, либо в состояния, когда прекратят распознаваться образы с максимально плохими оценками. Найдя такое действие, нервная система дает команду исполнителям совершить его. Этот способ принятия решений одновременно активен и реактивен. Например, при отсутствии всякого внешнего стимула, животное может встать и отправиться на поиски чего-то приятного, воспоминание о чем хранится у него в памяти, а в текущей ситуации он не видит для этого препятствий. Если же на животное подействовал некий раздражающий фактор, оно начнет совершать действия, направленные на его прекращение.
5. Аппарат эмоций как внутренние системные часы нервной системы При принятии решений в текущей ситуации нервной системе необходимо просмотреть свою базу знаний и найти оптимальное решение. Однако просмотр базы знаний требует определенного времени, которым нервная система может не располагать в текущих условиях. Определение времени, отведенного нервной системе на принятие решений в текущей ситуации, есть также функция аппарата эмоций. Внутреннее время нервной системы выражается в количестве k(t) образов, которое можно успеть проанализировать в базе знаний при принятии решений в текущих условиях. Речь здесь идет об «образах результатов» совершения действий, т.е. о тех образах, распознавание которых управляющая система может вызвать своими действиями. Это число определяется некоторой функцией
k(t) = f(S(t), dS/dt) от значений общей текущей эмоциональной оценки и ее производной (Рис. 2). Эта функция монотонно возрастает от некоторых предельно допустимых минимальных значений как Smin(t), так и (dS/dt)min. Т.е., чем хуже ситуация или чем быстрее она ухудшается, тем скорее надо принимать решение. При минимальных граничных значениях функция равна нулю, здесь нервная система «падает в обморок», так как не в состоянии успеть принять решение. 221
При больших значениях аргументов функция f имеет плато или спад, что индивидуально для индивида, и, возможно, в целом определяет тип его темперамента (сангвиник, холерик и т.д.).
Рис. 2. Примерный вид зависимости времени, отведенного на принятие решений (глубины просмотра «Базы знаний»), от значения общего текущего эмоционального состояния и его производной. Очевидно также, что те k(t) образов, которые управляющая система может проанализировать при принятии решений в текущих условиях, должны быть наиболее важными образами, т.е. образами, с максимальными, по модулю, оценками. Множество образов всегда упорядочивается по убыванию модуля их эмоциональной оценки, и в каждый текущий момент отсекаются для принятия решений только k(t) первых из них, и это число не очень велико. Из психологии известно «правило 7 +/- 2», отмечающее, что, например, человек может контролировать одновременно всего лишь около семи параметров. Можно предполагать, что живой организм, вынужденный, помимо всего прочего, поддерживать свой гомеостазис, в большинстве случаев борется именно с образами, имеющими большие отрицательные оценки, связанные с вызванными возмущающими факторами отклонениями от нормы основных параметров, определяющих нормальное функционирование организма. В этом отношении управляющая система проявляет себя как реактивная система, реагирующая на возмущающие факторы. Однако, хотя и сравнительно редко, но управляющая система распознает условия, благоприятные для получения некоторого большого выигрыша – возможности совершить некое действие, которое приведет к распознаванию образа с большой положительной оценкой. Тогда управляющая система может выбрать именно это действие, пренебрегая даже необходимостью поддержания гомеостазиса своего организма. Например, это проявляется в ситуациях, когда живое существо идет на некий опасный для него риск в надежде получить крупный выигрыш, и этот риск пропорционален 222
возможному выигрышу. В этих случаях управляющая нервная система проявляет себя не как реактивная, но как активная система, она совершает действия, не вызванные непосредственными воздействиями среды, но идущими от ее сложившейся информационной модели мира. Итак, в каждый момент функция f аппарата эмоций подсказывает нервной системе, сколько образов с максимальными по модулю оценками она может успеть просмотреть в базе знаний с целью прогнозирования их поведения при альтернативных вариантах действий, и определяет лучшее из возможных действий с учетом последствий только по этим образам. Остальные образы, на учет которых при прогнозировании не хватило времени, получат в результате выбранного действия случайные изменения. Здесь следует обратить внимание на то, что «результат», который достигается вследствие совершения управляющей системой выбранного ею действия, не является детерминированным по нескольким причинам, а именно: a) потому что управляющая система еще не знает всех последствий того или иного своего действия, у нее еще не сформированы соответствующие образы, не хватает знаний; b) управляющая система просто не успевает в текущих условиях учесть даже те последствия (образы), которые она знает, не хватает времени; c) а также по другим причинам. Отсюда следует, в частности, что от величины выработанной управляющей системой эмоциональной оценки образа зависит, попадет ли этот образ в число тех, которые будут «приняты во внимание» при принятии решения, или вовсе не попадет. Например, у человека эмоциональные оценки образов закладываются во многом в процессе его обучения и воспитания, т.е. от системы привитых человеку эмоциональных оценок образов в корне зависит его поведение, приоритеты, которые он выбирает при принятии решений.
6. Аппарат эмоций, как канал передачи качественной информации Наконец, следует упомянуть о важной роли участия аппарата эмоций в общении индивидов. При необходимости передачи знаний от одного индивида к другому, животному приходится передавать информацию как об образах некоторых объектов, так и о своих эмоциональных оценках этих образов. Поскольку даже в элементарном передаваемом знании должна содержаться информация и об образах условий, и об образах действий, и об образах ожидаемых результатов действия, то нужно передавать и сведения об эмоциональных оценках каждого из таких компонент. Каналом для передачи такой многообразной эмоциональной информации служит мимика животного, управляемая аппаратом эмоций, с помощью которой передается и распознается эмоциональная информация об условиях, действиях и об ожидаемых результатах действия. Здесь требуется обращение к специальным знаниям, чтобы понять, какие именно части тела, лица, и с помощью каких мимических выражений и жестов передают информацию о качественных оценках, являющихся актуальными в текущий момент. Очевидно, что чем развитее 223
управляющая система животного, чем больше образов формируется ею и принимается в расчет при принятии решений, чем более социально животное, тем более развитым должен быть этот «мимический» канал для передачи эмоциональной компоненты информации при общении между индивидами.
7. Использование аппарата эмоций в прикладных управляющих системах Описанные здесь принципы работы аппарата эмоций частично использовались нами при построении прикладных систем на основе метода ААУ [4]. В системах адаптивного управления угловым движением космического аппарата [4,5,6], автомобильной подвески, мобильного робота [7,8], системы управления моделью сердечно-сосудистой системы [9] важную роль играла подсистема эмоций. Использовались эмоциональные оценки, описанные выше в пунктах (1), (2), (4). В дальнейшем планируется реализовать и остальные возможности и функции аппарата эмоций. В заключение отметим, что общепринятое на сегодняшний день понятие, что эмоции животных определяются какой-либо актуальной потребностью и оценкой вероятности ее удовлетворения [10], нам представляются мало конструктивными. Литература 1. Анохин П.К. Очерки по физиологии функциональных систем. – М.: Медицина, 1975. – С. 447. 2. Zhdanov A.A., A.N. Vinokurov, Emotions Simulation in Methodology of Autonomous Adaptive Control. 1999 -14th IEEE International Symposium on Intelligent Control /Intelligent Systems and Semiotics ISIC/ISAS'99. Special session Emotions and Intelligent Systems. September 15-17, 1999, Cambridge, Massachusetts, USA. Paper 99002I-6. 3. Жданов А.А. Об одном имитационном подходе к адаптивному управлению. Сборник "Вопросы кибернетики" №2. Научный совет по комплексной проблеме "Кибернетика" РАН. М., 1996, С. 171- 206. 4. Жданов А. А., Метод автономного адаптивного управления // Известия Академии Наук. Теория и системы управления, 1999, № 5, с. 127-134. 5. Жданов А.А., Арсеньев С.В., Половников В.А. Об одной методологии автономного адаптивного управления. Труды института системного прог-раммирования РАН. 1999. Том 1. М.: Биоинформсервис, 2000.- С. 66-83. (англ. том. Zhdanov A.A., S.V. Arsenjev, V.A. Polovnikov, On autonomous adaptive control methodology.// Proceedings of the Russian Academy of Sciences Institute for System Programming. N 1, 1999, pp. 55-70). 6. Жданов А.А. Земских Л.В. Беляев Б.Б. Система стабилизации углового движения космического аппарата на основе нейоноподобной системы автономного адаптивного управления. // Космические Исследования, М. 2004 (принята редакцией).
224
7. Жданов А.А., Крыжановский М.В. Преображенский Н.Б. Нейронная адаптивная система управления. Труды международной конференции "Интеллектуальные и многопроцессорные системы" IMS’2002., С. 115-118. Кацивели. 8. Жданов А.А., Крыжановский М.В., Преображенский Н.Б.. Бионическая интеллектуальная автономная адаптивная система управления мобильным роботом // Мехатроника, 2004 (принята редакцией). 9. Zhdanov Alexander, Maxim Karavaev and Helen Maklakova, Claire Medigue, Michel Sorine. Simulation of control mechanisms in the cardio-vascular system. French-Russian A.M. Liapunov Institute for Applied Mathematics and Computer Science. Transactions. Vol. 4. Pp. 233-245. Moscow. 2003. 10. Психофизиология. Под. Ред Ю.И. Александрова. Изд-е 2-е. М., СПб и др.: «Питер», 2003, с. 267.
225
Архитектурно-управляемая модернизация существующего программного обеспечения Н. Н. Мансуров Аннотация. Отдел CASE-технологий института системного программирования (ИСП) занимается разработкой CASE-инструментов следующего поколения, основанных на формальных методах. Разрабатываемые инструменты и методы ориентированы на практическое усовершенствование процесса создания и поддержки программного обеспечения (ПО) в индустрии разработки систем реального времени и встроенных систем. В частности мы определяем ускоренную методологию спецификации, проектирования, тестирования и обратной инженерии ПО. Методология основана на широком применении формальных методов и формальных языков описания программ на самых ранних стадиях разработки, а также на автоматическом извлечении формальных моделей при помощи обратной инженерии из существующего кода. Основные направления в исследовательской работе отдела – восстановление и перестроение (рефакторинг) архитектуры ПО. Эта статья посвящена созданию методов так называемой архитектурно-управляемой модернизации существующего кода в Object Management Group (OMG), совместно с нашим партнером – компанией klocwork.
1. Введение Отдел CASE-технологий (Computer Aided Software Engineering tools) ИСП занимается исследованием и разработкой в области современной инструментальной поддержки разработки ПО. В отделе разрабатываются инструменты для работы с моделями следующего поколения, которые ускоряют разработку ПО за счет использования методов формального моделирования, автоматических трансформаций моделей, включая передовые технологии генерации кода, управляемую архитектуру ПО, валидацию и верификацию, особенно на ранних стадиях процесса разработки. Также осуществляется разработка методов и инструментов в следующих основных направлениях: Инструментальная поддержка управляемой архитектуры ПО. Это направление охватывает методы архитектурно-ориентированной разработки ПО, инструментальную поддержку разработки групп программных продуктов (Software Product Lines), автоматическое извлечение формальных моделей из существующего кода, а также 227
инструменты для ускоренной поддержки и модуляризации существующих программных систем (архитектурно-ориентированные «раскопки» и рефакторинг) Исполняемые сценарии. Это направление охватывает методы системной инженерии, анализ требований к ПО, а также разработку ПО, основанную на сценариях использования. Основные цели исследований отдела: разработать архитектурно-ориентированный ускоренный подход, включающий в себя набор методов спецификации, проектирования, тестирования и обратной инженерии ПО, основанных в значительной степени на использовании формальных методов и формальных языков описания ПО на самых ранних стадиях процесса разработки, а также автоматическом извлечении формальных моделей из существующего кода, уделяя особое внимание архитектурным вопросам и «крупномасштабному программированию» создать открытую архитектуру, включающую в себя языки и инструменты, поддерживающие описанный подход, и позволяющие его, в как можно большей, степени автоматизировать, для того чтобы сделать формальные методы и языки более доступными для разработчиков. Отдел CASE-технологий тесно сотрудничает с компанией Klocwork, Inc. (http://www.klocwork.com), располагающейся в Оттаве (Канада). Klocwork – член Object Management Group (OMG) (http://www.omg.org), где является сопредседателем группы (Special Interest Group) по архитектурно-управляемой модернизации существующего кода (http://legacy.omg.org). В сотрудничестве с Klocwork исследовательская группа отдела CASE-технологий активно участвует в процессе стандартизации формальных методов разработки ПО в OMG. Направление исследований отдела определяется несколькими факторами. В современной индустрии разработки программных систем реального времени, а также встроенных систем, существует достаточно много различных успешных организаций и подходов. Но по мере того, как возникают новые требования и технологии, и все больше участников вступает в игру, появляется потребность в усовершенствовании существующих подходов [4]. В частности, время выхода продукта на рынок («time-to-market») становится доминирующим фактором успеха в индустрии разработки ПО. Другие цели более традиционны и включают в себя улучшение качества программного продукта, соотношения цена/производительность и снижение расходов на производство ПО [4]. Общепризнанно, что использование методов формального описания (Formal Description Techniques - FDT), при поддержке CASE-инструментов – это важная составляющая в процессе достижения этих целей. Установленное, используемое и работающее ПО представляет большую ценность для современной экономики. Большая часть существующих прикладных систем, т.е. всего эксплуатируемого ПО, независимо от платформы, на 228
которой оно исполняется, языков программирования, на которых оно написано и времени эксплуатации, перешла на стадию поддержки и эволюции [12]. Поддержка существующего ПО включает в себя несколько направлений [9]: (1) корректирующая поддержка (исправление дефектов); (2) адаптационная поддержка (адаптация системы к изменениям исполняемой платформы); (3) превентивная поддержка (поддержание и улучшение внутренней структуры системы для предотвращения «распада» архитектуры); (4) расширение функциональности (добавление новых возможностей). Добавление новой возможности в существующую систему зачастую оказывается более сложной задачей, чем разработка аналогичной по функциональности системы с нуля, из-за ограничений, которые накладывает на дизайнерские решения существующее ПО. Таким образом, существует ряд проблем, специфичных для фазы поддержки, которые не возникают в процессе разработки новых систем: необходимо учитывать большее количество информации (унаследованные дизайнерские и программные решения, анализ существующего исходного кода); недостаток экспертных знаний из-за того, что ведущие разработчики уходят из проекта; необходимость обучения нового персонала; географически распределенная среда разработки, например, когда поддержка ПО осуществляется посредством аутсорсинга; недостаточная гибкость, сопротивление системы при попытке внесения изменений, вызванное «распадом» архитектуры (обычно сопротивление возрастает со временем). Эволюция существующего ПО зачастую затруднена, поскольку его стратегическая ценность и способность приспосабливаться ослаблена факторами, напрямую не связанными с его функциональностью. Примерами таких факторов может послужить неэффективность анализа и поддержки системы с экономической точки зрения, затрудненная интероперабельность, или зависимость системы от устаревших технологий или архитектур. Необходимость анализа и эволюции существующего ПО возникает в задачах документирования, развития, модификации, взаимодействия, переноса на другую платформу, перепроектирования и переустановки. Эти задачи в совокупности можно рассматривать как «модернизацию» ПО. Модернизация становится актуальной в тех случаях, когда существующие традиционные практики не удовлетворяют нуждам бизнеса [12]. Проблема поддержки и эволюционного развития существующего ПО достаточно долго игнорировалась ведущими методологами, разработчиками и стандартизационными комитетами. В результате между разработкой новых проектов (green-field projects, т.е. проектов разрабатываемых с нуля) и поддержкой существующего ПО образовался значительный разрыв в подходах и инструментальной поддержке. В частности, поддержка существующего ПО традиционно считалась одним из «потерянных миров» для методов 229
формального моделирования и CASE-инструментов, основанных на формальных методах. Современные подходы, использующие формальные языки и продвинутую инструментальную поддержку, зачастую плохо масштабируются применительно к задачам поддержки существующего ПО. Предварительное моделирование больших существующих систем обходится слишком дорого, и, поэтому, потенциальные преимущества современных подходов и инструментов не доступны для разработчиков, имеющих дело с модернизацией существующих систем. Инструменты поддержки обычно разрабатываются для узкого класса задач и слабо распространены в индустрии разработки ПО. С другой стороны задачи, специфичные для поддержки ПО (такие, как устранение дефектов, адаптация и анализ существующих дизайнерских решений) составляют значительно большую часть жизненного цикла программной системы, чем задачи прямой инженерии (такие как анализ исходных требований, проектирование и создание исходного кода системы). Как уже было показано в [15], начиная с 90-х годов, в процесс устранения дефектов и расширения функциональности существующих программных систем вовлекается больше разработчиков, чем в разработку новых проектов «с нуля» (см. Таблицу 1). Год Новые проекты Расширение Устранение Всего функциональности дефектов 1990 3 (43%) 3 (43%) 1 (14%) 7 2000 4 (40%) 4.5 (45%) 1.5 (15%) 10 2010 5 (35%) 7 (50%) 2 (14%) 14 Таблица 1. Прогноз количества разработчиков (млн. чел.) и распределение по решаемым задачам. Таким образом, большую важность имеет разработка ускоренных подходов, применимых в задачах поддержки ПО, и основанных на некоторых методологических принципах. Это является главной целью нашего исследования. Остальная часть статьи организована следующим образом. Раздел 2 описывает мероприятия, проводимые в рамках OMG, направленные на усовершенствование процесса поддержки и эволюции существующего ПО. В разделе 3 обсуждается своевременность разработки подходов к модернизации программных систем. Раздел 4 описывает первый запрос на внесение предложений (RFP – Request for Proposal) группы по архитекурноуправляемой модернизации OMG, вносящее предложения по разработке KDM (Knowledge Discovered Meta-Model). Разделы 5-8 представляют наши исследования в области архитектурно-ориентированного восстановления знаний о програм-мной системе и трансформации (рефакторинга) существующего ПО. В частности, раздел 5 содержит краткое введение в подход, основанный на интерфейсных моделях и архитектурных «раскопках», применяемый в Klocwork. Раздел 6 описывает архитектурно-ориентированный рефакторинг. Раздел 7 обрисовывает концепцию управляемых архитектур и 230
описывает соответствующую инструментальную поддержку. Раздел 8 содержит обсуждение того, как архитектурно-ориентированные трансформации могут использоваться для миграции современного ПО в направлении MDA (Model-Driven Architecture – модельно управляемая архитектура). Раздел 9 содержит некоторые выводы и заключение.
2. Почему OMG? Object Management Group (OMG) - это открытая некоммерческая организация, деятельность которой направлена на разработку и поддержку спецификаций для взаимодействующих промышленных приложений. Список членов OMG включает много организаций из числа наиболее успешных и новаторских компаний компьютерной индустрии, равно как и из числа тех, кто находится на переднем крае использования новых технологий для получения конкурентных преимуществ в своем бизнесе. Все они взяли на себя обязательства активно участвовать в формировании будущего промышленных систем, интернет-систем, систем реального времени и встроенных систем. OMG разработала несколько очень известных в индустрии и наиболее влиятельных спецификаций, включая CORBA, OMG IDL, IIOP, UML, MOF, XMI, CWM, OMA и Domain Facilities, в таких отраслях, как здравоохранение, промышленное производство, телекоммуникации и многие другие. Model Driven Architecture (MDA) опирается на успех этих технологий, обеспечивая всестороннюю основу взаимодействия для создания взаимосвязанных систем будущего. Однако, в прошлом, индустрия прямой инженерии практически полностью игнорировала существующие программные ресурсы, в то время как обратная инженерия, в свою очередь, игнорировала новые методы прямой инженерии. Со временем, это породило существенный разрыв в инструментальной и методологической базе, используемой в новых проектах, и проектах, занимающихся поддержкой и эволюцией существующего кода. Прилагаемые усилия направлены на то, чтобы преодолеть барьеры между инструментами прямой и обратной инженерии, и, таким образом, помочь организациям с существующими программными ресурсами использовать преимущества современных технологий обратной инженерии таких, как Unified Modeling Language (UML) [5] и Model-Driven Architecture (MDA) [14]. MDA обеспечивает открытый, независимый от производителей подход к проблеме интероперабельности, основывающийся и усиливающий значимость принятых стандартов моделирования. MDA направлен на отделение бизнес логики и логики приложений от технологий целевой платформы. MDA пропагандирует новый способ разработки ПО, в котором платформонезависимая модель становится долгосрочно поддерживаемым артефактом. Платформо-независимые приложения, построенные с использованием MDA и сопутствующих стандартов, могут быть реализованы автоматически на множестве открытых и проприетарных платформ включая CORBA, J2EE, .NET 231
и Web Services или на других Web-платформах, с помощью компиляторов моделей. По мере появления платформ и технологий, MDA гарантирует будущую защиту инвестиций в разработку. Таким образом, MDA абстрагируется от промежуточного ПО (middleware) для обеспечения всестороннего, структурированного решения для обеспечения будущей интероперабельности и переносимости приложений. Платформо-независимые модели MDA могут быть одной из целей модернизации. Для организаций, которые приняли решение о переходе на MDA, модернизация больше не является переносом с одного языка на другой, или с одной платформы на другую. Модернизация в контексте MDA создает модель кода с целью импортировать ее в MDA-ориентированную среду разработки. Стандарты модернизации становятся важной составляющей успешного применения современных технологий прямой инженерии, таких как MDA и UML. В июне 2003 года OMG анонсировала создание Platform Special Interest Group (PSIG) с целью создания спецификаций и поддержания консенсуса в индустрии по вопросу модернизации существующих приложений (http://legacy.omg.org/) [11]. Главной целью рабочей группы является создание стандартов модельноуправляемой модернизации, определенной как процесс понимания и развития ресурсов существующего ПО, с акцентом на архитектурные изменения. Благодаря созданию стандартов модернизации пользователи могут продлить жизнь своего ПО, впоследствии увеличив эффективность инвестиций (Return on Investment, ROI). Это сделает возможным взаимодействие между различными производителями ПО, а также обеспечит, что однажды модернизированное ПО, будет возможно подвергнуть подобной трансформации в будущем (доказательство функциональности). Стандартизация будет гарантировать, что конечные пользователи делают инвестиции не только в конкретные инструменты, а скорее в координированную стратегию. Для достижения своих целей группа планирует применить существующие стандарты моделирования OMG, включая MDA, к успешной трансформации и возвращения к жизни существующих приложений. В конечном счете, стандартизация модельно-управляемой модернизации поможет индустрии ПО и частному бизнесу уменьшением рисков инициатив по улучшению своего ПО, уменьшением времени, рисков и стоимости трансформации ПО с одновременным увеличением эффективности инвестиций инструментов разработки ПО. В ноябре 2003 года, в Лондоне, члены OMG начали работу над двумя новыми стандартами в этой области. В первую очередь Special Interest Group (SIG), работающая над модельно-управляемой модернизацией, опубликовала запрос на внесение предложений (RFP) по стандартизации фундаментальной модели (в технической терминологии, метамодели) для анализа функциональности существующего ПО. В рамках другого направления работ, группа разработала запрос комментариев (RFC) на спецификацию повторно используемых ресурсов (Reusable Asset 232
Specification или RAS). RAS определяет стандартный способ сборки повторно используемых программных ресурсов. Это является важной частью процесса разработки ПО, основанной на программных ресурсах (Asset-based Development или ABD), способствуя повторному использованию ресурсов разработки ПО в индустрии.
3. Почему теперь? Есть несколько факторов, демонстрирующих своевременность консолидации практик модернизации ПО и стандартизации в этой области [12]: Современная экономика требует от организаций более эффективного использования доступных ресурсов, включая повторное использование существующих программных ресурсов. Неагрессивные проекты интеграции достигли пределов своей способности приносить экономическую выгоду. "Закон выживания" главной инфраструктуры и разработчиков инструментов; унификация связующего ПО (middleware) и оборудования порождает интерес к портированию на новые платформы. Повсеместное принятие UML и MDA, обеспечивающее методологию, равно как и цель для модернизационных проектов. Развитие технологий анализа и повторного использования унаследованного ПО и выполнения трансформаций унаследованного ПО; критическая масса индивидуальных решений разработчиков ПО. Разрыв между технологиями и методологиями в индустрии, что требует от успешных разработчиков программных продуктов возвращаться и повторно исследовать существующие решения и практики (эволюция программных систем, вырастающих из первоначальных прототипов и слияний/поглощений). Требование к интероперабельности промышленного ПО. Существующие системы, которые в процессе эволюции приобрели противоречивую или сложную архитектуру, и чья модификация требует трудоемкого ручного кодирования, могут существенно затруднить подвижность организации. Компании, вынужденные противостоять слияниям и поглощениям, учитывать появление новых продуктов, изменение требований рынка, правительственное регулирование и другие бизнес-факторы, нуждаются в гибких инфраструктурах ПО для того, чтобы конкурировать или даже просто выжить. Модернизация может помочь удовлетворить эти бизнестребования быстрее, за меньшую стоимость, и с лучшим качеством. Для большого числа организаций необходимость модернизации своих промышленных информационных систем обычно побуждается определенными внешними событиями. Такими, как необходимость обеспечить Web-доступ к существующему приложению, или необходимость отказаться от неподдерживаемой платформы. Для компаний, выпускающих зависящие от технологии 233
или продукты, в которых программное обеспечение является важной частью, эволюция существующего кода является жизненной частью ежедневных бизнес-требований. ADM обеспечивает средства, направленные на удовлетворение этих требований, используя систематические и мало-рискованные подходы. При помощи анализа, категоризации и управления ресурсами существующего ПО, бизнес может продлить полезность функциональности существующего ПО и максимизировать эффективность инвестиций в разработку ПО.
4. RFP по метамодели обнаружения знаний (KDM – Knowledge Discovery Model) Первая из спецификаций в серии Архитектурно-управляемая модернизация (Architecture-Driven Modernization или ADM) позволит пользователям начать проекты по модернизации их программного обеспечения, обеспечив их уверенность в интероперабельности программных инструментов различных поставщиков [13]. RFP по KDM учитывает существование спецификаций OMG, которые связаны с ADM. Предложения по этому RFP должны задействовать эти спецификации или обосновать их неадекватность. Поощряется использование и расширение существующих OMG стандартов сторонами, отвечающими на этот RFP, с тем, чтобы сделать эти стандарты более подходящими для проблемной области, в которой действует ADM. RFP по KDM запрашивает предложения по метамодели для представления информации о существующих программных ресурсах и их операционной среде (в дальнейшем она именуется «обнаружением знаний» - «knowledge discovery»). Одной из общих черт различных инструментов, отвечающих на вопросы, которые ставит ADM, является то, что они анализируют существующие программные ресурсы (например, исходный код модулей, описание баз данных, сценарии сборки, и т.д.) с целью обнаружения знаний о системе. Каждый из этих инструментов извлекает порцию знаний о существующих ресурсах ПО. Подобные знания, зависящие от конкретного инструмента, могут быть неявными («зашитыми» в самом инструменте), ограниченными некоторым языком программирования, некоторым видом преобразования и/или операционной средой. Все это может стать помехой обеспечения интеропера-бельности этих инструментов. Метамодель обнаружения знаний обеспечит общую структуру репозитария, которая облегчит обмен данными, хранимых внутри моделей отдельных инструментов и представляющих ресурсы существующего ПО. Метамодель будет описывать физические и логические ресурсы на различных уровнях абстракции. Основной задачей, решаемой метамоделью является продвижение общего формата обмена, который обеспечит интероперабельность между различными инструментами модернизации ПО, службами и соответствующими моделями. 234
4.1. Выгода, приносимая интероперабельностью Существует развитая отрасль поставки программных инструментов и услуг, которая обуславливает востребованность ADM . Существует потребность в стандартизации, которая обеспечит возможность интеграции и интероперабельности решений от различных поставщиков решений, основанных на ADM. Стандартизация увеличит интероперабельность между различными программными инструментами путем создания открытого каркаса для подобных инструментов (framework). Это может привести к появлению нового поколения решений, от чего выиграет вся индустрия в целом [12]. ADM стандарты позволят пользователям начать процесс модернизации их программных проектов, гарантируя интероперабельность решений от различных поставщиков программных инструментов. Таким образом, стандартизация будет гарантировать конечным пользователям, что они вкладывают деньги не в отдельный инструмент, а, скорее, в некоторую выбранную стратегию.
4.2. Итоговые выгоды от стандартизации Стандартизация метамодели ADM поможет как всей индустрии в целом, так и отдельным компаниям путем сокращения рисков, возникающих при принятии инициатив по улучшению программного обеспечения. Возможность разделять информацию между различными проектами, в которых используются различные инструменты и процессы, сократит время, риски и цену преобразования программного обеспечения. В свою очередь, это улучшит качество инструментов поддержки обратной инженерии и ADM инструментов, обеспечит появление новых возможностей и увеличит возврат от капиталовложений (ROI – Return Of Investment) для инструментов разработки программного обеспечения.
4.3. Область поиска предложений Своим первым RFP по архитектурно-управляемой модернизации SIG запрашивает предложения по метамодели обнаружения знаний, призванной обеспечить обмен информацией, связанной с трансформацией существующих ресурсов программного обеспечения и их операционных сред [13]. KDM представляет структуру существующего программного обеспечения и связанных с этой структурой артефактов. Такая метамодель обеспечит возможность документирования существующих систем, выявления компонентов, годных для повторного использования в существующем ПО, обеспечит поддержку портирования ПО на другие языки и на MDA, и сделает потенциально возможными другие преобразования. Метамодель также позволит обмениваться информацией об артефактах существующего программного обеспечения между различными инструментами. Это позволит поставщикам решений, специализирующимся на 235
определенных языках, платформах или типах трансформаций поставлять потребителям решения, сочетающиеся с решениями других производителей.
4.4. Аспекты обнаружения знаний Существуют по меньшей мере четыре аспекта знаний, обнаруживаемых в рамках ADM процесса: Реализация Дизайн Архитектура Бизнес-правила В метамодели важно представить все основные артефакты существующего ПО, которые, в общем виде, могут быть описаны как сущности (структурные элементы), отношения между ними, и атрибуты. Метамодель должна быть достаточно общей, с тем, чтобы она могла обеспечивать все описанные выше уровни трансформации. Метамодель не должна быть ограничена ни одним из языков реализации или платформой. Это утверждение особенно важно для аспектов, связанных с существующими знаниями, относящихся к языковому уровню. Особенно важно, чтобы метамодель могла описывать поведенческие артефакты вплоть до процедурного уровня, но не ниже его. В качестве примера процедуры можно привести параграф в языке COBOL или метод в языке Java. Обоснованием этого ограничения области описанного выше RFP является тот факт, что сущности и их отношения ниже процедурного уровня зачастую чересчур тесно связаны с языком и нижележащей платформой. К сущностям языкового уровня относятся, например, методы, файлы с исходным кодом, классы, элементы данных, записи, таблицы или транзакции. В качестве отношений на языковом уровне могут выступать, например, связи вида “функция использует переменную”, “класс является наследником другого класса”, или “к файлу подключен заголовочный файл”. К атрибутам языкового уровня относятся, например, такие атрибуты как имя, права доступа, версия, язык, последнее время просмотра, или тип отношения. Аспекты дизайна системы могут широко варьироваться в зависимости от принятого методологического подхода. В общем случае информация о дизайне может включать в себя дизайн структур данных, системный дизайн, дизайн интерфейсов и программный дизайн. При этом, к аспектам, поддающимся обнаружению относятся, например, избыточность, сцепление (cohesion), удобство и простота использования, доступность (accessibility), производительность и фрагментация. KDM должен облегчать процесс обнаружения подобных аспектов. Архитектурные аспекты особенно важны для ADM. На архитектурном уровне существуют несколько различных типов структур: 236
Физические структуры (например, файлы, директории, отношения между файлами, связи времени сборки ПО, и т.д.) Логические структуры (например, подсистемы, модули, уровни системы, компоненты и их зависимости, различные архитектурные представления и т.д.) Те физические структуры, которые связаны с процессом сборки существующего ПО, зачастую имеют существенную роль в ADM проектах. К архитектурным сущностям относятся, например, модули, подсистемы, архитектурные уровни, компоненты или библиотеки. Архитектурные отношения включают в себя, например, отношения вида “файл содержится в директории”, “компонент предоставляет метод”, “компонент использует интерфейс другого компонента”, и т. д. К архитектурным атрибутам можно отнести, например, имя компонента. Для обеспечения применимости ADM на архитектурной основе, KDM должна быть способна описывать как физические, так и логические структуры. Метамодель должна обеспечивать возможность связывать элементы логической структуры с элементами физической структуры и, также, со структурами языкового уровня. Рассматривая бизнес-правила, следует отметить, что знания о функциях, выполняемых в системе, должны быть представимы в KDM. Сущность, содержащаяся в бизнес-правилах, дает функциональное описание лишь некоторого фрагмента системы, которое может быть дополнено системным аналитиком. Отношение, идущее от заданного бизнес-правила может вести к одному или более физическому аспекту системы. На уровне бизнес-правил KDM не должен быть привязан ни к одной из специфических проблемных областей. Для совмещения всех этих аспектов ADM, метамодель должна быть создана таким образом, чтобы облегчить ее использование, как в автоматических, так и ручных способах и средствах анализа. Далее в этой статье описываются проведенные исследования в области архитектурно-ориентированного обнаружения знаний и переработки существующего кода (рефакторинга), выполненные в интересах нашего «производственного» партнера – компании Klocwork.
для управления архитектурой существующего ПО, для анализа проблем в текущей архитектуре и для планирования и коор-динации оптимизационных инициатив. Данный подход чрезвычайно полезен, когда информация об архитектуре ПО устарела, отсутствует или неточна. Мы предлагаем концепцию «моделей с объединенными интерфейсами», являющуюся масштабируемой, поддерживающую точность интерфейсов компонент и сохраняющую связь с существующим кодом ПО. Подробнее об использовании моделей с объединенными интерфейсами рассказывается в работе [8] метод архитектурных раскопок компании Klocwork. В основе моделей с объединенными интерфейсами лежат компоненты и их интерфейсы. Так как компоненты могут состоять из подкомпонентов, модели с объединенными интерфейсами допускают неограниченное масштабирование. Модели с объединенными интерфейсами допускают трансформацию компонент (путем переноса символов между компонентами), по ходу трансформации сохраняется точность интерфейсов между компонентами. Это означает, что при появлении абстрактных компонент, объединяющих подкомпоненты, интерфейсы между компонентами остаются точными. Модель направляет процесс раскопки [7, 8].
5. Архитектуро-ориентированная методика раскопки знаний компании Klocwork В этой части описывается систематический процесс создания высокоуровневых архитектурно-значимых компонентных моделей существующего программного обеспечения – так называемый метод архитектурных раскопок Klocwork [7, 8]. Цель этого метода – создание формальной модели архитектуры сущес-твующего ПО, достаточно высокого уровня как для проведения анализа, так и для ее передачи команде разработчиков. Отсюда следует, что такая модель также может использоваться 237
Изначальная модель автоматически извлекается из исходного кода. Затем модель редактируется вручную, серией трансформаций, повышающих уровень абстракции компонентов и удаляющих случайные зависимости между компонентами. В процессе трансформации сохраняются точность информации, извлеченной из исходного кода. Отсюда, на каждом шаге трансформации, модели с объединенными интерфейсами точны по отношению к реализации. 238
Результирующая модель может быть использована для анализа и управления разработкой. В основе моделей с объединенными интерфейсами лежат UML диаграммы пакетов и объектов [3]. Пакетная модель представляет собой высокоуровневые “модули” и зависимости между ними. Модель иерархична, что также находит отражение в одном из представлений модели. В основании иерархии пакетов лежат файлы. Далее, файлы содержат части диаграмм объектов, состоящих из символов, как для классов, так и для отдельных процедур, переменных, типов. Зависимости между пакетами (модулями существующего ПО) в Klocworkдиаграммах являются производными от отношений между отдельными символами (элементарными языково-зависимыми сущностями исходного кода, такими как типы, процедуры, переменные, макросы и т.п.) Когда же одна группа сущностей (например, классов, файлов, директорий и т.д.), группируется и объединяется в один пакет, а другая группа – в другой пакет, то отношения между отдельными символами двух пакетов прибавляются к зависимостям между этими пакетами. Это означает, что любая диаграмма пакетов в точности отображает интерфейсы пакетов. Подробнее интерфейсы между пакетами можно изучить, путешествуя по зависимостям между паке-тами и просматривая списки отдельных составляющих зависимостей, или, даже, получить полный список отношений между символами-составляющими пакетов. Каждое отношение связывается с определенным положением в исходном коде. От любой высокоуровневой диаграммы пакетов возможно спуститься на уровень исходного кода, например посмотреть, откуда берется то или иное отношение. Пакет инструментов Klocwork использует блок-схемы для представления исходного кода, независимо от того, на каком языке написан код программы. Архитектурные раскопки осуществляются применением к моделям c объединенным интерфейсом одной из двух основных операций: объединение и рефакторинг. Объединение – визуальная операция, в ходе которой несколько выбранных блоков группируются в новый пакет, располагающийся на уровень выше в иерархии пакетов. В модели автоматически пересчитываются зависимости между пакетами на всех уровнях. Тем не менее, агрегация сама по себе не обеспечивает увеличения уровня абстракции диаграмм архитектуры, если она не поддерживается операцией обрамления. Рефакторинг – визуальная операция, позволяющая переносить блоки между пакетами. Обычно мы переносим отдельные символы с одной низкоуровневой диаграммы объектов из одного модуля в другой. Это означает, что рефакторинг включает в себя “виртуальное” редактирование файлов (конечно же, редактируется только соответствующая часть модели). Рефакторинг позволяет удалить зависимости между высокоуровневыми компонентами, вызванные случайным размещением функциональности на уровне файла. Это 239
происходит слишком часто, когда физическая архитектура программного обеспечения не соблюдается должным образом. В ходе архитектурных раскопок изначальная модель ПО подвергается значительным трансформациям. Таким образом, между архитектурными раскопками, анализом и оптимизацией архитектуры нельзя провести четкой границы. Обычно раскопка архитектуры имеет дело с небольшими случайными проблемами, затрудняющими понимание «настоящей» архитектуры и, следовательно, затрудняющими выявление «настоящих» проблем из-за чрезмерной сложности сырых (необработанных) данных. Архитектурные раскопки в большой степени включают в себя собственно понимание исследуемой программной системы (включая экспертизу предметной области, общее знание о программном обеспечении и здравый смысл) с целью выбрать группу символов для объединения и для рефакторинга. Дополнительные представления модели могут облегчить понимание этих проблем. Дополнительные представления позволяют временно уменьшить сложность, и, следовательно, «разморозить» процесс Архитектурных раскопок. Дополнительное представление модели позволяет обозреть набор объектов, включенных в некоторое первоначальное представление. Как правило, это обеспечивает достаточное понимание архитектурных абстракций. Часть представления может быть эффективно извлечена и, в последствии, применена в более сложном контексте.
6. Архитектурная переработка существующего кода klocwork Эволюция существующего кода - неотъемлемая часть бизнеса компаний, предоставляющих высокотехнологические программные продукты. Компании, разрабатывающие программные решения, часто модернизируют свои продукты. Модернизация может быть вызвана следующими факторами: Добавление новой или изменение существующей функциональности; Улучшение использования ценных частей программного кода путем усиления модульности, особенно при существовании группы программных продуктов (Software Product Line - SPL); Миграция к стандартным COTS-компонентам (компонентам готовым к использованию); Изменение или обновление платформы; Модернизация технологии разработки; Улучшение устойчивости программного продукта; Реорганизация компании, привлечение внешних ресурсов для разработки проекта. Для поддержки модернизации необходимы эффективные методы компонентизации существующего программного кода – выделение существующих 240
компонентов с постепенным определением их границ и интерфейсов. В данной статье описан подход к компонентизации, основанный на применении высокоуровневых моделей существующего кода, сохраняющих, тем не менее, точность по отношению к этому программному коду. Повышение уровня абстракции модели существующего кода – это основной подход, используемый для донесения «вычищенной» архитектуры до команд разработчиков, а также для анализа, оптимизации и управления архитектурой программного продукта. Основные усилия в исследовании и разработке направлены на увеличение скорости разработки и предоставлению конечному пользователю новых систем. С другой стороны, развитию существующих программных средств уделяется значительно меньше внимания. Развитие существующих программных средств затрагивает разработку новых возможностей, равно как и изменение существующего исходного кода (legacy code). Разработка новой возможности существующей программной системы может быть значительно сложнее разработки эквивалентной системы «с нуля», поскольку все решения прямой инженерии ограничены решениями, реализованными в существующем коде. Для выживания в условиях усиления давления рынка, организациям, которые занимаются разработкой программного обеспечения, необходимо, рано или поздно, уменьшать стоимость обновления программных средств. Типичный сценарий для телекоммуникационных проектов (а также большинства проектов систем реального времени): только ядро (основная часть) системы появилась как реализация новых идей, и затем, в процессе быстрого накопления опыта, а также по мере появления инвестиций в проект, система разрасталась хаотически. Качество базовой инфраструктуры, как правило, приносится в жертву активному добавлению новых возможностей системы для удовлет-ворения рыночных запросов. Начальная структура программного средства распадается, и добавление новых возможностей становится все более сложным. Проблемы поддержки необходимого уровня качества начинают расти. Объединения и приобретения могут еще больше усугубить ситуацию. Все вышеперечисленные проблемы создают дополнительные трудности для улучшения инфраструктуры программного средства, которое может быть описано как компонентизация существующего программного средства. Эти мероприятия представляют собой архитектурную переработку существующего кода. Компонентизация также является архитектурной активностью, которая определяет и улучшает модульность программного средства. Для улучшения модульности существующего программного средства следует произвести следующие действия: выделить компоненты, определить границы будущих компонентов путем агрегации подкомпонентов, представить новый компонент одним графическим символом и 241
исследовать интерфейсы между компонентами для определения проблем модульности, изменить компоненты добавлением или удалением содержимого, по мере того как появляются лучшие модули, более продвинутые архитектурные механизмы могут быть использованы для более четкого определения границ модулей и определения межмодульных интерфейсов. Инструменты, автоматизирующие процесс компонентизации, требуют точной информации о взаимосвязях между компонентами. В настоящий момент существует большое количество так называемых инструментов обратной инженерии, извлекающих подобную информацию из существующего исходного кода. Однако существующие инструменты обратной инженерии не могут решить проблему компонентизации. По нашему мнению, это происходит из-за недостаточности высокоуровневого представления существующего кода, получаемого при помощи традиционных инструментов. Другими словами, существующие инструменты обратной инженерии извлекают информацию об индивидуальных взаимосвязях между элементами существующего програм-много средства, а не работают в терминах модульных интерфейсов. Основной целью исследований и разработок, проводимых отделом CASEинструментов для klocwork, является уменьшение последствий вышеописанной проблемы. Наш подход к развитию существующего программного кода основан на, так называемой, методологии архитектурных раскопок [2].
7. Управляемые архитектуры В этой части статьи мы обсудим, как архиеткурно-ориентированное обнаружение знаний о ПО (архитектурные раскопки) и архитектурная переработка могут существенно улучшить возможности различных организаций по разработке программных систем. Мы продемонстрируем, как использование архитектурных инструментов может облегчить переход от управления реализацией к управлению архитектурой [10]. Что такое управляемая архитектура программного средства? Мы будем использовать следующее определение, основанное на широко известной модели SEI CMM. В действительности, это проекция модели SEI CMM в домен архитектурных моделей, так называемой Architecture Capability Maturity Model (ACMM). ACMM покрывает единственный аспект SEI CMM – архитектуру существующего программного кода. Уровень 1: Начальная архитектура Любое программное средство имеет некоторую структуру – вне зависимости от того, определена она или нет, понятна она (разработчикам) или нет. Она состоит из некоторых компонентов (может быть из одного монолитного компонента), у компонентов есть некоторые зависимости, компоненты объединяются в конфигурации. 242
Уровень 2: Повторяемая архитектура Часто организации используют повторяемые шаблоны конструирования и поставки программных систем: некоторые правила компоновки, использование некоторых библиотек, повторное использование кода. Обычно шаблоны появляются на физическом уровне. Любая организация, обладающая большим количеством программных ресурсов, включая вариации (любое встроенное программное обеспечение), начинает интересоваться вопросами архитектуры программных средств, с момента попытки определения составляющих успеха группы программных продуктов. Существуют и другие мотивы, побуждающие организации уделять больше внимания качеству архитектуры их программных продуктов и начать работы по ее оптимизации. Уровень 3: Определенная архитектура На этом уровне компоненты, их интерфейсы и конфигурации формально определены и поддерживаются вместе с остальным кодом. При этом используется компонентное окружение, средства моделирования вроде Rational Rose. Существует несколько различных сценариев перехода организаций на этот уровень. Некоторые начинают «с чистого листа», и определяют архитектуру до начала разработки. Другие делают это позже, когда линейка программных продуктов становится достаточно конкурентоспособной. Как бы то ни было, определение архитектуры программного средства является первым шагом к настоящему управлению программным средством, с точки зрения архитектуры. Уровень 4: Управляемая архитектура Архитектура программы становится управляемой, когда организация получает своевременную, точную и количественную информацию о компонентах, а также их зависимостях и конфигурациях. Для достижения этого уровня требуется: визуализация существующего программного кода; обратная связь между «разработанной» архитектурой и «построенной» архитектурой; использование метрик существующей архитектуры. Организации, получающие эту информацию, используют ее для увеличения целостности архитектуры их программных продуктов. Уровень 5: Оптимизирующая архитектура Архитектурная целостность усилена и улучшена. Действия по улучшению архитектуры становятся неотъемлемой частью общего процесса разработки. Есть существенное различие между Определенными Архитектурами и Управляемыми Архитектурами с точки зрения используемых программных систем. На уровне Определенной Архитектуры используются автоматизированные средства моделирования. На уровне Управляемых Архитектур 243
используются инструменты, обычно относящиеся к инструментам обратной инженерии или инструментам обеспечения качества ПО. Одна из крупнейших проблем – расширить средства моделирования для применения их во всех ситуациях, встречающихся в существующих программных ресурсах. Типичная роль ответственного за архитектуру скорее реактивная: сначала формулируются некоторые требования, затем они передаются разработчикам для реализации, и затем оцениваются результаты. Обычно, цикл конструирования является наиболее длинным, поэтому, когда проблемы выявляются – уже слишком поздно. В таких случаях устранить обнаруженные дефекты, не нарушая архитектурную целостность системы, практически невозможно. В связи с этим мы часто говорим об эрозии или распаде архитектуры – процессе деградации межкомпонентных зависимостей с течением времени, когда ответственный за архитектуру теряет контроль над ситуацией. Средства автоматизации управления архитектурой программного обеспечения сокращают цикл оценки результатов. Однако упреждающий подход к управлению архитектурой программной системы должен интегрировать действия по усилению целостности архитектуры в сам процесс разработки. Например, определенные «архитектурные правила» должны проверяться «на лету», когда разработчик пытается обновить некоторый модуль в системе управления конфигурацией. Цель инструментальной поддержки существующего ПО в ускорении разработки программной системы, использующей существующий программный код. Klocwork inSight использует современные, запатентованные алгоритмы анализа программного кода для выделения программной архитектуры, взаимодействия компонентов, логических последовательностей и исполняемых потоков непосредственно из исходного кода как системы целиком, так и ее частей [1]. Средства Klocwork позволяют анализировать, автоматически контролировать и управлять архитектурой при помощи графической визуализации, задания архитектурных правил и автоматического слежения за ними. Средства Klocwork также включают инструмент для поиска логических ошибок «на лету» для их раннего обнаружения и удаления. Посредством интуитивного, дружественного интерфейса, они быстро и точно снабжают архитекторов и проектировщиков уникальной, востребованной, ранее не доступной информацией, что уменьшает временной цикл разработки и улучшает качество ПО. Klocwork также имеет инновационные и автоматизированные решения для оценки программного обеспечения, с возможностью составления отчета по системе в целом, или отдельным ее частям, со 100% точностью.
8. Архитектурно-ориентированный переход к MDA Поддержка существующего ПО – только один аспект более широкого понятия эволюции программного обеспечения. Инфраструктура современных промыш244
ленных вычислительных систем быстро изменяется [18]. Это означает, что развитие программного обеспечения не должно отставать от этих изменений, что, в свою очередь, требует реструктуризации большей, чем просто разбиение на модули. Становится очевидным, что исходный код не всегда подходит для поддержки и эволюции, поскольку он обладает как платформо-независимыми, так и специфичными для некоторой платформы свойствами. Подход, основанный на модельно-управляемой архитектуре (MDA), который в настоящее время стандартизован OMG (http://www.omg.org/mda), может быть рассмотрен как применение принципа управляемой архитектуры программ (Managed Software Architectures) для новых (green field) проектов, созданных прямым моделированием с использованием UML, где модель является основным поддерживаемым артефактом. Ключевое понятие MDA – переход от поддержки кода к моделированию. MDA также выступает за разделение платформо-независимых и платформозависимых моделей (PIM, PSM). Реализация для выбранной платформы получается из PIM через PSM с использованием автоматической генерации кода. Это очень перспективный подход. Однако, при переходе от существующего кода к MDA возникает проблема унаследованного кода, так как требуется “раскопка” (excavation) PIM из существующего кода. Мы полагаем, что наши обобщенные интерфейсные модели (summary interface models), которые поддерживают неограниченную агрегацию, рефакторинг и связи с исходным кодом, делают возможным создание архитектурно значимых моделей существующего ПО, которые могут быть постепенно переработаны в PIM для существующих модулей. Таким образом, становится возможной интеграция существующих модулей в ориентированный на MDA процесс разработки ПО. Обобщенные модели хорошо соотносятся с моделями, используемыми в процессе прямой инженерии, поэтому они позволяют преодолеть проблему унаследованного кода для лучшего внедрения современных технологий разработки программных средств в промышленности. Рисунок, приведенный ниже, иллюстрирует архитектурно-ориентированный процесс миграции в направлении MDA. На левой части рисунка приведены трансформации, входящие в MDA (переход от PIM к PSM, и от PSM к коду). Эти трансформации предполагают наличие детальной исполняемой модели. Проблема интеграции существующих программных систем в “мир MDA” заключается в том, что такая модель обычно отсутствует, и должна быть восстановлена с наименьшими трудозатратами. По нашему мнению, “прямой подход” перехода от исходного кода к PIM трудно реализовать по причине сложности артефактов существующего программного обеспечения. Вместо этого, мы выступаем за следующий архитектурно-ориентированный подход. 245
PIC PSC
Во-первых, переход к управляемой архитектуре производится с помощью раскопки (excavating) обобщенной интерфейсной модели (summary interface model, SIM) существующего кода. Как было показано ранее, этот переход обычно включает некоторый рефакторинг архитектуры с целью восстановления интеллектуального контроля над “распадающейся” архитектурой. Во-вторых, из обобщенной интерфейсной модели в дальнейшем выделяются две части: платформо-независимые компоненты (Platform-Independent Components, PIC) и платформо-зависимые компоненты (Platform-Specific Components, PSC). В-третьих, модель компонентных интерфейсов, соответствующая PIC, может быть получена и экспортирована в инструментарий MDA. Дальнейшая разработка на основе существующего кода может увеличить детализацию модели. Таким образом, архитектурно-ориентированная модель существующего программного обеспечения может быть интегрирована в модель MDA. Конечно, эта архитектурно-ориентированная модель не полностью поддерживает MDA, поскольку в ней содержатся только ссылки на интересующие компоненты и их интерфейсы, но не их поведение. Существующие компоненты все еще необходимо интегрировать с новыми компонентами, созданными с помощью средств MDA. Преимущество этого подхода заключается в том, что целостность модели может быть усилена при использовании инструментов, описанных выше.
9. Заключение Мы обобщаем наш опыт в определении стандартов архитектурно-управляемой модернизации в Object Management Group (OMG) с помощью нашего партнера Klocwork. В частности, мы описали нашу методологию архитектурно-ориентированного обнаружения и рефакторинга знаний. Применение этого подхода организацией-разработчиком программного обеспечения может привести к 246
увеличению производительности за счет облегчения перехода от управления реализацией (существующим кодом) к управлению архитектурой ПО. Мы считаем это существенным шагом для увеличения пригодности ПО к модернизации с использованием MDA, SOA (service-oriented architecture) или еще какой-нибудь архитектурно-управляемой модернизации. Мы обозначили миграционный процесс, в котором архитектура становится управляемой, а целостность архитектуры усиливается, чтобы затем сделать возможным создание моделей интерфейсов компонентов (component interface models, CIM) и их интеграцию с новым процессом разработки, поддерживающим MDA. Литература: 1. N. Rajala, D. Campara, N. Mansurov, inSight Reverse Engineering CASE Tool, in Proc. of the ICSE 99, Los Angeles, USA, 1998. 2. Н. Мансуров, А. Рагозин, Генерация кода с простой и читабельной структурой по SDL-92, Вопросы кибернетики: System Programming Applications, N. 3, Москва, 1997 (in Russian) 3. N. Mansurov, A.Ragozin, Using declarative mappings for automatic code generation from SDL and ASN.1, in Proc. 9th SDL Forum, Montreal, Canada, June 21- 26, 1999, Elsevier Science Publishers B.V. (North-Holland). 4. R. Probert, N. Mansurov, Improving time-to-market using SDL tools and techniques (tutorial), Proc. 9th SDL Forum, Montreal, Canada, June 21-26, 1999. 5. J. Rumbaugh, I. Jacobson, G. Booch, The Unified Modelling Language Reference Manual, Addison-Wesley, 1999 6. A. Ragozin, Automatic generation and execution of programs from SDL specifications, PhD thesis, Moscow State University, 1999 7. N. Mansurov, A Systematic Approach to Recovering Architecture from Existing Software, SD Expo West, San Jose, 25th April, 2002 8. N. Mansurov, D. Campara, Extracting High-Level Architecture From Existing Code with Summary Models, in Proc. IASTED Conf. On Applied Informatics, Innsbruck, Austria, 2003 9. N. Mansurov, D. Campara, Using Message Sequence Charts to accelerate maintenance of existing systems, in Proc. 10th SDL Forum, Copenhagen, 2001, LNCS, Springer Verlag, 2001 10. N. Mansurov , Using Metrics to enforce quality of Managed Architectures , in industrial presentations proc. of int. Conf. Metrics-2002, Ottawa, Canada, 2002 11. OMG, Legacy Transformation Working Group Forms, Draws Number of New OMG Members, OMG press release, July 2003 12. OMG, Why do we need legacy transformation standards?, OMG whitepaper, 2003 13. OMG Architecture-Driven Modernization: Knowledge Discovery Meta-model RFP, 2003 14. D. Frankel, et. al. OMG Model-Driven Architecture, Addison-Wesley, 2003 15. A.van Deursen, P. Klint, C. Verhoef, Research issues in the Renovation of Legacy Systems, CWI reseaarch report P9902, April 1999
247
Покрытие графов циклами и быстрое восстановление оптоволоконных сетей* Н.Н. Кузюрин, С.А.Фомин Аннотация. В данной статье мы рассматриваем технологию защиты сетей с помощью циклов (P-cycle technology), основанную на нахождении замкнутых путей (п-циклов) в топологиях оптоволоконных сетей. Задача нахождения оптимального набора п-циклов может быть сформулирована как задача целочисленного линейного программирования (ЦЛП), в которой переменные соответствуют циклам оптимизируемой сети. Стандартный подход заключается в использовании алгоритмов целочисленного линейного программирования, но проблема заключается в очень большом, зачастую экспоненциальном (от размера сети) числе переменных (циклов). Мы предлагаем гибкий подход для генерации выделенного набора циклов, если множество всех циклов велико. Выделенный набор циклов имеет ограниченный размер и включает наряду с короткими циклами некоторое количество длинных циклов, полученных с помощью простых эвристических алгоритмов на графах и их случайных локальных преобразованиях. Представлена реализация и результаты тестирования для нового эффективного алгоритма генерации циклов в планарном графе. Предложены алгоритмы целочисленного линейного программирования, основанные на быстром извлечении относительно небольшого набора “важных” переменных, с помощью приближенного или вероятностного решения линейной релаксации исходной задачи ЦЛП. Разработана программная система «RingOptimizer», предназначенная для моделирования и решения этих задач. Проведенное тестирование показало эффективность предложенных алгоритмов.
1. Введение Сетевая надежность является важным понятием для потребителей и поставщиков телекоммуникационных услуг. С ростом пропускной способности сетей растет, с одной стороны, их использование в промышленности и обществе, с другой, возрастает ущерб при непредвиденных неисправностях, т.к. для больших оптоволоконных сетей протяженностью в сотни километров обрывы кабеля случаются на удивление часто. Тем самым разработка методов быстрого восстановления работоспособности сети при обрывах кабеля является важной проблемой проектирования оптоволоконных сетей. Наиболее распространенной архитектурой, обеспечивающей быстрое (<50мс) восстановление работоспособности сети с помощью простого механизма пере*
ключения направления потока, является кольцевая, так называемая BLSRархитектура (Bidirectional Line Switched Rings). В этом случае время восстановления в 50 миллисекунд достигается простым механизмом, переключающим поток в обратную сторону в случае обрыва. Ее недостатком является необходимость 100% резервирования пропускной способности сети, что существенно выше, чем в обычных сетях ячеистой структуры, где надежность обеспечивается динамической маршрутизацией. Сети ячеистой структуры могут иметь в два или три раза более эффективное использование резервной пропускной способности, но, к сожалению, как в случае динамической маршрутизации, так и в случае централизованного управления трафиком, невозможно обеспечить быстрое время восстановления (<50мс), что зачастую необходимо многим видам трафика, не допускающим задержек или прерываний, например, телевизионным трансляциям. Таким образом, долгие годы ситуация оставалась неизменной: кольца были простым механизмом обеспечивающим быстрое восстановление, но неэкономным по отношению к пропускной способности. Ячеистые сети существенно более экономны по пропускной способности, но неизбежно имеют долгое время восстановления. Таким образом, было необходимо добиться для ячеистых сетей 50мс времени восстановления без существенной потери эффективного использования пропускной способности. Известный подход, решающий данную задачу заключается в использовании заранее вычисленного расположения циклов (pre-configured cycles) в сетевом графе [3]. Чтобы обеспечить быстрое восстановление сети, в рамках данного подхода необходимо на этапе проектирования найти множество S виртуальных колец (циклов) в сетевом графе, которые и обеспечат замкнутые кольцевые пути, используемые для восстановления. Для обеспечения 100% восстанавливаемости сети, такой набор циклов должен “покрывать” каждое ребро в графе, вернее для каждого ребра e в графе должен быть цикл из множества S, на котором бы лежали и начальная и конечная вершина данного ребра e. В случае обрыва кабеля на некотором ребре e, поток в его начальных и конечных вершинах переключается на использование ребер из “покрывающего” цикла. Более подробная постановка задачи оптимизации также учитывает стоимость и пропускную способность цикла (см. Раздел 2). Известно, что задача нахождения самой экономной сети, основанная на этом подходе весьма сложна [3, 4]. В этой статье мы представим метод для эффективного решения оптимизационных задач типа упомянутой. Структура статьи такова. В разделе 2 мы даем постановку задачи. В разделе 3 мы описываем два основных подхода к ее решению и указываем на их недостатки. В разделе 4 мы описываем наш подход, содержащий преимущества описанных подходов, но избегающий их недостатков. В разделах 5, 6 мы описываем детали некоторых алгоритмов, используемых в нашем подходе. Результаты вычислительных экспериментов представлены в разделах 7, 8.
Работа выполнена при поддержке РФФИ, проект 02-01-00713.
249
250
2. Постановка задачи. Существуют различные постановки задачи проектирования самовосстанавливаемой сети, (survivable network design) основанной на кольцевом покрытии. В нашей работе мы считаем, что задана топология физической сети в виде графа и матрица использования трафика между узлами (вершинами графа) также известна. Этим подразумевается, что задача маршрутизации в сети уже решена, и мы знаем требуемую пропускную способность для каждого отрезка сети ребра графа.
2.1. Обобщенная постановка задачи проектирования сети с кольцевой защитой. Дано. Сетевая топология в виде графа G=(V,E) с заданной функцией требуемой пропускной способности w: ER+ которая каждому ребру e=(u,v)E графа G сопоставляет неотрицательное значение требуемого трафика. Пусть C будет множеством простых циклов в G. Пусть R будет множеством возможных колец основанном на множестве С. То есть каждому циклу c из С мы можем сопоставить множество колец, лежащих на данном цикле, но с разными пропускными способностями и различными стоимостями (далее в этом разделе мы будем использовать r и с для перечисления колец и циклов соответственно). Пусть mr будет пропускной способностью, а pr будет фиксированной стоимостью r-ого кольца. Для каждого ребра e=(u,v) пусть R(e)R будет множеством колец, которые содержат обе вершины u и v. Найти. Мультимножество колец R*, в котором для каждого ребра e множество соответствующих колец R*(e) имеет суммарную пропускную способность (равную r R*(e)mr ) не меньшую we. При этом необходимо минимизировать суммарную стоимость колец из R* (равную r R* pr). Теперь переформулируем эту задачу в терминах целочисленного линейного программирования (ЦЛП).
e r
min r R prXr r R*(e)mrXr we Xr 0
(1)
где Xr представляет собой выбранное для покрытия число колец типа r. В этой целочисленной программе переменные Xr соответствуют кольцам, а ограничения ребрам сети G. Таким образом, решение X это вектор размерности |R|, причем его r-тый элемент указывает, сколько раз r-тое кольцо входит в решение. В частности, если Xr=0, то r-тое кольцо не входит в решение.
3. Предшествующая работа: два основных подхода. Мы исследовали и сравнили два основных метода для поиска решения задачи, сформулированной в предыдущем разделе. В первом случае, формулируется 251
целочисленная линейная программа (1), где переменные соответствуют всем возможным циклам в сети и далее используются стандартные алгоритмы и программные пакеты (например, CPLEX) целочисленного линейного программирования для решения этой задачи. Другой подход заключается в использовании эвристических алгоритмов нахождения требуемых циклов непосредственно в заданной сети [3, 4]. Эти алгоритмы обычно очень быстрые, но не могут обеспечить оптимизации хорошего качества. Теперь еще раз об этих подходах более подробно. Первый подход состоит из следующих шагов: 1. Генерация максимально возможного, в рамках имеющихся вычислительных ресурсов набора циклов и соответствующих возможных колец. Однако, так как число простых циклов даже в планарном графе может расти экспоненциально с ростом размера сети (выраженном в количестве вершин или ребер), то используются различные эвристики для ограничения этого набора. Обычно вводится ограничение на длину цикла (hop limit) выраженную в количестве вершин (или ребер, что, то же самое) в цикле. Однако множество циклов и возможных колец остается весьма большим. 2. Решение целочисленной линейной программы (1) с использованием специализированного программного обеспечения, например CPLEX. Заметим, что число переменных в задаче (1) существенно превышает число ограничений, так как обычно число возможных колец растет экспоненциально с ростом числа ребер |E|. Например, см. таблицу 1 в следующем разделе, где мы приводим число циклов в графах сетках вида kk (2k6). Таким образом, этот подход имеет два узких места: 1. Генерация всех циклов в графе может занять экспоненциальное время; 2. Решение целочисленной линейной программы большого размена, в худшем случае может занять экспоненциальное время от размера самой программы. То есть основной недостаток данного подхода заключается в том, что мы должны решать целочисленную линейную программу, где число переменных велико даже для относительно небольших сетей. Преимущество данного подхода заключается в том, что для небольших сетей, или в случае покрытия сети небольшим набором циклов ограниченного размера, мы можем найти оптимальное решение. Другой подход основан на использовании эвристических алгоритмов для приближенного поиска требуемого множества циклов. Например, так работает программная система RingBuilder [15]. Обычно при этом порождается набор “избранных” (согласно некоторому правилу) циклов, и окончательное решение получается из этих циклов. Обычно набор этих “избранных” циклов достаточно небольшой, даже для достаточно больших сетей, что часто приводит к решению далекому от оптимального. 252
Как мы уже говорили, в первом подходе оптимальное решение можно получить только для небольших сетей, так как размер целочисленной программы растет экспоненциально с размером сети, и для больших сетей дождаться решения задачи (1) становится невозможно. Типичный способ избежать этого ограничить число переменных в задаче (1), введением ограничений на длину цикла (так называемый hop limit). Однако, это ограничение на практике приводит к ухудшению качества аппроксимации. Значит, для получения решения близкого к оптимальному, обязательно надо использовать и длинные циклы.
4. Наш подход: гибкое сочетание ЦЛП алгоритма с эвристическими алгоритмами на графах. Принимая во внимание соображение о необходимости использования длинных циклов для получения хорошей аппроксимации, мы разработали некоторые приближенные алгоритмы, основанные на генерации специальных множеств длинных циклов, наряду со всеми короткими циклами, и решении задачи ЦЛП (1), соответствующей объединению этих двух множеств. Перечислим три основных этапа нашего подхода: 1. Породить все короткие циклы в сети. 2. Используя эвристические алгоритмы, породить набор достаточно длинных циклов, перспективных с точки зрения некоторого критерия (так и называемые “перспективные” циклы). 3. Решить задачу ЦЛП (1) с переменными соответствующими всем коротким и “перспективным” циклам. Преимущество данного подхода состоит в том, что он комбинирует лучшие свойства двух предыдущих подходов. К тому же, мы рассматриваем и множество длинных циклов, которые существенно улучшают качество получамого нами решения. Теперь рассмотрим наш метод более подробно.
ного дерева и всех ребер графа, в него не включенных, мы получаем фундаментальный набор циклов графа G, который образует базис для всех циклов графа G. К сожалению, не все элементы этого векторного пространства являются простыми циклами (т.е. циклами без самопересечений), которые нам необходимы в рамках этой оптимизации. Более того, только очень малая часть элементов этого векторного пространства соответствует простым циклам (см. Таб. 1). Таким образом, нам нужен специальный алгоритм для эффективной генерации всех (простых) циклов в графе. Далее, под циклами, мы будем иметь в виду только простые циклы. Известно несколько алгоритмов для генерации всех циклов в графе [5, 6]. Однако они достаточно медленны. Более привлекательным было бы рассматривать специальные классы графов, и использовать их особенности для быстрой генерации всех простых циклов в этих графах. Известно, что большинство графов, представляющих сетевые топологии являются планарными, т.е. могут быть нарисованы на плоскости без пересечения ребер (либо близки к оным). Для таких графов структура базиса циклов еще проще, в частности, для любого планарного графа G набор его внутренних ячеек образует планарный базис циклов. Используя это и другие свойства планарных графов, были предложены различные алгоритмы для генерации всех простых циклов в планарном графе [7, 8]. Оказалось, эти алгоритмы гораздо более эффективны и могут быть использованы на первом этапе. Сетка
Вершин
Число циклов
22
4
1
33 44 55 66 77
9 16 25 36 49
13 213 9349 1222363 487150371
Таб. 1. Число циклов в планарной сетке kk.
4.1. Этап 1 Первый этап более или менее стандартный, однако, для достижения эффективности, требуется анализ временной сложности существующих алгоритмов, правильный выбор и аккуратная реализация. Известно, что множество циклов конечного графа G= (V, E) образуют линейное пространство по отношению к операции “сложение по модулю 2” (оно же “исключающее ИЛИ”) над циклами. Это означает, что каждый цикл представляется вектором размерности C2|V| бит, и что их можно складывать по модулю два. Размерность этого линейного пространства назвается цикломатическим числом (cyclomatic number) графа. Базис в этом линейном векторном пространстве может быть получен выбором произвольного остовного дерева и последовательным добавлением к этому дереву оставшихся ребер из графа. Добавление любого произвольного ребра к остовному дереву дает в точности один фундаментальный цикл. Повторяя эту процедуру для выбранного остов253
Как мы уже упоминали, число циклов в графе растет очень быстро (экспоненциально) с ростом числа вершин и ребер. В таблице 1 мы представляем зависимосить между размером графа и числом циклов для планарных сеток kk (2k7). Заметим, что для k=6 размер линейного векторного пространства циклов есть 225>32000000, однако число простых циклов “всего лишь” 1222363.
4.2. Этап 2 На этом этапе нам необходимо сформировать достаточно большой набор длиных, “перспективных” циклов. Здесь нужно использовать эвристики, основанные на локальных алгоритмах, а также вероятностные мутации множества циклов. Отличие нашего подхода в отличие от эвристик раздела 3, состоит в том, что мы должны выбирать существенно большее множество “перспективных” циклов, (скажем тысячи циклов), а не единицы или десятки оных. 254
Основная идея локальных алгоритмов, состоит в генерации некоторого множества допустимых решений нашей задачи, и затем в их последовательном улучшении с помощью локальных трансформаций и вероятностных мутаций. На этом этапе должно быть выбрано существенное множество для обеспечения хорошей апроксимации при окончательном решении задачи ЦЛП-алгоритмом. Также могут использоваться и другие виды эвристик, такие как генетические алгоритмы (genetic algorithms), иерархическая декомпозиция (hierarchical decomposition) и т.п.
4.3. Этап 3 Основная идея нашего подхода к эффективному решению таких ЦЛП-задач состоит в том, что, так как число ограничений существенно меньше, чем число переменных, то необходимо найти относительно небольшое подмножество “необходимых” переменных в исходной целочисленной программе. А затем решить эту относительно небольшую целочисленную подпрограмму, содержащую только выбранные “необходимые” переменные. Для выбора необходимых переменных мы используем различные методы, основанные на точном или приближенном решении dualLP линейной программы двойственной к линейной релаксации исходной ЦЛП. Здесь мы опишем два таких метода. 1. Согласно RandomLP-методу мы решаем dualLP вероятностным алгоритмом, гарантирующим точное решение задачи [12]. Мы опишем этот алгоритм в разделе 5. Все ограничения dualLP, которые определяют решение (неисключаемые ограничения) соответствуют “необходимым” переменным исходной задачи ЦЛП (1). Так как наш ЛП алгоритм вероятностный, то различные запуски могут приводить к различным множествам “необходимых” переменных, и после нескольких запусков мы объединяем все эти множества в окончательном множестве “необходимых” целочисленных переменных. 2. В PLPAPX-методе, (методе, основанном на алгоритме PLPAPX) мы решаем задачу dualLP приближенно с заданной точностью нашим алгоритмом PLPAPX [21], приведенном в разделе 6. Затем, мы выбираем некоторое множество переменных с наибольшими значениями. Мы можем варьировать размер этого множества, тем самым, управляя балансом между размеров получающейся ЦЛП программы (и, следовательно, временем ЦЛПоптимизации) и качеством получаемого решения. Также мы можем менять точность алгоритма PLPAPX, балансируя между качеством и временем предварительной аппроксимации. К полученному с помощью того или иного метода набору “перспективных” циклов мы добавляем набор “маленьких” циклов с длиной меньше заданной, (скажем <7). Вычислительные эксперименты показали, что часто это существенно улучшает качество решения за небольшую временную плату. Далее мы рассмотрим детали реализации этих алгоритмов. 255
5. Вероятностный алгоритм ЛП Алгоритм для решения задач ЛП, в которых число ограничений существенно больше числа переменных был предложен в [12]. В [12] было показано, что ожидаемое время работы этого вероятностного алгоритма в случае, когда число ограничений существенно больше числа переменных, 2 составляет O(n mlogm). Причем математическое ожидание времени работы алгоритма не зависит о распределения входных данных, оно усредняется вероятностным выборами ограничений, выполняемыми алгоритмом. В частности, не существует входных данных, на которых алгоритм может работать плохо. Мы использовали некоторую модификацию исходного алгоритма. Псевдоалгоритмическое описание нашего алгоритма приведено ниже. В описании n означает число переменных, а m обозначает число ограничений, ExactLP функция получения точного решения заданной линейной программы, например симплекс-метод или метод внутренней точки. Через s(x) мы обозначим отсечку невязки ограничения s: s(x)=max0, bs-j=1,nasjxs. function RandomLP(S: a set of constraints) V*; choose RS at random, |R|=r loop x*ExactLP(V*R) vargmaxsS s(x*) if v= then exit loop; V* V*v; end loop V=; return x*; end function В начале алгоритма мы выбираем случайное множество ограничений R* размера r m. Затем следуют итерации, пока мы не найдем допустимое решение. В каждой итерации мы решаем задачу ЛП с подмножеством ограничений V*R, выбираем наиболее нарушенное ограничение v, или z наиболее нарушенных ограничений и добавляем их к V*. Таким образом, у алгоритма два параметра: r and z. 256
Вычислительные эксперименты (см. раздел 7) показали, что предложенный алгоритм достаточно эффективен, и в рамках предложенной в разделе 5 схемы обеспечивает близкие к оптимальным решения больших целочисленных программ рассматриваемого типа.
6. PLPAPX приближенный алгоритм ПЛП Положительное Линейное Программирование (ПЛП) это частный случай линейного программирования, когда входные данные (матрица ограничений, вектор правых частей, и коэффициенты целевой функции) содержат только неотрицательные элементы. Задачу ПЛП также называют задачей дробного покрытия, если это задача минимизации и ограничения вида Axb, и задачей дробной упаковки, если это задача максимизации и ограничения вида Axb. Приближенный алгоритм, гарантированно дающий решение не более чем в 1+раз хуже оптимального, называется -оптимальным. PLPAPX это быстрый -приближенный алгоритм ПЛП, основные идеи которого близки к идеям алгоритмов из [17, 18, 19, 20]. Мы доказали в [21], что временная сложность последовательной реализации является лучшим известным результатом O(N /log(mn /)), где N число ненулевых записей в матрице ограничений, m число строк в матрице ограничений, n число переменных (колонок). Далее в этом разделе мы будем использовать i для индексирования ограничений, и если другое не указано, считать что i изменяется в пределах 1,,m; аналогично мы будем использовать j для индексирования переменных и 1,,n будут ее пределами изменения. Рассмотрим задачу ПЛП в следующей стандартной форме. Прямая задача (задача дробной упаковки): Для заданной вещественной матрицы A, в которой все элементы aij 0, необходимо найти вектор x = x1, , xn, который максимизирует Xxj при выполнении следующих ограничений: i j aij xj 1 j xj 0 Двойственная задача (задача дробного покрытия):
Заметим, что задача ПЛП в обычной форме maximize cj xj i j aij xj bi j xj 0 просто преобразуется в стандартную форму путем преобразования матрицы ограничений: aijaij /(bj /ci) . Ниже приведено упрощенное алгоритмическое описание алгоритма PLPAPX. Более подробное описание, доказательство оптимальности, корректности и оценок времени выполнения можно найти в [21].
m, n, , mn матрица A Векторы x, y соответственно оптимальные решения
Input Output
прямой и двойственной задачи ПЛП в стандартной форме.
Y=exp( ((1+) log m + ); j xj0;
X0;
i yi;
Ym;
xj / maxi aij ;
j dual_lhsji aij yi ; dual_lhsminminj dual_lhsj ; Y Y/ dual_lhsmin ; repeat forall
j : (Y/ dual_lhsj)(Y/ (1+) ) do
xjxj+xj ;
Xj xj ;
i lhsij aij xj; i yiexp( lhsi ); j dual_lhsji aij yi ;
Y yi ; lhsmaxmaxi lhsi ;
dual_lhsminminj dual_lhsj ;
Y Y/ dual_lhsmin ; end for until ( (X/ lhsmax )>(Y / (1+)) or (Y>Y ) )
return (x / lhsmax), (y / dual_lhsmin)
Для заданной вещественной матрицы A, в которой все элементы aij 0, необходимо найти вектор y = y1, , yn, который минимизирует Yyi при выполнении следующих ограничений: j i aij yi 1 i yi 0
257
Алгоритм параллельно модифицирует допустимые решения прямой (x) и двойственной (y) задачи, пока они не сходятся к заданной области оптимального решения. Вычислительные эксперименты показали эффективность алгоритма на различных видах входных данных, таких как матрицы ограничений со случайными элементами или линейные релаксации задачи ЦЛП (1).
258
7. Вычислительные эксперименты Мы разработали «RingOptimizer» программную систему для моделирования и оптимизации задачи проектирования сетей с самовосстановлением связи методом п-циклов с использованием вышеописанных алгоритмов. «RingOptimizer» решает следующие задачи: предоставляет графический интерфейс для постановки задачи проектирования, т.е. обеспечивает рисование графа топологии сети и установки требуемых пропускных способностей и стоимости каждого ребра сети; порождает множество всех циклов и колец для заданной сети; осуществляет отбор “перспективных” циклов с использованием описанных алгоритмов ЛП PLPAPX и RandomLP. решает ограниченную задачу (1), включающую только “перспективные” циклы. предоставляет графический интерфейс для просмотра полученного решения. При разработке «RingOptimizer» мы использовали следующие программные библиотеки: GLPK (GNU Linear Programming Kit) [15], библиотеки линейной оптимизации (симплекс-метод, метод внутренней точки) и целочисленной линейной оптимизации. Согласно регулярным независимым тестам программ линейной и целочисленной оптимизации [16], GLPK является лучшей некоммерческой библиотекой и не сильно уступает коммерческим продуктам для ЛП и ЦЛП оптимизации, таким как CPLEX. LEDA (library of the data types and algorithms for combinatorial computing) для эффективной реализации внутренних структур данных. Также для целей тестирования мы использовали следующие программы оптимизации ЛП и ЦЛП: LP SOLVE (автор — Michel Berkelaar, [email protected]); IBM OSLMSLV. В качестве входных данных мы использовали несколько реальных сетей из статьи [11] и несколько искусственных, полученных добавлением к наибольшей сети из [11] дополнительных вершин и ребер. Примеры таких сетей можно видеть на Рис. 1, 2. Ниже представлены некоторые свойства этих сетей: Сеть Вершин Ребер Циклов
japan11-23 11 23 307
japan26-42 26 42 2295
japan28-45 28 45 7321
Рис. 1. Сеть japan28-45
isp42-63 43 66 113041
Все времена тестирования приведены для обычного персонального компьютера: AMD Athlon XP 1800+, Speed: 1.53GHz, Performance Rating: PR2224, 512Mb. 259
Рис. 2. Сеть isp42-63 260
7.1. Алгоритм порождения циклов
Сеть
Ниже мы представим время (в секундах) перечисления всех циклов (без записи порожденных циклов на диск) и время, требуемое для полной генерации циклов с учетом записи результатов в файл. Два типа результатов предоставляются потому, что время генерации существенно зависит от производительности подсистемы ввода/вывода. Сеть japan11-23 japan26-42 japan28-45 isp42-63 isp43-66 isp43-68
число циклов 307 2295 7321 113041 300614 821780
6
japan11-23
0 0 0 17 50 143
japan26-42
Заметим, что для любого графа также возможна генерация циклов, с ограничением по длине (maxlength), но и в этом случае производительность генерации (число циклов/ в секунду) примерно будет таким же, как и при генерации всех циклов. Так, например, для сетки 1010, наш алгоритм перечислил 2801895 циклов длины 20 за 221 секунду.
7.2. Решение ЦЛП задачи на множестве циклов с ограниченной длиной
japan28-45
Для тестируемых сетей мы порождали наборы циклов с различными ограничениями на длину, и для каждого множества циклов порождали соответствующее множество колец. При расчете стоимости каждого кольца мы считали, что стоимость кольца линейно зависит от суммы стоимостей ребер входящих в цикл, на котором лежит данное кольцо: isp42-63
pr=mreE(r)Coste,
isp43-66
0
280
2476
0
2136
0
43
1680
0
8
72
1520
0
12
277
1200
0
16
870
1120
0
20
1820
1120
0
Все циклы
2295
1040
1
5
27
31776
0
6
39
28340
0
8
87
23120
0
12
465
19640
0
16
1864
18592
6
20
4809
17868
74
Все циклы
7321
16720
2
8
92
28220
9
10
225
28220
9
11
338
22680*
10000**
113041
*
*
8
103
27292
25
10
250
25160*
600*
12
596
23696*
600*
300614
*
8
130
42034
10
6132
38444
12
17426
*
821780
*
Все циклы
262
2932
307
Все циклы
isp43-68
134
6
Все циклы
где, согласно постановке задачи (1), pr это стоимость кольца r, mr пропускная способность кольца r, E(r) набор ребер в кольце r, Coste стоимость ребра e. На самом деле система «RingOptimizer» позволяет для каждого цикла порождать набор колец разных пропускных способностей и использовать более сложную функцию стоимости каждого кольца, но для простоты иллюстрации в приведенных результатах для каждого цикла мы порождали только один тип кольца с пропускной способностью 4. Таким образом, число переменных в задаче ЦЛП совпадало с числом циклов. Число ограничений, разумеется, было равно числу ребер. Сначала рассмотрим результаты касательно зависимости оптимума ЦЛП задачи (1) от ограничения на длину циклов, определяющего множество переменных задачи (1). Звездочка означает, что оптимальное значение не удалось найти за выделенное время, и приведенное значение, если оно есть, отражает результат работы ЦЛП оптимизатора за заданный временной интервал. 261
8 Все циклы
время перечисления время генерации 0 0 0 6 20 58
Набор циклов Число циклов Оптимум время решения с длиной (переменных) ЦЛП ЦЛП (в секундах )
Приведенные результаты показали, что ограничение на максимальную длину цикла существенно ухудшают качество решения.
7.3. Использование PLPAPX для выбора циклов В этом разделе мы представляем некоторые результаты оптимизации задачи (1) с использованием алгоритма PLPAPX для выделения “перспективных циклов” и с использованием пакета GLPK для решения ограниченной задачи ЦЛП. Мы запускали алгоритм PLPAPX с различными параметрами для dualLP (двойственной релаксации исходной задачи (1)), затем отбирали MIP_SIZE циклов, соответствующих наибольшим переменным в приближенном решении. Затем мы также добавляли к выбранным циклам набор “маленьких” циклов с длиной addCyclesLength (например 8). Таким образом, предложенная схема имеет следующие параметры: изменяя параметр алгоритма PLPAPX, мы влияли на качество аппроксимации dualLP. Однако нам не выгодно выбирать слишком маленьким, так как с одной стороны время аппроксимации обратно зависит от качества аппроксимации, а с другой точное решение может быть слишком далеким от целочисленности. MIP_SIZE. Изменяя параметр MIP_SIZE, мы изменяем количество отобранных циклов и следовательно размер ограниченной задачи ЦЛП, и тем самым, балансируем между качеством решения и временем решения ограниченной задачи ЦЛП. AddCyclesLength. Мы обнаружили, что добавление небольшого набора маленьких циклов ограниченной длины часто приводит к улучшению качества решения за небольшую временную плату. Качество решения, время предварительной PLPAPX-селекции и время решения усеченной задачи ЦЛП для сети isp42-63, в зависимости от различных параметров приведены в таблице 1. PLPAPX- время PLPAPXселекции циклов MIP_SIZE (AddCycles- решение Length=0.) ЦЛП 20 30 40 50 60 70 80 90 100
20796 18676 17892 17884 17884 17884 17760 17760
0.3
0.2
0.1
47
79
204
время ЦЛП 1 1 2 7 68 334 206 300
решение ЦЛП 20964 18021 17960 17884 17884 17812 17676 17676 17608*
время ЦЛП 0 1 10 11 32 37 126 211 600
решение ЦЛП 18756 17984 17828 17812 17812 17668 17612 17468 17396
время ЦЛП
PLPAPX- время PLPAPXселекции циклов MIP_SIZE (+ 34 cycles решение with length<6) ЦЛП 20 30 40 50 60 70 80 90 100
MIP_SIZE (+ 92 cycles решение with length<9) ЦЛП 20 30 40 50 60 70 80 90 100
20408 19788 18268 17892 17800 17728 17728 17788 18092
0.2
0.1
47
79
204
время ЦЛП 0 0 2 3 10 130 406 369 559
время ЦЛП 9 3 31 19 19 227 600* 600* 600*
решение ЦЛП
время ЦЛП
20340 18012 17960 17884 17884 17804 17676 17676 17608
решение ЦЛП
решение ЦЛП
0 2 15 59 58 64 287 313 883
время ЦЛП
19940 18012 17876 17736 17736 17572 17832 17944 17936
17984 17984 17892 17812 17996 17668 17612 17468 17396
решение ЦЛП
5 6 47 110 143 36 600* 600* 600*
время ЦЛП 0 3 5 20 50 363 262 703 562
время ЦЛП
17884 17884 17572 17572 17572 17824 17640 17488 17396
2 18 4 11 359 900* 600* 600* 600*
Таб. 1. PLPAPX-оптимизация сети isp42-63. Различные параметры оптимизации. Отсортировав по времени полного решения (время работы PLPAPX + время ЦЛП оптимизации) мы получаем следующую таблицу зависимости качества решения от затраченного времени. время оптимизации 47
0 3 3 14 34 188 159 406 456
263
20936 19872 18460 17892 17884 17884 17884 17760 17760
0.3
49 50 54 56 66 78
264
значение решения
время PLPAPX
время ЦЛП
MIP_ SIZE
19872 17892 19788 17884 20408 17800 18268
47
0 2 3 7 9 19 31
30 50 30 60 20 60 40
47 47 47 47 47 47
число “маленьких” циклов
PLPAPX-
34
0.3
0
0.3
92
0.3
0
0.3
92
0.3
92
0.3
92
0.3
время оптимизации 80 81 84 89 115 116 126 143 189 204 205 207 253 254 274 363 392 610 647 660 679 804
значение решения
время PLPAPX
время ЦЛП
MIP_ SIZE
18021 18012 19940 17960 17572 17812 17876 17804 17736
79
79
1 2 5 10 36 37 47 64 110
30 30 20 40 70 70 40 70 50
17984 17676 17828 17760 17996 17728 17612 17668 17468 17788 17396 17608 17488
204
0
79
126 3 206 50 227 159 188 406 600 456 600 600
20 80 40 90 60 70 80 70 90 90 100 100 90
79 79 79 79 79 79 79
204 47 204 47 204 204 204 47 204 79 204
число “маленьких” циклов
PLPAPX-
0
0.2
34
0.2
92
0.2
0
0.2
92
0.2
0
0.2
92
0.2
34
0.2
92
0.2
34
0.1
0
0.2
0
0.1
0
0.3
34
0.1
92
0.3
0
0.1
0
0.1
0
0.1
92
0.3
0
0.1
0
0.2
92
0.1
С помощью этих параметров можно осуществлять оптимальную настройку алгоритма RandomLP на входные данные, улучшая качество решения и уменьшая временные затраты. Например, мы обнаружили, что качество решения несильно зависит от параметра iterations, но более серьезно от параметров r и z. Поэтому мы представляем здесь результаты оптимизации с различными параметрами r и z (при фиксированном iterations=1). Сеть japan28-45
isp42-63
z
r
Оптимум
время время решения RadomLP
время ЦЛП
размер ЦЛП
1
0.1
16792
1
1
0
1
0.1
17536
632
32
600*
339
1
0.05
17480
647
47
600*
263
0.5
0.05
17380
642
42
600*
221
0.5
0.02
17380
400
82
318
180
0.5
0.01
17448
202
86
116
158
1
0.01
17356
211
82
129
177
2
0.01
17428
370
75
295
237
При добавлении множества циклов с длиной меньшей или равной 6, мы имеем: Сеть
Таб. 2. PLPAPX-оптимизация сети isp42-63. Сортировка по времени.
r
z
Оптимум
время время решения RadomLP
время ЦЛП
размер ЦЛП
0.3 0.01
17420
208
83
125
176
0.5 0.02
17348
400
89
312
199
0.5 0.01
17392
202
71
198
172
0.1 0.01
17348
466
92
374
179
isp42-63
8. Использование RandomLP для отбора циклов В этом разделе мы представляем некоторые результаты оптимизации задачи (1) с использованием алгоритма RandomLP для выделения “перспективных циклов” и с использованием пакета GLPK для решения ограниченной задачи ЦЛП. Основные параметры алгоритма RandomLP следующие (см. раздел 5.): r — определяет размер начального множества ограничений |R|=rm, где m является числом ребер (переменных dualLP). z — определяет размер (zm) подмножества ограничений, добавляемых на каждой итерации. iterations — число итераций алгоритма RandomLP. 265
Здесь также добавление небольшого набора маленьких циклов ограниченной длины часто приводит к улучшению качества решения за небольшую временную плату.
9. Заключение. Пока не существует автоматизированных систем планирования сетей с пциклами, находящих оптимальные решения для сетей реального, большого 266
размера. Два основных подхода к решению этой задачи это использование алгоритмов ЦЛП или различных эвристик. В первом случае мы можем в принципе найти оптимальное решение, но экспоненциальная временная плата является непосильной. Эвристики работают быстро, но зачастую порождаемые ими решения далеки от оптимальности. В этой работе мы предлагаем метод для эффективного решения подобных оптимизационных задач. Мы используем гибкое сочетание эффективных алгоритмов ЦЛП работающих на разумного размера множестве циклов, порожденном специальными алгоритмами (включая эвристики). Таким образом, мы обеспечиваем эффективность, так как избегаем узкого места с экспоненциальным числом циклов, но при этом добиваемся хорошего качества приближенных решений.
17. Yair Bartal, John W. Byers, and Danny Raz. Global optimization using local information with application to flow control. In IEEE FOCS, pages 303311, 1997. 18. N. Garg and J. Koenemann. Faster and simpler algorithms for multicommodity flow and other fractional packing problems. In IEEE FOCS, pages 300309, 1998. 19. M. Luby and N. Nisan. A parallel approximation algorithm for positive linear programming. In Proc. of 25th ACM STOC, pages 448457, 1993. 20. С. А. Фомин. Новый приближенный алгоритм для решения задачи положительного линейного программирования, Дискретный анализ и исследование операций. Серия 2, 8(2), 2001. 21. С. А. Фомин. Быстрый приближенный алгоритм для решения задачи положительного линейного программирования, Труды Института Системного Программирования РАН, 2003.
Литература 1. T.S. Wu, Fiber Network Service Survivability, Artech House, 1992. 2. GR-1230-Core, SONET Dual-Fed Unidirectional Path Switched Ring (UPSR) Equipment Generic Criteria, Bellcore, Issue 1, October 1995. 3. C.D. Morley and W.D. Grover, Comparison of mathematical programming approaches to optical ring network design, Proc. of CCBR’99. 4. J.L. Kennigston, V.S.S. Nair, M.H. Rahman, Optimization based algorithms for finding minimal cost ring covers in survivable networks, Computational Optimization and Applications, 1999, v. 14, pp. 219–230. 5. D.B. Johnson, Finding all the elementary cycles of a directed graph, SIAM J. Computing, 1975, v. 4, pp. 77–84. 6. Prabhakar Mateti and Narsingh Deo. On algorithms for enumerating all circuits of a graph. SIG COMP, 5(1):90–99, 1976. 7. M. M. Syslo, An efficient cycle vector space algorithm for listing all cycles of a planar graph, SIAM Journal on Computing, 10(4):797–808, November 1981. 8. U. Dogrusoz, M.S. Krishnamoorthy, Enumerating all cycles of a planar graph, SIG COMP, v. 10, 1996, 21–36. 9. K.L. Clarkson, A Las Vegas algorithm for linear programming when the dimension is small, Proc. 29th Annual IEEE Symposium on Foundations of Computer Science (FOCS), 1988, pp. 452–456. 10. F. Glover, M. Laguna, Tabu search, Kluwer Academic Press, 1997. 11. Kazutaka Murakami and Hyong S. Kim. Comparative study on restoration schemes of survivable ATM networks. In Proceedings of IEEE INFOCOM, pages 3C.1.1–8, April 1997. 12. Documentation on RingBuilder 1.3 is available at http://www.ee.ualberta.ca/grover/RingBuilder/ringbuilder.htm 13. Claus G. Gruber and Dominic A. Schupke, Capacity-efficient Planning of Resilient Networks with p-Cycles. Networks 2002, 10th Int. Telecommunication Network Strategy and Planning Symposium, Munich, Germany, June 23-27, 2002. 14. Dieter Rautenbach, Bruce A. Reed: Approximately covering by cycles in planar graphs. SODA 2001: 402-406. 15. Andrew Makhorin, GLPK Reference Manual, 2003, http://www.gnu.org/software/glpk/glpk.html. 16. Hans Mittelmann. Benchmarks for Optimization Software. Department of Mathematics and Statistics, Arizona State University, http://plato.la.asu.edu/bench.html}, 2003.
267
268
Эвристики распределения задач для брокера ресурсов Grid А.И. Аветисян, С.С. Гайсарян, Д.А. Грушин, Н.Н. Кузюрин, А.В. Шокуров Аннотация. Последние работы в области Grid позволяют приложениям использовать вычислительные ресурсы, принадлежащие различным организациям, распределенным по различным странам и континентам. Одним из видов ресурсов Grid являются однородные многопроцессорные системы (кластеры), которые могут состоять из сотен или даже тысяч процессоров. В работе представлена архитектура и основные принципы иерархического децентрализованного распределения параллельных задач в таких Grid окружениях. Рассматривается двухуровневая иерархия: на первом уровне несколько независимых брокеров распределяют задачи на кластеры в соответствии с некоторым критерием; на втором уровне каждый кластер распределяет задачи, поступившие от брокера, используя эвристики, основанные на алгоритмах упаковки в полосу. Эффективность предлагаемой схемы распределения задач проверяется на моделях.
1. Введение Глобальные вычислительные сети Grid [1] были предложены в качестве новой парадигмы для решения крупномасштабных вычислительных задач в науке, технике и бизнесе [2]. Они дают возможность одновременного использования миллионов вычислительных ресурсов [3], принадлежащих различным организациям и расположенных в различных административных областях. Системы Grid объединяют разнородные вычислительные ресурсы (персональные компьютеры, рабочие станции, кластеры, суперкомпьютеры), используя разные стратегии доступа к ним, выполняя различные приложения (научные, инженерные и коммерческие), предъявляющие к системе различные требования. Ресурсы принадлежат различным организациям, имеющим свои правила управления ресурсами, их использования и определения их стоимости для различных пользователей в различное время. Доступность и загруженность ресурсов также может динамически изменяться во времени. В окружении Grid владельцы и потребители ресурсов имеют различные цели, используют различные стратегии и экономические схемы регулирования спроса и предложения. Таким образом, актуальной проблемой является разработка систем управления ресурсами Grid, нацеленных на оптимизацию отношений между владельцами ресурсов и пользователями в соответствии с выбранными ими стратегиями. 269
Многие системы управления ресурсами Grid (такие как Legion [4], Condor [5], AppLeS PST [6], NetSolve [7], PUNCH [8], XtremWeb [9] и т.д.) используют простые схемы распределения, когда компонент, отвечающий за распределение, решает, какие задачи должны быть выполнены на каком ресурсе, используя функции стоимости, задаваемые системными параметрами. Целью таких систем распределения является увеличение пропускной способности системы, ее загруженности и уменьшения времени выполнения задач, а не увеличение рентабельности ресурсов и приложений. Они не рассматривают цену использования каждого ресурса, а это означает, что значимость выполнения всех приложений в любое время одинакова, что в реальности далеко не так – значимость должна возрастать с приближением срока выполнения прикладной задачи. В [10] предложено использование экономического подхода к планированию и распределению ресурсов, когда решения о распределении ресурсов производятся динамически и зависят от текущих требований пользователей (такой подход реализован в системе GRACE [11]). Это – рыночная модель распределения ресурсов, когда цена каждого ресурса определяется потребностями в нем пользователей и его доступностью. Таким образом, в системе Grid пользователь конкурирует с другими пользователями и владелец ресурса с другими владельцами ресурсов. Экономический подход позволяет успешно управлять децентрализованными и гетерогенными ресурсами так, как это происходит в реальной экономике. Экономические системы управления ресурсами Grid динамически определяют наилучшие ресурсы, учитывая их цену и производительность, и распределяют задачи на этих ресурсах так, чтобы удовлетворить потребности пользователей. Как и другие системы, определяемые целями, ресурсами и действиями, вычисления на Grid могут быть рассмотрены в экономических терминах. Быстрое развитие сетевых технологий изменило архитектуру высокопроизводительных вычислительных систем: вместо централизованных моделей управления ресурсами стали использоваться децентрализованные. Использование экономического подхода является естественным продолжением этого развития. Способность ценовых механизмов заменять локальные решения по управлению различными объектами определением глобально эффективных характеристик определяет их значение в организации вычислений в больших системах, таких как Grid или Internet. До последнего времени решения отдельных людей или организаций предоставить ресурсы для Grid в значительной степени мотивировались общественной пользой, призами, забавой, известностью, или совместной выгодой. Это в корне отличается от построения частных Grid систем (но с использованием добровольных ресурсов) или исследовательских проектов, таких как Distributed.net [11], SETI@Home [3], Condor pool [5], GUSTO [12], eGrid [13], World-Wide Grid [14]. Распределенная архитектура Grid показана на рисунке 1 (который взят из [10]).Эта архитектура является достаточно полной и подходит для описания 270
различных моделей, используемых для распределения и управления ресурсами. Основными компонентами в системе Grid являются: Пользователь Grid и приложения (последовательные, параметрические, параллельные или совместные) Интерфейсное ПО уровня пользователя – высокоуровневые услуги и инструменты Программные окружения Брокеры ресурсов Интерфейсное ПО ядра Grid (распределение ресурсов и объединение распределенных ресурсов) Поставщики ресурсов и услуг Grid
Рис. 1. Архитектура Grid Двумя главными субъектами в системе Grid являются поставщики и потребители ресурсов. Оба субъекта имеют собственные стратегии. Потребители ресурсов применяют стратегии решения своих прикладных задач в зависимости от требуемого времени и наличного бюджета. Поставщики ресурсов используют стратегию получения наибольшей выгоды от вложенных средств. Владельцы ресурсов стараются максимизировать использование своих ресурсов. Пользователи имеют возможность выбора поставщиков, которые в наибольшей степени удовлетворяют их требованиям. Если поставщики ресурсов имеют локальных пользователей, они будут стараться получить наилучшую отдачу от простаивающих ресурсов. Для этого системы Grid должны использовать утилиты и механизмы, которые позволяют поставщикам и потребителям задавать свои требования. Потребители ресурсов Grid взаимодействуют с брокерами для задания своих требований, таких как сумма, которую они могут потратить на решение данной задачи и предел времени, в течение которого они хотят получить результат. 271
Они также должны иметь возможность выбирать между этими двумя группами требований. Поставщики ресурсов нуждаются в утилитах для задания ценовых политик и механизмов, которые помогут им максимизировать прибыль и утилизацию ресурсов. Брокер ресурсов Grid выступает в роли соединительного звена между пользователями и поставщиками ресурсов Grid, используя интерфейсное ПО ядра для обеспечения услуг. Он отвечает за поиск ресурсов, их выбор, привязку программного обеспечения и данных к выбранным ресурсам, инициализацию вычислений, адаптацию к изменениям в системе. Брокер выступает для пользователей Grid как единый ресурс. Брокер состоит из следующих компонент: Система управления задачами. Отвечает за прохождение задачи пользователя. Взаимодействует с планировщиком для генерации расписания, производит создание задачи, поддержку статуса задачи, взаимодействие с клиентами и пользователями, планировщиком и распределителем. Система составления расписаний. Отвечает за поиск ресурсов (используя систему исследования Grid), выбор ресурса и распределение задания (генерация расписания), чтобы убедиться в том, что требования пользователя удовлетворены. Система исследования Grid. Отвечает за обнаружение ресурсов, взаимодействуя с информационным сервером Grid. Система установки задачи. Отвечает за активацию выполнения задачи на выбранном ресурсе и периодическое обновление статуса выполняемой задачи. В данной статье рассматривается проблема оптимизации распределения параллельных задач в таких системах. Рассматривается двухуровневая иерархия: на первом уровне несколько независимых брокеров распределяют вычислительные задачи на кластеры в соответствии с некоторым критерием. На втором уровне каждый кластер распределяет задачи, присвоенные ему локальным планировщиком. Такие локальные планировщики могут использовать эвристики, основанные на алгоритмах упаковки в полосу. Эффективность предлагаемого распределения проверяется с помощью моделирования и численных экспериментов. В данной статье не рассматриваются детали реализации брокера и другие задачи, решаемые брокером, такие как поиск и выбор ресурсов. Главной задачей данной статьи является сравнение различных стратегий распределения ресурсов и определение их эффективности. Статья организована следующим образом. В главе 2 рассматриваются компоненты системы. В главе 3 – различные стратегии распределения задач. Результаты численных экспериментов представлены в главе 4.
2. Кластеры и описание задач Брокер ресурсов ответствен за выбор ресурсов и распределение задач таким образом, чтобы удовлетворить все требования пользователей и 272
оптимизировать общее время выполнения и стоимость используемых ресурсов. Цель состоит в определении эффективности такого распределения задач при использовании различных критериев. В состав рассматриваемой системы входят следующие компоненты. Кластеры. Процессоры одного кластера одинаковы, однако процессоры различных кластеров могут иметь различные объемы памяти и производительность. Таким образом, кластер Ci можно охарактеризовать количеством процессоров mi, объемом памяти каждого процессора Si и производительностью процессоров ri по отношению к стандартному процессору. Стоимость Ki характеризует каждый кластер и равна стоимости единицы времени одного процессора этого кластера. Каждый кластер имеет очередь задач, которые должны быть выполнены. Описание задач. Задачи Tj являются независимыми – во время их выполнения не происходит коммуникаций между задачами, что позволяет выполнять задачи в любом порядке. Мы предполагаем также, что каждая задача может быть решена с использованием только одного кластера (нет необходимости в совместных вычислениях на нескольких кластерах). Каждая задача может быть описана количеством требуемых процессоров pj, максимальным временем выполнения tj (на pj стандартных процессорах), требованиями к памяти Mj и предельным временем. Когда время выполнения задачи Tj превышает tj задача Tj должна быть прервана и отправлена обратно брокеру. Стоимость (или важность) задачи Ij определяется как функция от количества процессоров pj и времени t(Tj). Брокеры. Каждый брокер получает задания от пользователей и распределяет задачи между кластерами учитывая информацию о задачах и текущем состоянии кластеров. Мы рассматриваем следующий сценарий. Брокер анализирует запрос на выполнение задачи и рассылает его всем кластерам, которые могут его выполнить. Каждый кластер возвращает время до которого задача может быть выполнена. Брокер принимает решение на основе этой информации и выбирает кластер, который удовлетворяет предельному времени выполнения задачи и имеет наименьшую стоимость (или использует другой критерий, например, минимальное время выполнения – MCT). Затем брокер заключает «контракт» с кластером, посылая кластеру описание задачи. Таким образом, иерархическая система распределения задач имеет два уровня: 1) распределение задач по кластерам 2) распределение многопроцессорных задач на кластере Первый уровень обслуживается брокерами, а второй – кластерами (локальными планировщиками кластеров). Рассматриваются различные алгоритмы для этих уровней и оценивается эффективность системы в целом. Так как существует несколько брокеров, работающих одновременно, они распределяют задачи по кластерам в режиме транзакций. Это означает, что существует общая очередь запросов брокеров, где все брокеры, желающие распределить задачи, оставляют свои запросы. Когда транзакция брокера 273
завершается, следующий брокер в очереди получает возможность распределить свои задачи. Время каждой транзакции ограничено, например, константой K, равной количеству задач, которые брокер может разместить (в общем случае K=1). Такое ограничение исключает ситуацию, когда один брокер может распределить много задач, тогда как другие должны ждать.
3. Стратегии распределения В данной главе рассматриваются основные понятия теории распределения параллельных задач. Затем описываются некоторые специфические особенности распределения задач в окружении Grid, усложняющие задачу распределения. Наконец, описываются различные стратегии распределения, которые будут рассмотрены в следующей главе.
3.1. Распределение параллельных задач Время выполнения параллельной задачи может зависеть от числа используемых процессоров и, в общем случае, может быть определено ассоциативной функцией f j : D R , где D – множество возможных процессоров для задачи j. Существующие исследования по теории распределения для мультипроцессоров были сфокусированы на минимизации максимума времен выполнения Cmax, суммы времен выполнения Cj и пропускной способности системы (числа задач, завершенных до предельного времени выполнения). Как правило, распределение многопроцессорных задач является NP-полной задачей [10]. Тем не менее, было предложено несколько различных приближенных алгоритмов. В некоторых случаях распределение параллельных задач может рассматриваться как задача упаковки в полосу, где множество прямоугольников (соответствующих задачам) должно быть упаковано в полосу с ограниченной шириной и неограниченной высотой. В [4] было показано, что асимптотическая эффективность эвристики "левый нижний угол" равна 3 (оценка достигается, когда прямоугольники отсортированы обратно пропорционально их ширине). В [6] было показано, что некоторые алгоритмы, где прямоугольники расположены по «полкам», используя эвристику одномерной бинарной упаковки, имеют асимптотическую эффективность 2.7 (оценка достигается, когда прямоугольники отсортированы по уменьшению их высоты). Асимптотическая эффективность лучших эвристик была в дальнейшем уменьшена до 2.5 [15], затем до 4/3 [12] и, наконец, до 5/4 [3]. Последние улучшения распределения параллельных задач представлены в [10, 12, 13]. Критерий пропускной способности был исследован в основном в классической теории распределения [3], при этом максимизируется количество ранних задач (wj)Uj, где Uj=1 если задача Tj завершилась до предельного времени выполнения d(Tj) и Tj =0. В мультипроцессорных системах хорошие алгоритмы известны только для частных случаев (времена выполнения одинаковы и количество процессоров pj для каждой задачи Tj фиксировано) [16]. 274
Несмотря на большое количество теоретических и экспериментальных результатов относительно алгоритмов распределения, интересны способы распределения параллельных задач несколькими независимыми брокерами, что делает проблему более сложной и отличающейся от классических задач распределения.
{1,…,n}{1,…,m} задач к кластерам допустим, что El обозначает все задачи, завершенные до предельного времени выполнения. Пусть Ij определяет стоимость задачи j, где Ij= pjtj. Затем допустим
3.2. Специфика распределения задач в окружении Grid
и плотность распределения определяется как COST I T mi
Просуммируем вкратце некоторые особенности распределения задач в окружении Grid. 1) различные представления задач Различные пользователи могут использовать различные представления задач и различные ограничения. Например, одно приложение может потребовать завершения до предельного времени выполнения, другие могут потребовать ограниченную стоимость или выполнение на фиксированном кластере и т.д. 2) существует поток задач Брокер должен распределять задачи, не зная всего множества задач. Это похоже на распределение в реальном времени, но брокер имеет возможность предварительно набрать некоторое количество задач для улучшения качества распределения. 3) нечеткое предполагаемое время выполнения Брокеру известно только максимальное время выполнения задачи (а не реальное время ее выполнения). Таким образом, брокер принимает решение о размещении задачи, основываясь на неполной информации о точном числе требуемых процессоров и верхней границе времени выполнения. 4) динамическое поведение ресурсов В окружении Grid вычислительные ресурсы могут изменять производительность, коммуникационные соединения могут изменять пропускную способность и т.д. 5) множество различных критериев оптимизации (общая производительность, цена и т.д.) Различные критерии могут быть выбраны как целевая функция для определения эффективности политики распределения: общее время выполнения, цена, пропускная способность и т.д.
3.3. Сравнение стратегий распределения Рассмотрим n задач, m кластеров, общее предельное время выполнения T. Пусть tj – время выполнения задачи j на pj процессорах и mi – число процессоров кластера i. В качестве целевой функции используется плотность распределения, которая определяется как сумма стоимостей всех задач которые завершились до предельного времени выполнения T деленное на общее число процессоров всех кластеров умноженное на T. Введем более формальное определение плотности распределения. Для данного отношения l: 275
COST
I
j
jEl
i
Таким образом, плотность распределения определяется как взвешенная целевая функция пропускной способности. Как мы уже упоминали выше, каждому кластеру j соответствует некоторая стоимость Kj. Положим Kj равной отношению числа процессоров кластера j к числу процессоров наименьшего кластера. Напомним, что брокер анализирует запрос на вычисление задачи и посылает его всем кластерам, которые могут его выполнить. Каждый кластер возвращает время, до которого задача может быть выполнена. Брокер принимает решение на основе этой информации и выбирает кластер, который удовлетворяет предельному времени выполнения задачи и имеет наименьшую стоимость (или использует другой критерий, например, минимальное время выполнения – MCT). Затем брокер заключает «контракт» с кластером, посылая кластеру описание задачи. Исследуем эффективность эвристик брокера, основанных на: 1) 2)
распределении задачи на самый дешевый кластер, который удовлетворяет предельному времени выполнения распределении задачи на кластер, который предоставляет наименьшее время выполнения задачи
Кроме того, рассмотрим влияние сортировки задач по ширине на целевую функцию Во всех случаях кластер (локальный планировщик) размещает задачу, основываясь на эвристике "левый нижний угол" (в порядке поступления задач). В случаях CHEAP-SORT, MCT-SORT эвристики используют препроцессорную сортировку задач по уменьшению их ширины (ширина задачи j это число требуемых процессоров pj). Исследуем зависимость эффективности распределения от соотношения больших, средних и маленьких задач. Стоимость распределения определяется как m
K Q j
j 1
276
j
где Q j
I
i
и l 1 ( j ) определяет число задач, распределенных на кластер j.
Число задач
1
il ( j )
4. Численные эксперименты Была спроектирована среда моделирования для проверки упомянутых стратегий распределения. В данной главе представлены результаты численных экспериментов. Предполагается, что время выполнения известно точно и что все процессоры кластеров имеют одинаковую производительность. Рассмотрим две системы кластеров. Первая состоит из 6 кластеров (различного размера) и одного брокера. Два кластера являются большими (по 512 процессоров каждый), два имеют средний размер (по 128 процессоров) и два маленьких (по 32 процессора). Вторая система содержит 4 кластера (по 16 процессоров), 2 кластера (по 32 процессора), один кластер содержит 64 процессора, один – 128 процессоров и один – 512 процессоров. Для первой системы кластеры делятся на три типа согласно количеству процессоров: большие, средние и маленькие. Задачи разделяются похожим способом в соответствии с требуемым количеством процессоров. Предположим, что каждая задача (например, j) имеет случайное время выполнения между 10 и 300 секундами на pj процессорах, причем L% задач соответствуют большим задачам (256
1000 400 300 300
Плотность распределения CHP MCT 0,7625 0,7828 0,1166 0,1328 0,2256 0,2324 0,4203 0,4175
Стоимость распределения CHP MCT 6,2194E7 6,4130E7 0,3262E7 0,4604E7 1,2691E7 1,3583E7 4,6241E7 4,5942E7
Таблица 1 Неотсортированная очередь. Кластеры имеют размеры: 128, 128, 256, 256, 512, 512 процессоров.
Все задачи маленькие Средние Большие
1000 400 300 300
Плотность распределения CHP MCT 0,8475 0,8435 0,1205 0,1181 0,2533 0,2517 0,4737 0,4737
Стоимость распределения CHP MCT 7,0046E7 6,9760E7 0,3528E7 0,3406E7 1,4393E7 1,4230E7 5,2125E7 5,2125E7
Таблица 2 Отсортированная очередь. Кластеры имеют размеры: 128, 128, 256, 256, 512, 512 процессоров. Число задач Все задачи маленькие Средние Большие
1000 500 400 100
Плотность распределения CHP MCT 0,8042 0,8434 0,1863 0,1985 0,4223 0,4417 0,1955 0,2031
Стоимость распределения CHP MCT 5,1061E7 5,3517E7 0,8394E7 0,7632E7 2,6191E7 2,8768E7 1,6475E7 1,7117E7
Таблица 3 Неотсортированная очередь. Кластеры имеют размеры: 128, 128, 256, 256, 512, 512 процессоров. Число задач Все задачи маленькие Средние Большие
1000 500 400 100
Плотность распределения CHP MCT 0,8441 0,8460 0,1250 0,1317 0,4457 0,4408 0,2734 0,2734
Стоимость распределения CHP MCT 5,2175E7 5,2392E7 0,2640E7 0,2903E7 2,6501E7 2,6457E7 2,3033E7 2,3033E7
Таблица 4 Отсортированная очередь. Кластеры имеют размеры: 128, 128, 256, 256, 512, 512 процессоров. В таблицах 5-6 представлены результаты для второй системы, которая состоит из 4 кластеров по 16 процессоров, 2 кластеров по 32 процессора, одного кластера из 64 процессоров, одного кластера из 128 процессоров и одного кластера из 512 процессоров. Каждая задача имеет случайное время выполнения между 10 и 300 секундами. Все задачи маленькие (0< pj128). Число задач маленькие
1000
Плотность распределения CHP MCT 0,9004 0,9219
Стоимость распределения CHP MCT 8,9449E7 9,0216E7
Таблица 5 Неотсортированная очередь. Кластеры имеют размеры: 16, 16, 16, 16, 32, 32, 64, 128, 512 процессоров. 277
278
Число задач маленькие
1000
Плотность распределения CHP MCT 0,9447 0,9169
Стоимость распределения CHP MCT 9,0501E7 8,9466E7
Таблица 6 Отсортированная очередь. Кластеры имеют размеры: 16, 16, 16, 16, 32, 32, 64, 128, 512 процессоров.
5. Заключительные замечания Вычислительные эксперименты показывают, что предложенная иерархическая система независимых брокеров может производить эффективное распределение, даже если она использует сравнительно простые алгоритмы распределения. Достигнутая плотность распределения составляет как минимум 75%. Показано, что препроцессорный шаг, когда задачи сортируются по ширине, улучшает плотность распределения на 10%. Дополнительным фактором, влияющим на качество распределения, является соотношение между большими и дешевыми задачами: чем дешевле задачи, тем больше эффективность. Используя лучшие алгоритмы упаковки (для кластеров) и позволяя задачам мигрировать с одного кластера на другой, брокер может увеличить эффективность распределения. Это является предметом дальнейших исследований. Таким образом, интересно рассмотреть следующие вопросы:
1) как нечеткие значения эффективность?
времени
выполнения
влияют
на
Задачи имеют только оценочное время выполнения [11]. Интересно предположить, что время выполнения каждой задачи – случайная величина, распределенная в некотором интервале. При таких предположениях ожидаемое время выполнения становится «нечетким».
2) насколько использование лучших алгоритмов упаковки может улучшить эффективность распределения? 3) Как миграция задач с одного кластера на другой влияет на эффективность распределения? В данном случае задача может быть возвращена брокеру (возможно с некоторым штрафом), если кластер получит больше выгодных задач от других брокеров. Брокер может перераспределить возвращенную задачу на другой кластер. Интересно исследовать также случай “гибких” задач, когда число процессоров для задачи не задается заранее пользователем, а может выбираться брокером.
2. L. Hluchy, V.D. Tran, D. Froehlich, and W. Castaings, Methods and Experiences of Parallelizing Flood Models, The 10th EuroPVM/MPI conference. LNCS 2840. Sept. 2003, Venice. pp. 677-681. 3. B.S. Baker, D.J. Brown and H.P. Katseff, A 5/4 algorithm for two-dimensional packing, J. of Algorithms, 1981, v. 2, pp. 348-368. 4. B.S. Baker, E.J. Coffman and R.L. Rivest, Orthogonal packings in two dimensions, SIAM J. Computing, 1980, v. 9, pp. 846-855. 5. R. Buyya, D. Abramson, J. Giddy, An Economy Driven Resource Management Architecture For Global Computational Power Grids, International Conference on Parallel and Distributed Processing Techniques and Applications, 2000. 6. E.J. Coffman, M.R. Garey, D.S. Johnson and R.E. Tarjan, Performance bounds for leveloriented two-dimensional packing algorithms, SIAM J. Computing, 1980, v. 9, pp. 808826. 7. The Global Grid Forum. http://www.gridforum.org 8. Foster, C. Kesselman, editors. The Grid: Blueprint for a future computing infrastructure, Morgan Kaufmann, San Fransisco, 1999. 9. K. Czajkowski, S. Fitzgerald, I. Foster, C. Kesselman, Grid Information Services for Distributed Resource Sharing, 10th IEEE International Symposium on High-Performance Distributed Computing, 2001. 10. M. Drozdowski, Scheduling multiprocessor tasks - an overview, European J. of Oper. Research, 1996, v. 94, pp. 215-230. 11. S. Orlando, P. Palmerini, R. Perego, F. Silvestri, Scheduling high performance data mining tasks on a data Grid environment, Euro-Par 2002, LNCS 2400, Springer-Ferlag Berlin Heidelberg 2002, pp. 375-384. 12. K. Jansen, Scheduling malleable parallel tasks: an asymptotic fully polynomial-time approximation scheme, Proc. European Symposium on Algorithms, ESA, 2002. 13. C. Kenyon and E. Remila, A near optimal solution to a two-dimensional cutting stock problem, Mathematics of Operations Research, 25 (2000), 645-656. 14. W. Ludwig and P. Tiwari, Scheduling malleable and nonmalleable parallel tasks, Proc. 5th ACM-SIAM Symposium on Discrete Algorithms, SODA (1994), 167-176. 15. D.D.Sleator, A 2.5-times optimal algorithm for bin packing in two dimensions, Inf. Processing Letters, 1980, v. 10, pp. 37-40. 16. A.V. Fishkin, G. Zhang, On maximizing the throughput of multiprocessor tasks, Proceedings 27th International Symposium on Mathematical Foundations of Computer Science (MFCS'02), Warszawa - Otwock, Poland, LNCS 2420, Springer Verlag: Berlin, 2002, 269-279. 17. R. Wolski, Dinamically forecasting network performance using the network weather service, Cluster Computing (1998). 18. Abraham, R. Buyya, B. Nath, Nature's heuristics for scheduling jobs on Computational Grids, International Conference on Advanced Computing and Communications (2000). 19. N. Sample, P. Keyani, G. Wiederhold, Scheduling under uncertainty: Planning for the Ubiquitois Grid, International Conference on Coordination models and languages (2002).
Литература 1. P. Brucker, Scheduling Algorithms, Springer Ferlag (1998), 217-218.
279
280