Предисловие В очередном томе «Трудов Института» представлены статьи, посвященные различным аспектам системного программирования: организации компиляторов и систем программирования, защите программных средств от различного рода атак, тестированию программного обеспечения на основе формальных спецификаций, автоматизации создания программного обеспечения на основе формализованных описаний аппаратуры, модельноориентированной разработке программных систем, интеллектуальному анализу данных. В статье А. Белеванцева, М. Кувыркова, Д. Мельника «Использование параллелизма на уровне команд в компиляторе для Intel Itanium» описывается выполненная авторами разработка и реализация алгоритма эффективной генерации команд раннего выполнения (speculative execution). Технология раннего выполнения – это одна из особенностей EPIC (Explicitly Parallel Instruction Computing), заключающаяся в возможности опережающего выполнения команд, которые используют данные из памяти, что помогает “скрывать” задержки чтения данных и лучше переупорядочивать поток команд. В статье описывается предложенный авторами алгоритм генерации инструкций раннего выполнения, а также приводятся методы, используемые авторами для улучшения эффективности раннего выполнения на основании данных анализа указателей. В статье П. Довгалюка «Разреженная модель базовых блоков для оптимизации потоков команд» предлагается модель для описания потоков команд в базовых блоках. Модель ориентирована на задачи оптимизации потоков команд по скорости их исполнения. Подобные модели применяются с целью получения кратчайшего по времени расписания команд, поступающих на конвейер процессора. Статья С. Гайсаряна и К Долговой «Разработка системной поддержки вызова программ, реализованных на языке Fortran, из среды Java посвящена исследованию возможности вызова программ, реализованных на языке Fortran 95, из среды Java. Чтобы среды могли обмениваться данными, должно иметься отображение данных одной среды на данные другой. В статье представлено описание отображения данных языка Fortran на данные языка Java и обратно. Также описывается способ эффективной передачи данных из среды Java в среду Fortran и обратно. Помимо этого, в статье рассматривается метод организации вызова подпрограмм, реализованных на языке Fortran из окружения Java. В статье П. Бойко «Метод виртуального процессора в защите программного обеспечения» рассматривается метод защиты программного обеспечения от изучения с помощью переноса защищаемого кода в виртуальную среду 5
исполнения. Проводится анализ эффективности, а так же анализ недостатков метода. Предлагается вариант реализации, позволяющий снизить себестоимость разработки. Статья В. Несова и О. Маликова «Использование информации о линейных зависимостях для обнаружения уязвимостей в исходном коде программ» посвящена некоторым аспектам реализации метода обнаружения потенциальных уязвимостей в программе на основе статического потоковочувствительного анализа потоков данных. Серьезной проблемой этого метода является большое количество ложных предупреждений. Часто ложные предупреждения вызваны недостаточной точностью определяемой информации об атрибуте – значение некоторой переменной (объекта программы). Самым простым подходом определения информации о целочисленных значениях является анализ на основе интервальных оценок. Предлагаемый авторами подход состоит в поддержании системы линейных неравенств, выполняющихся для числовых атрибутов в данной точке программы. В статье В. Владимирова «Критерии полноты тестового покрытия в генетических алгоритмах генерации тестов». В статье описывается применение генетических алгоритмов для автоматической генерации тестов. Проводится анализ некоторых широко распространённых критериев полноты на предмет их применимости для построения тестов с помощью генетических алгоритмов. Строятся оценочные функции, соответствующие этим критериям. Статья С. Грошева «Применение технологии UniTesK для тестирования систем с различной конфигурацией активных потоков управления» посвящена особенностям тестирования различных конфигураций активных потоков с помощью технологии тестирования UniTesK. В статье исследуются возможности использования технологии тестирования UniTesK для построения тестов с различной конфигурацией потоков управления, систематизируется опыт тестирования различных конфигураций активных потоков, разрабатываются подходы для случаев, на которые технология UniTesK в существующем на данный момент виде не рассчитана. В статье А. Демакова, С. Зеленова и С. Зеленовой «Генерация тестовых данных сложной структуры с учетом контекстных ограничений» представлена технология автоматической генерации тестовых данных сложной структуры, обеспечивающая возможность тонкой настройки процесса генерации тестовых данных и оптимизации этого процесса под особенности функциональности конкретного тестируемого приложения. Подход основан на использовании формального описания данных сложной структуры. В статье В. Мутилина «Паттерны проектирования тестовых сценариев» рассматриваются вопросы использования типовых решений (паттернов проектирования) для построения тестовых программ, основанных на обобщенных моделях тестируемых систем в форме неявно заданных конечных автоматов. 6
В статье С. Зеленова и Д. Силакова «Автоматическая генерация тестовых данных для оптимизаторов графических моделей» предлагается метод GraphOTK автоматической генерации тестовых данных для тестирования оптимизирующих трансляторов графических моделей. Это метод позволяет решить проблему автоматической генерации тестовых данных, а также за счет параметризации генератора позволяет варьировать количественные и качественные характеристики получаемых тестовых данных. В статье В. Рубанова и А. Михеева «Интегрированная среда описания системы команд встраиваемых процессоров» рассматривается интегрированная среда MetaDSP для описания системы команд встраиваемых процессоров. Такое описание включает спецификацию синтаксиса и поведения команд процессора и позволяет автоматически настроить набор кросс-инструментария разработки (ассемблер, дисассемблер, симулятор, отладчик), а также сгенерировать документацию прикладного программиста для целевого процессора. Эти возможности позволяют использовать MetaDSP и соответствующий настраиваемый кросс-инструментарий на этапе дизайна аппаратуры для прототипирования встраиваемых процессоров. В статье Ю. Фонина «Использование языков описания процессоров высокого уровня для генерации платформо-зависимых частей операционной системы» анализируются языки описания архитектур процессора, рассматриваются основные элементы микропроцессора, а также выделяются базовые элементы архитектуры процессора, необходимые для генерации ядра операционной системы, их параметры и свойства. В статье Е. Волковой и А. Страбыкина «Анализ и трансформации исполняемых UML моделей» рассматриваются конечные автоматы языка UML, предлагается подход к анализу исполняемых моделей UML. На основании выборки моделей, использованных в промышленных проектах, исследуются их количественные свойства и демонстрируется актуальность трансформации моделей. Выделяются образцы, часто используемые при построении автоматов. Предлагаются новые трансформации, улучшающие структуру модели, описывается процесс их применения к реальной системе. В статье А. Волкова «Использование ролей в сценариях взаимодействия» рассматривается возможность систематического использования понятия роли в сценариях взаимодействия и исследуются средства, позволяющие строить общее поведение для объектов моделируемой системы по их поведению в различных ролях. Для представления сценариев используется модель взаимодействий UML (UML Interactions). В качестве абстрактных моделей для описания общего поведения объектов рассматриваются автоматные модели и модели, основанные на сетях Петри, в нотации UML (машины состояний и активности соответственно). Целью статьи Г. Маракаевой «Применение методов выявления закономерностей для классификации химических соединений» является постановка задачи классификации неизвестных химических соединений. С 7
помощью классификации выявляются признаки, характеризующие группу, к которой принадлежит тот или иной объект. Это делается посредством анализа уже классифицированных объектов и формулирования некоторого набора правил. Целью различных алгоритмов классификации, обзор которых приводится в статье, является построение классификационной модели, которая будет предсказывать класс для заданного примера на основании имеющихся значений атрибутов. Наконец, завершающая сборник статья В.В. Кулямина, В.А. Омельченко и О.Л. Петренко «Формирование профессиональных компетенций современного разработчика ПО» посвящена обоснованию эффективности применения активных методов обучения передовым технологиям разработки программного обеспечения, в частности, формальным методам. Предоставлено несколько примеров таких методов, которые подталкивают студентов к активному мышлению и использованию получаемых при обучении знаний в практической деятельности. Замечу, что наряду с изданием ежегодного сборника «Трудов Института» ИСП РАН регулярно издает препринты, в которых публикуются более объемные работы сотрудников Института. В частности, одновременно с настоящим сборников публикуются препринты А. Болдакова и М. Гринева «Расширение языка XQuery функциональными update-выражениями» и П. Плешачкова «SXTM: Высокопроизводительный менеджер управления XMLтранзакциями». Эти работы, как и многие исследования, результаты которых публикуются в сборнике, поддержаны грантами РФФИ, Министерства науки и образования и президиума РАН. Член-корреспондент РАН
8
В.П. Иванников
Использование параллелизма на уровне команд в компиляторе для Intel Itanium А. Белеванцев, М. Кувырков, Д. Мельник
1. Введение Современные микропроцессоры обладают достаточными ресурсами для выполнения нескольких инструкций за один такт. Для того, чтобы достичь хорошей производительности на таких процессорах, нужно уметь находить в программе инструкции, которые могут выполняться независимо. Обычно эту задачу называют обнаружением параллелизма на уровне команд (ILP, instruction level parallelism). Суперскалярные процессоры решают задачу нахождения ILP динамически в процессе выполнения программы. Программа для этих процессоров не содержит сведений о том, какие инструкции могут выполняться независимо, и вся нагрузка по нахождению оптимального “плана” выполнения ложится на аппаратуру. Чем больше команд процессор может выдать за такт, тем сложнее в реальном времени обнаружить оптимальную последовательность выполнения команд. Для того, чтобы преодолеть эти ограничения, фирмой Intel была предложена архитектура EPIC (Explicitly Parallel Instruction Computing [1]) с очень длинным командным словом, реализованная в процессорах семейства Itanium. Идея EPIC состоит в том, чтобы переложить задачу по поиску ILP на компилятор. EPIC-программа содержит явные указания на то, какие инструкции можно выполнять параллельно, а EPIC-процессор в точности следует тому плану выполнения, который задает программа. При этом его основной задачей становится обеспечение работы конвейера, и необходимость в аппаратной реализации сложной логики поиска независимых инструкций отпадает. С другой стороны, отдавая компилятору задачу определения наилучшего плана выполнения программы, архитектура должна предоставить компилятору широкие возможности по управлению ходом выполнения программы. EPIC дает возможность компилятору (помимо явного указания на независимость определенных команд) предсказывать ветвления, влиять на работу кэша, избавляться от коротких ветвлений, выполнять команды с опережением и некоторые другие. Кроме того, предоставляется значительный объем ресурсов 9
– большой регистровый файл и много параллельно работающих функциональных устройств. Из перечисленного списка особенностей архитектуры видно, что создание оптимизирующего компилятора для EPIC является принципиально иной задачей, чем оптимизация под традиционные последовательные архитектуры. Компилятор для EPIC должен уметь выразить как можно больше параллелизма на уровне команд, создавая эффективный план выполнения программы с учетом всех возможностей архитектуры, и упаковать эти команды в длинные слова. При этом задачи, возникающие при использовании свойств архитектуры, ранее в компиляторах не ставились, и методы их решения до сих пор в полной мере не разработаны. Целью нашей работы является разработка и реализация алгоритма эффективной генерации команд раннего выполнения (speculative execution). Технология раннего выполнения – это одна из особенностей EPIC, заключающаяся в возможности опережающего выполнения команд, использующих данные из памяти, что помогает “скрывать” задержки чтения данных и лучше переупорядочивать поток команд. В данной статье мы описываем предлагаемый нами алгоритм генерации инструкций раннего выполнения, а также приводим методы, которые используются нами для улучшения эффективности раннего выполнения на основании данных анализа указателей. Кроме того, мы обсуждаем результаты тестирования реализации алгоритма для компилятора GCC [2] на пакете SPEC CPU 2000.
2. Реализация раннего выполнения на Intel Itanium В этом разделе мы описываем технику раннего выполнения, а также ее реализацию в процессорах Itanium. Далее под инструкцией (или командой) мы понимаем одну операцию, выполняемую процессором. Процессоры семейства Intel Itanium [3] являются реализацией архитектуры EPIC с очень длинным командным словом (VLIW – Very Long Instruction Word). Каждое такое командное слово представляет собой пакет инструкций, который включает в себя 3 инструкции, и задает шаблон, который указывает процессору, на каком функциональном устройстве следует выполнять каждую из инструкций. Itanium 2 имеет более 20 функциональных устройств, которые могут работать параллельно. Пакеты инструкций объединяются в группы инструкций (далее – просто группы), каждая из которых может быть выполнена за 1 такт работы процессора (всего до двух групп за 1 такт). Группы разделяются между собой стоп-битами, которые являются частью кода шаблона; в текущей реализации в одной группе может быть до двух пакетов. Задача компилятора по выявлению ILP состоит в явном указании шаблонов пакетов и границ групп инструкций (с помощью стоп-битов). Шаблоны указывают процессору, куда 10
требуется распределить инструкции, а группы явно указывают, какие инструкции можно выполнять независимо. Для того, чтобы эффективно использовать параллелизм на уровне команд, имеющийся в программе, необходимо иметь как можно большую свободу перемещения инструкций между группами с тем, чтобы максимально использовать все функциональные устройства, доступные во время выполнения каждой группы. Возможности по перемещению инструкций компилятором ограничиваются зависимостями инструкций по данным и по управлению. Тем не менее, часто бывает, что точно определить наличие зависимости в момент компиляции нельзя, но можно с большой вероятностью утверждать, что зависимости нет. При обычном планировании компилятор в таких случаях обязан предполагать наличие зависимости, чтобы сохранить корректность программы. Архитектура EPIC позволяет компилятору игнорировать такие зависимости, поддерживая технику раннего выполнения (speculative execution). Компилятор может выдать инструкции раньше, чем позволило бы наличие зависимости, но должен сгенерировать код восстановления (recovery code), который обеспечит корректное выполнение программы, если зависимость окажется реальной. В случае отсутствия зависимости использование раннего выполнения позволяет скрыть задержки операций загрузки из памяти и уменьшить время выполнения программы. До:
После:
/* Процессор простаивает */
/* Загрузить раньше */
...
До:
После:
...
/* Выдать загрузку раньше */
/* Процессор простаивает */
store(st_addr, data) load(ld_addr, target)
if (a>b) { load(ld_addr, target)
/* Если ld_addr и st_addr различны, можно работать с данными, иначе перейти на код восстановления */
use(target)
acheck(target, recovery) use(target)
Рис. 2. Пример раннего выполнения (устраняется зависимость по данным)
if (a>b) { /* Проверить, было ли исключение */
/* Дождаться окончания загрузки */
scheck(target, recovery) /* Если нет, сразу работать с данными */
use(target)
aload(ld_addr, target) store(st_addr, data)
/* Дождаться окончания загрузки */
...
sload(ld_addr, target)
}
могут быть перемещены. Перед использованием результатов перемещенных команд должна быть выполнена проверочная инструкция, определяющая, действительно ли была зависимость. Если результат проверки положителен, то проверочная инструкция выполняет переход на код восстановления (см. примеры на рисунках 1 и 2).
use(target) }
Рис. 1. Пример раннего выполнения (устраняется зависимость по управлению) Существует два вида раннего выполнения: один направлен на устранение зависимостей по данным (data speculation), другой – зависимостей по управлению (control speculation). Первый состоит в перемещении операции загрузки из ячейки памяти выше операции записи в некоторую ячейку, адрес которой может пересекаться с адресом загрузки. Второй состоит в перемещении операции загрузки из памяти выше операции ветвления. Инструкции, в которых используется результат операции загрузки, также 11
В системе команд Itanium раннее выполнение поддерживается двумя группами инструкций, для преодоления зависимостей по данным и по управлению. К первой группе относятся инструкции ld.a (расширенная команда загрузки), а также ld.c и chk.a (проверка выполненной ранней загрузки), ко второй – соответственно ld.s и chk.s. При устранении зависимости по данным необходимо убедиться, что адреса ячеек памяти, указатели на которые создают эту зависимость, не совпадают в момент выполнения программы. Для этого инструкция ld.a, выполняя раннюю загрузку операнда из памяти, сохраняет фактический адрес ячейки памяти, из которой загружалось значение, в специальной таблице адресов – ALAT (Advanced Load Address Table – таблица адресов ранней загрузки). Эта таблица индексируется по номеру регистра, в который выполнялась загрузка. Операции записи по адресу, перекрывающемуся со значением одной из ячеек в таблице ALAT, а также выполнение ранней загрузки в тот же регистр удаляет предыдущее значение соответствующей ячейки. При выполнении инструкции проверки ранней загрузки ld.c с тем же номером регистра назначения, в таблице адресов ранней загрузки выполняется поиск значения с индексом, равным номеру этого регистра. Если такого значения не найдено, то считается, что была выполнена конфликтующая 12
операция записи. Следовательно, раннее выполнение не удалось, и инструкция загрузки выполняется еще раз. В случае команды chk.a происходит переход на ранее сгенерированный компилятором код восстановления. При устранении зависимости по управлению достаточно гарантировать, что в случае возникновения исключительной ситуации при выполнении ранней загрузки она будет возбуждена в корректном месте программы. Для этого инструкция ld.s, выполняя раннюю загрузку в некоторый регистр, при возникновении исключительной ситуации устанавливает для него специальный флаг NaT (Not a Thing), который свидетельствует о наличии отложенного исключения. Этот флаг может быть установлен для любого регистра общего назначения. Если этот флаг был установлен для какого-либо регистра, то он также будет установлен для всех регистров, значения которых были получены с помощью вычислений, использовавших значение первого регистра. Если впоследствии проверочная инструкция chk.s обнаруживает, что для ее операнда регистра установлен флаг NaT, то она передает управление на код восстановления, который должен устранить последствия неудачной попытки раннего выполнения. Примеры ассемблерного кода с использованием раннего выполнения приведены на рис. 3. Программа с инструкциями Исходная программа раннего выполнения ld8.a r18=[r19];; adds r15=r16,r14 adds r15=r16,r14 st8 r14=[r14] nop.i nop.i st8 r14=[r14] ld8 r18=[r19];; ld8.c.clr r18=[r19] st4 r15=[r33] nop.i;; nop.i ld8 r14=[r18];; ld8 r14=[r18];; st4 [r15]=r33 а) преодоление зависимостей по данным Исходная программа
Программа с инструкциями раннего выполнения adds r14=1,r8 mov r1=r42 ld4.s r15=[r33] adds r14=1,r8;; mov r1=r42;; cmp4.ltu p6, r14 cmp4.ltu p6,r14 (p6) br.cond bd0 (p6) br.cond bf0 ld4 r14=[r33];; chk.s.m r15,b40;; add r14=r14,r8 add r15=r15,r8 б) преодоление зависимостей по управлению
Избыточная генерация инструкций раннего выполнения зачастую может не только не дать выигрыша в производительности, но и наоборот, привести к ухудшению производительности программы, т.к. в случае неудачного раннего выполнения необходимо будет выполнять загрузку из памяти повторно, или выполнять дополнительный код восстановления. Использование информации, полученной с помощью анализа указателей, во многих случаях дает возможность оценить целесообразность генерации инструкций раннего выполнения, что позволяет генерировать такие инструкции только в тех местах, где это действительно необходимо.
3. Алгоритм генерации инструкций раннего выполнения Инструкции раннего выполнения порождаются компилятором в процессе планирования. В этом разделе описывается, как нужно изменить планировщик, чтобы он мог поддерживать раннее выполнение. Предполагается, что планировщик может оперировать регионами из нескольких базовых блоков (иначе не появляется зависимостей по управлению и раннего выполнения для них). При описании того, как меняется собственно алгоритм планирования, мы предполагаем, что планировщик принадлежит к классу алгоритмов списочного планирования (list scheduling [4]). Для моделирования раннего выполнения в планировщике инструкций введем понятие блока раннего выполнения. Некоторые инструкции могут порождать начало таких блоков (например, загрузки из памяти). Затем могут следовать несколько инструкций, использующих результат загрузки (первой инструкции блока). Блок завершается специальными инструкциями проверки (такими как ld.c и chk.s). Таким образом, блок раннего выполнения формируется из операций ранней загрузки и проверки, и может включать несколько использований результата ранней загрузки. Алгоритм поддержки раннего выполнения в планировщике имеет своей целью корректное создание и наполнение блоков раннего выполнения наравне с планированием обычных инструкций. Для этого необходимо решить следующие подзадачи: расширение структур данных планировщика, хранящих сведения об инструкциях и зависимостях, данными раннего выполнения; инициализация новых структур данных; планирование инструкций раннего выполнения; поддержка планирования машинно-зависимой частью компилятора. Далее мы подробно описываем решение каждой из этих задач.
Рис. 3. Примеры ассемблерного кода с командами раннего выполнения 13
14
3.1. Расширение и инициализация структур данных
3.2. Планирование инструкций раннего выполнения
Для отражения свойств инструкций и зависимостей, связанных с ранним выполнением, в структуры данных планировщика, представляющие инструкции и зависимости между ними, включены флаги раннего выполнения (см. таблицу 1). Наличие флага раннего выполнения для зависимости означает, что для преодоления данной зависимости можно использовать раннее выполнение. Аналогично, такой флаг для инструкции означает, что она может быть запланирована альтернативным способом – с использованием раннего выполнения. Также специальными флагами помечаются инструкции, которые более предпочтительны для раннего выполнения, либо, наоборот, не должны в нем участвовать.
Планировщиком семейства list scheduling непосредственно для планирования используется список готовых инструкций. Инструкция может быть помещена в этот список при начале планирования, либо после того, как запланирована предыдущая инструкция и удовлетворены зависимости по данным. Из списка выбирается (обычно руководствуясь набором эвристик) наилучшая для планирования в данный момент инструкция, которая выдается на планирование и удаляется из списка, а зависимые от нее инструкции добавляются в список. Процесс повторяется до тех пор, пока не будут запланированы все инструкции. С точки зрения планировщика, все истинные зависимости по памяти могут быть потенциально устранены с помощью раннего выполнения по данным. Дополнительное ограничение накладывает архитектура машины, которая может поддерживать раннюю выдачу лишь некоторых инструкций (в Itanium это команды загрузки из памяти). За проверку этого ограничения отвечает машинно-зависимая часть компилятора. Аналогично, любая инструкция из последующих базовых блоков может быть выполнена в планируемом блоке с помощью раннего выполнения по управлению, если это поддерживается целевой машиной. Это ограничение проверяется при каждом перемещении инструкции в список для планирования и далее в этом разделе не упоминается.
Флаг
Зависимость может быть устранена с помощью:
Инструкция может быть:
BE_IN_DATA BE_IN_CONTROL
ранняя загрузка с помощью ld.a ранняя загрузка с помощью ld.s использование результата ранней загрузки
FINISH_DATA
–
использование результата ранней загрузки ld.c
FINISH_CONTROL
–
chk.s
HARD_DEP
невозможно устранить
WEAK_DEP
ранняя загрузка предпочтительна
ранняя загрузка не может быть использована ранняя загрузка предпочтительна
BEGIN_DATA BEGIN_CONTROL
ld.a ld.s
3.2.1. Помещение в список планирования.
Таблица 1. Флаги раннего выполнения Инициализация флагов происходит перед началом планирования, когда работает анализ зависимостей по данным. Все, так называемые, истинные зависимости по памяти (команда, читающая данные из памяти, зависит от ранее выполняемой команды записи этих данных) помечаются анализом зависимостей флагом BEGIN_DATA. Некоторые зависимости при этом помечаются флагом HARD_DEP (например, зависимости, возникающие при волотильных обращениях в память). Флаг зависимости по управлению BEGIN_CONTROL, BE_IN- и FINISH- флаги, а также флаги раннего выполнения для инструкций устанавливаются в процессе планирования при анализе их зависимостей.
15
Рассмотрим, как изменяется процесс добавления инструкций в список готовых к планированию. Пусть инструкция находится в том же базовом блоке, который сейчас планируется. Тогда она может быть добавлена в список, если у нее нет зависимостей, либо все ее зависимости помечены флагами BEGIN_DATA либо BE_IN_DATA. Такая инструкция при помещении в список также помечается одним из этих флагов. Если же инструкция находится в другом базовом блоке, то возможны три случая. В первом случае у инструкции нет зависимостей по данным, и она не может возбудить исключение – перемещение такой инструкции не нарушает корректность программы, и она сразу помещается в список. Во втором случае инструкция может создать исключение, но не имеет зависимостей. Эта инструкция может быть помещена в список для раннего выполнения по управлению, если вероятность выполнения ее базового блока относительно текущего высока, и в этом случае она помечается флагом BEGIN_CONTROL. В третьем случае у инструкции есть зависимости по данным. Если все такие зависимости помечены флагами BEGIN_DATA либо BE_IN_DATA, тогда, аналогично двум предыдущим случаям, в зависимости от того, может или нет инструкция возбудить исключение, она может быть помещена в список с флагом (либо без флага) BEGIN_CONTROL и с флагами, соответствующими флагам ее зависимостей. Если же зависимости инструкции устранить 16
невозможно (флаг HARD_DEP), то она не может быть помещена в список планирования.
3.2.2. Сортировка списка планирования. После формирования списка готовых инструкций он сортируется в соответствии с эвристиками планировщика. Затем из списка выбирается инструкция, планирование которой позволит выдать наибольшее число инструкций в текущем цикле. Для определения приоритетов среди инструкций раннего выполнения при планировании используются следующие эвристики: обычная инструкция всегда предпочитается инструкции раннего выполнения; инструкция раннего выполнения по данным предпочитается инструкциям раннего выполнения по управлению; если обе инструкции раннего выполнения устраняют зависимости по данным, то вычисляется оценка того, какие из зависимостей наименее вероятны. Эта оценка является суммой оценок вероятностей каждой зависимости инструкции. Вероятность зависимости в свою очередь является степенью “слабости” зависимости (понятие слабых зависимостей подробнее рассматривается в следующем разделе); если обе инструкции являются инструкциями раннего выполнения по управлению, то предпочитается инструкция с наибольшей вероятностью выполнения.
3.2.3. Выдача инструкций раннего выполнения Выдача инструкций раннего выполнения происходит следующим образом. Инструкция, помеченная одним из флагов BEGIN_* (загрузка из памяти в случае Itanium) разбивается на две части: инструкцию раннего выполнения и инструкцию проверки. Все зависимости исходной инструкции (как прямые, так и обратные), переносятся на инструкцию проверки, а также добавляется зависимость между инструкциями раннего выполнения и проверки. При этом обратные зависимости с флагом HARD_DEP изменяются на зависимости BE_IN_*. Инструкция раннего выполнения планируется на текущем цикле, а инструкция проверки помечается как последняя инструкция блока раннего выполнения (FINISH_*), и планируется позже, как обычная инструкция. Кроме того, при планировании инструкций, создающих новый блок раннего выполнения, также создается новый блок, который будет содержать код восстановления, и в него помещается копия спланированной инструкции. Для данной копии создается зависимость от инструкции проверки типа HARD_DEP, которая обеспечивает планирование кода восстановления после проверочной инструкции. При выдаче инструкции, содержащейся внутри блока раннего выполнения (помеченной флагами BE_IN_*), аналогично ее зависимости также изменяют 17
свой тип с BEGIN_* на BE_IN_*, и копия инструкции помещается в уже созданный блок восстановления. При этом BE_IN_* зависимости инструкции, которые были устранены при планировании, перемещаются на копию инструкции, чтобы указать планировщику зависимость копии инструкции от уже содержащихся в блоке восстановления инструкций. При выдаче инструкции проверки, завершающей блок раннего выполнения, соответствующий блок восстановления закрывается и добавляется к текущему региону для последующего планирования аналогично обычным базовым блокам. Если блок выполнения состоит из одной инструкции, то возможна ситуация, когда задачу восстановления выполнит сама инструкция проверки (в случае Itanium это возможно для ld.c). Тогда блок восстановления уничтожается.
3.3. Машинно-зависимая поддержка раннего выполнения При разработке алгоритма раннего выполнения мы ориентировались на мультиплатформенный компилятор, подобный GCC. Для этого машиннозависимые части поддержки раннего выполнения были выделены отдельно. Если необходимо реализовать поддержку для определенной платформы, то модуль компилятора, реализующий кодогенерацию для этой платформы, должен предоставить следующие возможности (реализованные в виде процедур): запрос о том, какие типы раннего выполнения (в терминах введенных нами флагов) поддерживает архитектура; запрос о том, поддерживает ли архитектура раннее выполнение данной инструкции; запрос на преобразование инструкции, подготавливаемой к раннему выполнению определенного типа, к виду (во внутреннем представлении), который она примет при раннем выполнении. Для Itanium, например, при передаче инструкции загрузки из памяти в качестве параметра необходимо вернуть инструкцию во внутреннем представлении, соответствующую ld.s или ld.a; запрос на создание инструкции проверки для данного типа раннего выполнения; запрос на то, нужен ли блок восстановления для данной инструкции данного типа раннего выполнения, или же можно обойтись инструкцией проверки; запрос на расширение структур данных при создании новых инструкций (нового базового блока). Кроме того, для всех типов инструкций раннего выполнения необходимо задать их вид в ассемблере целевой машины для кодогенератора, а также время выполнения (латентность) и занимаемые функциональные устройства для того, 18
чтобы планировщик мог оценивать состояние конвейера целевой машины в процессе планирования.
4. Реализация алгоритма раннего выполнения в компиляторе GCC
3.4. Использование анализа указателей для эффективности раннего выполнения
Данный подход был реализован в компиляторе GCC на основе серии 4.х (в настоящий момент еще не вышедшей). Логика планирования инструкций раннего выполнения и расширение структур данных планировщика были реализованы так, как описано в разделе 3. В кодогенераторе GCC для процессоров Itanium были описаны ассемблерные формы инструкций раннего выполнения. Кроме того, был исправлен ряд недочетов и сделано несколько улучшений планировщика, не связанных непосредственно с основным алгоритмом: структуры данных планировщика не были рассчитаны на то, что в процессе планирования могут появиться новые инструкции. Нами был предусмотрен ряд процедур, осуществляющих расширение этих структур на лету; планировщик не поддерживал граф потока управления в консистентном состоянии, что не позволяло добавлять блоки восстановления к планируемым регионам; планировщик также не поддерживал консистентность информации о времени жизни регистров, так как дальнейшим оптимизациям она не была нужна. Это мешало обрабатывать инструкции раннего выполнения во время второго запуска планировщика; приоритет инструкций на стыках базовых блоков вычислялся неправильно, что не являлось проблемой до появления команд раннего выполнения. После реализации алгоритма оказалось, что при переходе к планированию следующего базового блока из-за неверного вычисления приоритета в длинное командное слово, не полностью заполненное инструкциями из предыдущего базового блока, могли попасть новые инструкции раннего выполнения, причем корректность программы нарушалась; планировщик не сохранял все типы зависимостей, а только сильнейшую зависимость между двумя инструкциями. Это может помешать корректно выдать команду раннего выполнения. Рассмотрим следующий пример:
улучшения
Данные анализа указателей могут значительно повысить эффективность планирования инструкций с поддержкой раннего выполнения, указывая планировщику, в каких случаях генерация инструкций раннего выполнения является наиболее эффективной. На основе данных анализа указателей с помощью приведенных ниже эвристик оценивается степень истинной зависимости между инструкциями. Будем говорить, что между двумя инструкциями существует слабая зависимость, если между ними с помощью консервативного статического анализа диагностируется истинная зависимость по данным, но фактически вероятность возникновения такой зависимости мала. Аналогично, будем считать, что сильной зависимостью между двумя инструкциями является такая истинная зависимость по данным, которая с достаточно большой вероятностью имеет место и во время выполнения программы. Для определения степени зависимости вычисляется эвристическая оценка, показывающая вероятность ее существования с точки зрения статического анализа. Используются следующие эвристики: два указателя, ссылающиеся на ячейки, степень зависимости которых определяется, имеют непересекающиеся множества значений, на которые они могут указывать (множества points-to), но вследствие консервативности анализа для одного из указателей известно, что он мог ссылаться по неопределенному адресу; один из указателей является прямой ссылкой, а другой – непрямой. Эта эвристика используется при ссылках на поля структуры (s.a или p->b); указатели являются различными параметрами одной функции; указатели имеют различные базовые значения, т.е. значения, относительно которых выполнялись операции над указателями, и эти базовые значения являются различными параметрами функций. Другими словами, указатели p и q имеют вид p = arg1 + offset1, q = arg2 + offset2, где arg1 и arg2 – различные аргументы функции. Аналогично, зависимость является сильной, и мы не должны пытаться «разорвать» зависимость по данным, если множества points-to соответствующих указателей пересекаются. В этом случае, как было установлено экспериментально, высока вероятность того, что раннее выполнение окажется неудачным.
19
add r3 = r3, r4 st [r6] = r4 ld r4 = [r5] Загрузка в регистр r4 не может быть перемещена для раннего выполнения в текущую точку планирования, поскольку такое перемещение нарушит обратную зависимость (anti-dependence) 20
между инструкциями ld и add. Между тем, эта зависимость может быть опущена из-за наличия прямой (истинной) зависимости у инструкции ld. Мы исправили анализ зависимостей так, чтобы сохранялись все типы зависимостей; было улучшено формирование регионов планирования. За счет нескольких дополнительных итераций (в 95% достаточно двух, а в 99% – трех итераций) по графу потока управления стало возможным формировать бóльшие регионы, что позволяет иметь лучший выбор при раннем планировании.
Результаты тестирования показывают, что раннее выполнение наиболее полезно для вычислительных задач, где применение этой техники может дать большее ускорение (до 20% и выше). Для целочисленных задач применение техники должно быть более консервативным, и стандартного анализа указателей (компилятора GCC) может не хватать. Вообще говоря, чем более консервативны настройки раннего выполнения, тем меньше ускорение для отдельных тестов, но при этом и меньше тестов, показывающих худшие результаты.
6. Заключение
5. Экспериментальные результаты Мы провели тестирование раннего выполнения на наборе тестов SPEC 2000 [5]. Использовались серверы HP rx1600 с двумя процессорами Intel Itanium 2 1.8 ГГЦ и 2 ГБ оперативной памяти. В таблице 2 приведены результаты тестирования для пакета SPEC FP c уровнем оптимизации –O3. Для сравнения приведены также данные ускорений, получаемые при включении отдельных оптимизаций. При уровне оптимизации –O3, помимо раннего выполнения, работает также и широкий набор стандартных оптимизаций компилятора GCC. По данным Только Все Оптимианализ и по вместе зация-O3 управлению указателей
Тесты
Только по данным
Только по управлению
168.wupwise
0,71%
1,43%
1,43%
1,66%
0,95%
-0,47%
171.swim
-0,30%
-0,30%
0,30%
-0,44%
-0,15%
-0,15%
172.mgrid
0,00%
0,00%
0,30%
4,79%
5,09%
-4,84%
173.applu
0,24%
0,00%
1,18%
-0,71%
-0,24%
0,95%
177.mesa
-1,09%
0,00%
2,89%
0,14%
0,82%
1,73%
178.galgel
2,51%
-5,75%
2,51%
-5,92%
-3,41%
8,76%
179.art
1,05%
0,06%
-0,17%
-0,06%
0,58%
-0,23%
183.equake
-0,90%
-0,23%
-1,13%
-0,23%
-0,45%
-2,24%
187.facerec
0,19%
0,00%
-1,12%
-3,16%
-2,99%
2,87%
188.ammp
18,84%
0,15%
18,84%
-1,52%
16,87% 20,68%
189.lucas
0,12%
-0,12%
-0,36%
-0,12%
0,00%
0,00%
191.fma3d
0,73%
-0,36%
0,36%
0,73%
2,93%
-0,72%
200.sixtrack
2,43%
0,00%
2,08%
-1,04%
1,04%
3,16%
301.apsi SPEC FP 2000
1,12%
-0,67%
0,45%
-4,45%
-3,13%
5,57%
1,71%
-0,57%
1,89%
-0,76%
1,14%
2,46%
В этой статье мы описали проблемы, возникающие при компиляции для архитектур с явно выраженным параллелизмом на уровне команд, на примере задачи поддержки раннего выполнения для Intel Itanium. Разработанный нами алгоритм реализован в компиляторе GCC и протестирован на пакете SPEC CPU 2000. Алгоритм показывает ускорение примерно в 2,5% на пакете вычислительных программ SPEC FP 2000, причем отдельное ускорение достигает 20% (для теста ammp). В наших дальнейших планах тонкая настройка алгоритма раннего выполнения, а также тестирование этого алгоритма с улучшенным анализом указателей, разработанным нами в рамках предыдущих исследований. Мы планируем включить нашу реализацию алгоритма раннего выполнения в компилятор GCC версии 4.2. Литература 1. EPIC Technology Whitepaper. http://www.intel.com/pressroom/kits/events/enterprise_server/ EPIC_white_paper.pdf 2. GNU Compiler Collection. http://gcc.gnu.org. 3. Intel(R) Itanium(R) Architecture Software Developer's Manual. http://www.intel.com/design/ itanium/manuals/iiasdmanual.htm 4. S. Muchnick. Advanced compiler design and implementation. Morgan Kaufmann, 3rd ed., 1997. 5. SPEC CPU benchmark. http://www.spec.org/cpu2000/
Таблица 2. Результаты тестирования на SPEC FP 2000 21
22
1 mov a, b
Разреженная модель базовых блоков для оптимизации потоков команд П.М. Довгалюк E-mail:
[email protected] Аннотация. Предлагаемая модель предназначается для описания потоков команд в базовых блоках. Данная модель ориентирована на задачи оптимизации потоков команд по скорости их исполнения. Подобные модели применяются с целью получения кратчайшего по времени расписания команд, поступающих на конвейер процессора.
1. Анализ существующих математических моделей вычислительных процессов в базовых блоках Существует ряд моделей вычислительных процессов в базовых блоках. Наиболее распространенные из них используют для представления базового блока направленные ациклические графы [3], [4], [5]. Во всех распространенных графовых моделях базовых блоков множество вершин соответствует множеству команд, а наличие дуги между двумя вершинами соответствует наличию зависимости между соответствующими командами (дуга (v, u) показывает, что команда v должна быть выполнена раньше команды u). Для того чтобы задать протяженность задержки между командами, в наиболее популярной модели, описанной в [3] и [5], используются числовые пометки ребер графа, соответствующие продолжительностям задержек — D((v, u)). На Рис. 1 и Рис. 2 представлен пример содержимого базового блока и его традиционное представление с помощью графа. mov a, b add c, 1 mul a, c mov d, c mul a, d Рис. 1. Пример содержимого базового блока
23
1 1
add c, 1
1 2
2
mul a, c
1
2
1
1
mov d, c
mul a, d
Рис. 2. Традиционное представление базового блока в виде графа Корректным расписанием S для систем с одним конвейером называется функция S : V N v, u E S u S v Dv, u . Таким образом, S(v) – позиция вершины v в результирующем расписании. В каждой позиции расписания может находиться либо одна инструкция, либо специальная команда NOP, которая не выполняет никаких действий. mov a, b add c, 1 mul a, c nop mov d, c mul a, d Рис. 3. Пример корректного расписания для базового блока Существует множество моделей, построенных на основе описанной выше, отличающихся различными атрибутами вершин и дуг, в зависимости от особенностей архитектуры целевых машин. В некоторых распространенных архитектурах, например Intel i860 [2], зависимости между командами могут быть ограничены по времени сверху. То есть вторая (зависящая) инструкция должна быть выполнена ровно через определенное количество тактов после первой, иначе результат выполнения первой команды будет утерян. Хотя такие виды зависимостей и описываются существующими моделями [1], [5], но эффективных алгоритмов построения расписания, создающих корректное расписание всегда, когда это возможно, для них не существует. Это объясняется тем, что такие зависимости вводятся в 24
модель с помощью специального атрибута связей. Данное расширение модели не позволяет эффективно использовать алгоритмы оптимизации, пригодные для моделей без этого атрибута [4], [5]. Эти алгоритмы в процессе работы могут заходить в тупик, генерируя некорректное расписание. Также ни в одной из наиболее распространенных моделей не учитывается тот факт, что в большинстве архитектур различные команды занимают разное количество тактов конвейера. Например, для RISC-процессоров, где все команды кодируются одним машинным словом, некоторые команды, оперирующие большими константами, могут кодироваться двумя словами. Кроме того, в традиционных моделях базовых блоков не учитываются команды перехода, имеющие неустранимые задержки. Такие задержки допустимо заполнять полезными командами, если это не приводит к конфликтам по данным. Так как такое ограничение плохо вписывается в существующие модели, то для решения этой задачи используются специальные алгоритмы [3]. Таким образом, необходимо построить модель базовых блоков, позволяющую оптимизировать вычислительный процесс и в тех случаях, когда существуют жесткие ограничения сверху на продолжительность задержки между командами, а также, если команды кодируются неодинаковым количеством слов. Кроме того, новая модель должна позволять учитывать зависимости между командами из смежных базовых блоков для конвейерной оптимизации команд перехода.
2. Разреженная модель вычислительных процессов в базовых блоках Традиционная графовая модель базовых блоков использует в качестве узлов отдельные команды целевой машины, из которых состоит базовый блок [5]. Такая модель не отражает загруженности конвейера непроизводительными вычислениями и не позволяет оперировать командами, размер которых больше одного машинного слова. Поэтому предлагается видоизменить модель базовых блоков следующим образом: в качестве узлов использовать операции, выполняемые конвейером за один такт. Такими операциями могут быть – выборка кода команды, либо непроизводительная задержка, в течение которой на конвейер не поступает новых команд. Связывать же эти операции в граф предлагается с помощью связей двух видов: задающих относительный или абсолютный порядок операций, поступающих на конвейер. Добавление узлов-задержек между командами делает граф более разреженным, что и послужило источником названия модели. Разреженную модель базовых блоков можно математически описать с помощью следующего ациклического графа: G V ; E ; s; e , где 25
V – множество узлов, соответствующих конвейерным операциям, формирующим базовый блок;
E V V – множество связей, определяющих порядок поступления узлов-операций (команд и задержек) на конвейер процессора;
s V – стартовый (корневой) узел;
e V – последний узел в любом корректном расписании, построенном на основе данного графа. Узлы в таком графе должны быть помечены соответственно их назначению – являются ли они выборками кода команды из памяти, либо непроизводительными задержками. Для решения поставленных задач необходимо ввести два вида связей между вершинами. Введем следующие определения: Определение 1: Связь называется «жесткой», если две операции, которые она соединяет должны поступать на конвейер строго друг за другом (между ними не должно быть других операций). Обозначим подмножество жестких связей как H. Определение 2: Связь называется «гибкой», если она задает лишь относительный порядок поступления операций на конвейер (между ними на конвейер могут поступать другие операции). Множество задержек введено для моделирования минимального времени между инструкциями, которое традиционно [3] представляется в виде числовой пометки дуги. В предлагаемой модели паузы между инструкциями заполняются с помощью непроизводительных операций. Формальное описание графа приведенное ниже недостаточно точно описывает модель. Для того чтобы решать задачи оптимизации потока команд с помощью данной модели, граф должен удовлетворять следующим условиям:
26
в графе существует только одна корневая вершина – s; в графе существует только один лист – e; граф является слабо связным; в графе не существует циклов, так как не могут существовать циклические зависимости по данным между инструкциями в одном базовом блоке.
1 mov a, b
1
mul a, c
1
1
1
Предлагаемая модель отличается от традиционной специальными видами узлов и связей. В отличие от традиционных моделей, в разреженной модели в качестве узлов используются однотактовые операции конвейера целевой машины. Данные операции объединяются в граф с помощью ребер двух видов – для задания относительного и абсолютного порядка операций. Разряженная модель позволяет применять единый подход при оптимизации потока команд в базовых блоках при наличии команд из нескольких машинных слов, инструкций перехода с неустранимыми задержками, а также команд с ограниченным временем жизни результата их выполнения. Эта ее особенность дает возможность оптимизировать потоки команд в базовых блоках в рамках одного универсального алгоритма, что невозможно в традиционных моделях.
add c, 1
mov d, c
Литература
mul a, d
Рис. 4. Представление базового блока с помощью разреженной модели
2.1. Моделирование машины
особенностей
архитектуры
1. Beaty, S. List scheduling: Alone, with foresight, and with lookahead. In Conference on Massively Parallel Computing Systems: the Challenges of General-Purpose and SpecialPurpose Computing (Ischia, Italy, May 1994) 2. Intel. i860 64-bit microprocessor programmer’s reference manual, 1990. 3. S. Muchnick. Advanced compiler design and implementation, 1997 4. Philip Schielke. Issues in Instruction Scheduling. Rice University, Department of Computer Science. Ph. D. Thesis Proposal 5. Bjorn De Sutter. General-Purpose Architecture Instruction Scheduling Techniques. ELIS Technical Report DG 98-09, November 1998
целевой
Такая особенность целевой машины, как инструкции, состоящие из нескольких машинных слов, может быть описана с помощью нескольких последовательных узлов-операций, соединенных жесткими связями. Команды, продолжительность задержки между которыми строго фиксирована (т.е. время жизни результата выполнения первой из команд ограничено), предлагается моделировать с помощью последовательности, состоящей из двух узлов-операций и нескольких узлов-задержек между ними. Данные узлы соединяются жесткими связями. Аналогичным образом могут описываться команды переходов с неустранимыми задержками, только в этом случае вместо второй операции должен использоваться последний узел графа.
3. Выводы В статье рассмотрен традиционный способ представления базовых блоков с помощью графовой модели. На основе анализа её недостатков введена разреженная модель базовых блоков. 27
28
использованием методики.
JNI,
которая
показала
эффективность
предложенной
2. Отличия языков C и Fortran
Разработка системной поддержки вызова программ, реализованных на языке Fortran, из среды Java. С.С. Гайсарян, К.Н. Долгова Аннотация. Статья посвящена исследованию возможности вызова программ, реализованных на языке Fortran 95, из среды Java. Для того чтобы среды могли обмениваться данными, должно быть отображение данных одной среды на данные другой. В статье представлено описание отображения данных языка Fortran на данные языка Java и обратно. Также описан способ эффективной передачи данных из среды Java в среду Fortran и обратно. Он заключается в том, что память, выделенная средой Fortran для размещения общих блоков и массивов, отождествляется с прямыми буферами среды Java. То есть прямые буферы среды Java размещаются по тем же адресам памяти, по которым размещены общие блоки и массивы языка Fortran. Помимо этого, в статье описан метод организации вызова подпрограмм, реализованных на языке Fortran из окружения Java, заключающийся в передаче параметров через прямые буферы окружения Java.
1. Введение Имеется достаточно большое количество программ, реализованных на языке Fortan и не потерявших ценность. В настоящее время широкую популярность получила среда программирования Java, обеспечивающая переносимость программ. Следовательно, возникает потребность иметь возможность вызывать подпрограммы, реализованные на языках Fortan, из Java-программ. Для вызова подпрограмм, реализованных на языке С из Java-программ есть JNI, который доступен начиная с версии JDK 1.2. Аналогичного интерфейса для вызова Fortran-подпрограмм нет. Предложенная работа повящена разработке методики вызова Fortran-подпрограмм из Java-среды. В настоящей работе рассмотрены основные отличия языков С и Fortran, препятствующих использованию методике аналогичной JNI для вызова Fortran-подпрограмм из Java-программ. Построено отображение данных языка Fortran на данные Java и обратно. Предложена методика реализации общей области памяти для Java- и Fortran-сред через прямые буферы пакета java.nio. В последнем разделе описана прототипная реализация, выполненная с 29
У языков программирования C и Fortran, существует ряд различий, из-за которых нельзя перенести организацию JNI для языка С на организацию подобного интерфейса для языка Fortran. (1) В стандарте языка С напрямую не указан размер примитивных типов [1]. Выбор наилучшего для данной архитектуры размера типов оставлен на рассмотрение разработчиков компилятора. В стандарте языка Fortran для каждого примитивного типа данных строго задан их размер. Это позволяет установить взаимно однозначное соответствие между типами языка Java и типами языка Fortran, не используя промежуточных типов, как это реализовано в JNI. (2) Среда Fortran размещает данные в статической области памяти программы. К данным есть доступ только по ссылке, и нет возможности получить адрес памяти, где они расположены. Среда Fortran не поддерживает динамически создаваемых объектов данных. Среда C, во-первых, располагает данные программы в стеке, в куче и в статической области памяти программы, во-вторых, определена операция взятия адреса, позволяющие получить доступ не только к значениям данных, но и к адресам памяти, где они расположены. Соответственно, для передачи данных из Java-среды в C-среду JNI достаточно указать адрес области памяти, где данные хранятся. Передачу данных из Java-среды в Fortran-среду нельзя выполнить аналогично тому, как это сделано в JNI. (3) Все параметры в языке Fortran передаются только по ссылке, потому что в нем не определено понятие адреса переменной. В языке С параметры передаются только по значению, однако есть возможность передавать в качестве параметра функции указатели на ту область памяти, где хранится переменная. Соответственно, передачу данных из среды Java в среду Fortran и обратно нельзя выполнить аналогично тому, как это сделано в JNI. (4) В многомерных массивах языка С данные располагаются по строкам, тогда как в многомерных массивах языка Fortran данные располагаются по столбцам. В языке Fortran есть возможность непосредственно работать с частями массива – вырезками и сечениями. В языке С такой возможности нет. Следовательно, методика передачи массивов, реализованная в JNI, не может быть применена для среды Fortran. (5) В языке Fortran есть общие блоки COMMON. Эти блоки можно размечать по-разному в каждой подпрограмме. Так, например, в одной подпрограмме может быть объявлен массив типа complex размера 100, 30
расположенный в общем блоке /A/, а в другой подпрограмме на этой же памяти, то есть в том же общем блоке /A/ может быть объявлен массив типа real размера 200. Оба массива будут размещаться в памяти, начиная с одного и того же виртуального. Данные, которые в нем расположены – одни и те же, однако тип данных разный. В языке С аналогичная возможность может быть реализована посредством использования объявления union. Однако передача данных, расположенных в COMMON блоках с целью эффективности должна выполняться по схеме, отличной от той, которая реализована в JNI. Однако передача данных, расположенных в COMMON блоках с целью эффективности должна выполняться по схеме, отличной от той, которая реализована в JNI для передачи данных, объявленных в union. Учитывая то, что в реализации связывания подпрограмм, написанных на языке Fortran, с Java окружением должна быть сделана эффективная передача данных между Fortran-подпрограммами и основным Java-модулем, а так же принимая во внимание отличия языков С и Fortran, можно сделать вывод о том, что организация связывания между виртуальной машиной Java и подпрограммами, реализованными на языке Fortran, должна осуществляться по несколько иной схеме, нежели связывание C-методов и виртуальной машины Java.
3. Размещение данных в среде Fortran Программа, написанная на языке Fortran, допускает использование следующих видов программных единиц: стандартных функций, подпрограмм FUNCTION, подпрограмм SUBROUTINE, операторов – функций, подпрограмм, написанных на других языках программирования, и подпрограмм BLOCK DATA [2]. Формальные параметры языка Fortran передаются обычно по ссылке, за исключением тех случаев, когда параметр не модифицируется в подпрограмме [3]. В языке Fortran имеются средства, позволяющие использовать одну и ту же область памяти для хранения данных, общих для двух или более программных модулей выполняемой программы. Таким средством является общий блок [3]. Значения объектов из общего блока доступны всем программным единицам, в которых этот блок описан [2]. Каждый общий блок обязательно занимает в памяти непрерывный участок. Если некоторый программный модуль содержит несколько объявлений COMMON с одним и тем же именем, то все они рассматриваются как одно объявление и располагаются в памяти непрерывно и последовательно. Для объявления массивов в языке Fortran существуют специальные предложения спецификации: объявление размерности DIMENSION [3]. Так же массивы могут быть расположены в общих блоках. Массивы, полученные объявлением DIMENSION, представляют собой локальные данные той подпрограммы, внутри которой они описаны. 31
При вызове подпрограмм, реализованных на языке Fortran, из Java-окружения необходимо передавать данные из Java-среды в Fortran-среду. Также может возникнуть необходимость передавать данные из среды Fortran в среду Java, если вызываемая программная единица из среды Fortran – FUNCTION – возвращает значение. Java-среда передает все параметры только по значению, в среде Java нет методов работы с указателями, а все данные Java-программы расположены в куче. Любая подпрограмма, реализованная на языке Fortran, может получать данные извне либо как параметры, либо через общие блоки, которые в ней описаны. Если Fortran-подпрограмма получает данные для обработки через общие блоки, то вызывающая Java-программа должна иметь доступ на запись и чтение к той памяти, в которой эти общие блоки расположены. Такой доступ Java-программе возможно обеспечить, если на памяти, где располагается общий блок, разместить Java-объект. В качестве такого Java-объекта может быть взят прямой буфер класса Buffer, методы работы с которым доступны через пакет java.nio. Для того чтобы получить такой буфер, нужно из Fortran среды передать адрес начала общего блока и его размер. Дальше достаточно создать прямой буфер байтов, адрес начала которого будет совпадать с адресом начала общего блока, а размер будет такой же, как у соответствующего общего блока. Если Fortran-подпрограмма получает данные для обработки через формальные параметры, то для передачи таких параметров из Java-окружения необходимо выделить прямой буфер в Java-окружении, на который будут помещены передаваемые параметры. После того, как передаваемые параметры будут расположены на буфере, Fortran-подпрограмме нужно передавать только адрес этого буфера и смещение в нем, по которому расположен соответствующий параметр. Возврат данных из функций языка Fortran осуществляется по значению. Для передачи возвращаемого значения функцией языка Fortran в Java-окружения нужно это значение располагать в той области памяти, которая доступна и Java-окружению, и среде Fortran. Такой областью памяти с точки зрения среды Java может выступать прямой буфер. На нем необходимо выделить место для значения, возвращаемого функцией среды Fortran, и передать смещение в буфере Fortran-функции как параметр. А Fortran-функция запишет по полученному адресу возвращаемое значение.
4. Отображение типов данных языка Java в типы данных языка Fortran Основные типы языка Java и соответствующие им типы языка Fortran представлены в таблице 1. Данные для таблиц взяты из литературы [4] и [2].
32
Тип данных языка Java Int Short Long Byte Float Double Char Boolean
Требуемый объем памяти 4 байт 2 байт 8 байт 1 байт 4 байт 8 байт 2 байт 1 байт
Тип данных языка Fortran INTEGER INTEGER*2 INTEGER*8 CHARACTER REAL DOUBLE PRECISION CHARACTER LOGICAL*1
Таблица 1. Отображение примитивных типов языка Java в типы языка Fortran. Массив языка Java можно отобразить на такое представление данных языка Fortran как массив. Отображение массива языка Java на массив языка Fortran можно сделать через прямой буфер, средства работы с которым предоставлены в пакете «java.nio». Тип данных языка Требуемый объем Тип данных языка Fortran памяти Java INTEGER*2 2 байт short INTEGER 4 байт int INTEGER*4 4 байт int REAL 4 байт float REAL*4 4 байт float DOUBLE PRECISION 8 байт double REAL*8 8 байт double REAL*16 16 байт double double COMPLEX 8 байт float float COMPLEX*8 8 байт float float COMPLEX*16 16 байт double double COMPLEX*32 32 байт double double double double LOGICAL*1 1 байт byte LOGICAL 4 байт int LOGICAL*4 4 байт int CHARACTER 1 байт byte CHARACTER*L L байт string Таблица 2. Отображение примитивных типов языка Fortran в типы языка Java.
Основные типы языка Fortran и соответствующие им типы языка Java представлены в таблице 2. Данные для таблиц взяты из литературы [2] и [4] Для отображения данных, определенных в общем блоке, в окружении Java следует использовать прямой байт буфер. Такое отображение легко организовать, потому что общий блок представляет собой некоторую область памяти, хранящую неоднородные данные. Прямой байт буфер, доступный в Java-окружении также представляет собой область памяти, которая может хранить неоднородные данные. Для каждого как именованного, так и неименованного общего блока можно использовать по одному буферу. В языке Fortran массивом называется упорядоченная последовательность данных, занимающая непрерывную область памяти, к которой можно обращаться по имени [2]. Массивы характеризуются типом значений их элементов и граничными парами – диапазоном индексов по каждому измерению. Несмотря на то, что Fortran массивы могут быть как одномерными, так и многомерными, в памяти они располагаются как одномерный массив. Причем элементы многомерного массива располагаются в памяти таким образом, что значение первого индексного выражения возрастает быстрее второго, значение второго – быстрее третьего и т. д. [2]. Следовательно, приведенный индекс многомерного массива можно рассчитать по ниже приведенной формуле, а именно: пусть имеется многомерный массив arr[N, M, K], тогда приведенный индекс элемента arr[i, j, k] рассчитывается следующим образом: (i - 1) ( j - 1) * N (k - 1) * N * M . Массив языка Fortran следует отображать на прямой байт буфер, доступный в Java среде. Такое представление выгодно, потому что многомерный Fortranмассив в памяти располагается как одномерный массив. Для получения данных из прямого буфера соответствующих элементу многомерного Fortran-массива в Java окружении реализуется специальный класс. Так как многомерный массив не может иметь больше 7 измерений [5], то всегда можно автоматически получить данные из прямого буфера, соответствующие элементу многомерного Fortran-массива в Java окружении. При этом следует обойтись без транспонирования самого Fortran-массива. Для ссылки на элемент массива задается индексированная переменная; на массив в целом ссылаются по его имени. Начиная со стандарта Fortran 90, в языке есть возможность непосредственно работать с частями массива – вырезками и сечениями. Вырезка из массива представляет собой подмассив вида (< нижняя граница – верхняя граница),
Данные в Fortran-программах могут быть представлены в виде констант или имен переменных (или идентификаторов). 33
34
Элементы вырезки из массива могут быть взяты с шагом, отличным от единицы. В этом случае вырезка по соответствующему измерению задается уже не граничной парой, а триплетом. (< нижняя граница – верхняя граница, шаг >,…) Если по какому-то измерению опущены обе границы, то говорят о сечении массива. Вырезку из массива можно также задать с помощью векторного индекса[5]. Для отображения вырезки или сечения массива на объекты Java среды также можно использовать байт буфер. Такое отображение можно выполнить следующим образом. Весь массив отображается на буфер, а дальше в Javaсреде организуется специальный класс, содержащий методы получения и записи элементов вырезки и сечения массива посредством пересчета с учетом шага. Таким образом, любой массив языка Fortran можно отобразить на прямой байтовый буфер языка Java. Если массив размещен на общем блоке, он автоматически отобразится в Java окружение при отображении общего блока. Если массив определен посредством использования оператора DIMENSION, то для него надо создать прямой буфер, расположенный на том участке памяти, который компилятор языка Fortran выделил для хранения данного массива. Что касается вырезки и сечения массивов, то это представление данных можно отобразить через указатели на соответствующие элементы.
5. Вызов Fortran-подпрограмм из Java-среды При вызове Fortran-подпрограмм из Java-среды необходимо учитывать особенности чтения данных в Java- и Fortran-средах. Java-машина читает байты, в которые записано одно число, слева направо (прямое чтение), а в C- и Fortran- – программах порядок байт в записи чисел зависит от архитектуры. То есть, на некоторых платформах используется чтение справа налево (так называемое, инвертированное чтение). Следовательно, на некоторых платформах для корректной работы, данные, записанные Fortran-подпрограммой, нужно подвергнуть дополнительному преобразованию в формат языка Java, чтобы Java-программа прочитала их корректно. И наоборот, данные, записанные Java-программой, тоже надо подвергать обратному преобразованию в формат языка Fortran, чтобы подпрограмма, реализованная на языке Fortran, смогла прочитать именно то, что было помещено в Java-коде. В выше упомянутом преобразование предполагается менять местами соответствующие записи в ячейках. Такое преобразование необходимо осуществлять каждый раз, когда обработка данных, расположенных в памяти, общей и для Java-окружения, и для среды Fortran, передается от Java-машины Fortran-среде и обратно. 35
Такое преобразование предполагается целесообразным выполнять при каждой записи виртуальной машиной Java данных в общую память и при каждом считывании данных из общей памяти Java-машиной. Следовательно, среда Fortran всегда будет обрабатывать данные, записанные в формате языка Fortran, а Java-машина всегда будет работать с данными, записанными в формате языка Java.
6. Описание практической части Прототипная реализация выполнена посредством связывания вызова подпрограммы, реализованной на языке Fortran, из Java-программы через язык С (JNI). В настоящее время окружение Java не предоставляет возможности вызывать напрямую подпрограммы, реализованные на языке Fortran. Реализация выполнена для GNU компилятора Fortran (g77), GNU компилятора С (gcc) версии 3.3.4 и JDK версии 1.4.2_03. Компилятор g77 основан на стандарте ANSI Fortran 77, но он включает в себя многие особенности, определенные в стандартах Fotran 90 и Fortan 95 [6]. JDK версии 1.4.2_03 содержит пакет java.nio, который предоставляет возможность использования новых средств ввода-вывода таких как прямые буферы и JNI (Java Native Interface). Как уже отмечалось в пункте 2, прежде чем выполнить вызов подпрограммы, реализованной на языке Fortran, из Java-среды, необходимо выделить область памяти, которая была бы доступна как из Java-окружения, так и из среды Fortran. Для этого нужно: 1. На языке Fortran реализовать подпрограмму. В этой подпрограмме должны быть объявлены все общие блоки, которые будут использоваться для обмена данными Fortran-среды с Java-окружением. 2. На языке С должен быть реализован модуль, который через разделяемую библиотеку посредством JNI будет вызываться из Javaсреды. Модуль должен содержать функцию, которая вызывается из среды Fortran. Данной функции, в качестве параметров по ссылке, из Fortran-среды передается адрес первого, адрес последнего элемента и размер в байтах последнего элемента общего блока. По полученным данным вычисляются и сохраняются начало и размер общего блока. Такая функция вызывается для каждого общего блока. Некоторая функция вычисляет и сохраняет размер общего блока, а так же сохраняет адрес начала общего блока. Теперь во встроенном модуле, реализованном на языке С, хранятся адреса и размеры всех общих блоков, которые определены в подпрограмме, реализованной на языке Fortran. Следовательно, запросив по указанному адресу прямой буфер нужного размера, будет получено размещение нового байт-буфера Javaсреды на том же участке памяти, что и соответствующий ему общий блок. 36
3. На языке Java реализуется класс, который содержит метод инициализации и метод получения прямого байт-буфера. Метод инициализации вызывает встроенный метод инициализации, реализованный на языке С в описанном в пункте 2 модуле. Встроенный метод инициализации вызывает Fortran-подпрограмму, описанную в пункте 1. Метод получения прямого байт-буфера вызывает встроенный С-метод, который заказывает в оперативной памяти прямой буфер нужного размера, начиная с указанного адреса. Дальше полученный прямой байт-буфер уже сам пользователь может представлять как буфер тех данных, которые ему нужны. Байт-буферы расположены непосредственно в том же участке памяти, что соответствующие им общие блоки, следовательно, все данные, которые записываются в прямой буфер в Java-коде, автоматически становятся доступными из общего блока в коде, реализованном на языке Fortran. И наоборот: все, что помещено в общий блок в Fortran-подпрограмме, автоматически становится доступно из прямого буфера в Java-программе. Такое расположение данных полностью решает поставленную в пункте 1 задачу о совместном размещении данных Java-окружения и среды Fortran на одном участке памяти. Чтобы выполнить вызов Fortran-подпрограммы из Java-среды нужно сделать: 1. В Java-среде нужно расположить параметры для передачи в среду Fortran на прямом буфере. Этот прямой буфер передается в качестве параметра вспомогательным С-функциям, которые описаны в пункте 2. Так же, в качестве параметра передается смещение в буфере, по которому расположены передаваемые параметры. 2. На языке С реализовать встраиваемый через JNI в Java-окружение модуль. В этом модуле реализуются вспомогательные функции для каждой вызываемой Fortran-подпрограммы из Java окружения. Каждая такая вспомогательная функция вызывается из Java-программы. Одним из ее действий является непосредственный вызов Fortran-подпрограммы. Также вспомогательная функция выполняет передачу параметров из Java-окружения в среду Fortran, как это описано в пункте 2. То есть вспомогательная функция получает адрес буфера, вычисляет адреса параметров, зная смещения их расположения в буфере, и передает вычисленные адреса Fortran-подпрограмме. 3. На языке Java реализуется класс, который занимается записью и чтением данных из общей для Fortran-среды и Java-оболочки памяти. При этом при записи выполняется преобразование данных из формата языка Java в формат языка Fortran, а при чтении выполняется преобразование данных из формата языка Fortran в формат языка Java, как это описано в пункте 2.
37
7. Накладные расходы В предложенной реализации накладные расходы возникают при вызове метода инициализации прямых Java-буферов, но эти накладные расходы возникают только один раз за все время работы программы, поэтому время, которое на них тратится, не существенно влияет на общую производительность программного продукта. Накладные расходы возникают при преобразовании данных из формата языка Java в формат языка Fortran. Однако полное преобразование данных из одного формата в другой есть необходимость выполнять только дважды за работу всего приложения: в начале, после инициализации, и в конце, перед тем, как вывести окончательный результат работы приложения. Следовательно, эти накладные расходы тоже считаются разовыми и не существенно влияют на время выполнения программного продукта. Однако возникают еще накладные расходы, когда данные обрабатываются не только в Fortran-подпрограммах, но и в основной программе, написанной на языке Java. В этом случае при каждом переключении есть необходимость преобразовать данные из одного формата в другой. Но, как правило, объем данных обрабатываемый сразу и в Java-коде и в коде, реализованном на языке Fortran, не очень велик. Следовательно, не следует преобразовать сразу все данные, которые рассчитываются в приложении, а нужно преобразовать только тот их фрагмент, который нужен для обработки. Такой подход позволит сократить накладные расходы на преобразование данных. Именно эти накладные расходы следует учитывать при оценке времени работы программного приложения.
8. Пример Чтобы убедиться в корректности работы реализации была взята программа расчета динамики взрыва сверхновой звезды, реализованная на языке Fortran. [7]. Основная функция main, которая управляет расчетами, была переписана на язык Java. Остальные подпрограммы оставлены на языке Fortran. Результаты работы исходной программы, реализованной только на языке Fortran, и программы, основная часть которой реализована на языке Java, а подпрограммы выполнены на языке Fortran, одинаковые. Для сравнения времени работы полученного приложения, реализованного на языке Java с использованием Fortran-подпрограмм, было произведено сравнение с точно таким же приложением, но реализованным целиком на языке Fortran и на языке Java. Приложение можно представить в виде следующей схемы, представленной на Рис. 1.
38
только на языке Java, данные из файла записываются в массивы языка Java, а в приложении, реализованном на языках Java+Fortran, - в прямые буферы.
Инициализация данных
Инициализация данных
счет
Счет
300000
70000 60000
250000
50000
200000
Fortran 40000
запись данных в файлы
Java + Fortran
30000
Fortran Java + Fortran
150000
Java
Java
100000
20000 50000
10000
Рис.1. Схема приложения.
1
1
В приложении, реализованном на языках Java+Fortran, инициализация данных и запись данных в файлы выполняется в Java-окружении, а счет выполняется в Fortran-среде. Для сравнения времени выполнения были выполнены замеры, как скорости работы всего программного приложения, так и отдельных его частей, в соответствии с Рис. 1. Замеры проводились на персональном компьютере. Размер оперативной памяти 512 MB, частота процессора 1700 MHz. Характеристики кэш-памяти процессора следующие: CPU L1 Cache: 64K (64 byte/line), CPU L2 Cache: 526K (64 byte/line) Сравнение времени работы представлено в таблице 3 и на Рис. 2. Fortran Java + Fortran Java
0
0
полное приложение (ms)
инициализация (ms)
счет (ms)
запись (ms)
261559 266223 337225
42826 43540 69874
218450 221623 265727
283 1060 1624
а)
б) Счет
Запись данных в файл
1800
300000
1600 250000
1400
200000
1200
Fortran
Fortran
1000
Java + Fortran
150000
Java + Fortran
800
Java 100000
Java
600 400
50000
200 0
0
1
в)
1
г) Рис. 2. Время выполнения.
Таблица 3. Сравнительная производительность. Как видно в таблице 4 и на Рис. 2 (а) реализация приложения на языках Java+Fortran не значительно проигрывает по времени выполнения приложению, реализованному только на языке Fortran. Это достигается за счет того, что в приложении, реализованном на Java+Fortran, вычисления полностью выполняют в Fortran-среде. Однако приложение, реализованное на языках Java+Fortran, значительно быстрее работает, нежели приложение, реализованное на языке Java. Как видно на Рис. 2 (б), 2(в), 2(г) в приложении, реализованном только на языке Java, не только вычисление занимает больше времени, нежели в приложении, реализованном на языках Java+Fortran, но и инициализация и запись данных в файл. Потеря времени происходит за счет того, что большая часть инициируемых данных берется из файла. В приложении, реализованном 39
9. Некоторые ограничения реализации приложения пользователя Fortran-подпрограммы, которые вызываются из Java-среды, не должны содержать символа «подчеркивание» в своем имени. В противном случае разделяемая библиотека не сможет сопоставить реализованные в ней методы с теми, которые вызываются. Это вызовет падение работы всего приложения. Компилятор GNU g77, разрешает использование переменных без их явного описания. Однако если явно не определить тип переменной в подпрограмме, которая вызывается из Java-окружения, вероятен случай, что виртуальная Javaмашина получит внешний сигнал. Этот сигнал, номер которого 11, сообщает виртуальной машине о некорректном обращении к памяти за пределами ее работы. Аналогичная ситуация может возникнуть и с функциями. При 40
описании функций стандартом предусмотрено описывать явно тип возвращаемого значения. Однако если этого не сделать, то компилятор сам подберет соответствующий тип, исходя из типа возвращаемого выражения. Если такую функцию вызывать из программы, реализованной только на языке Fortran, то все стабильно будет работать. Но, как только объектный модуль с такой функцией участвует в формировании разделяемой библиотеки и подобного рода функция вызывается подпрограммой, которая в свою очередь вызывается виртуальной машиной Java, выполнение основной программы прекращается по причине получения виртуальной Java-машиной сигнала номер 11. Данные ограничения в дальнейшем развитии работы будут сняты посредством автоматического добавления в код Fortran-программы недостающих описаний.
10. Заключение Разработана организация взаимодействия среды Java и подпрограмм, реализованных на языке Fortran. Была выполнена прототипная реализация. Прототипная реализация показала, что описанная методика вызова подпрограмм, реализованных на языке Fortran, из окружения Java вызывается с минимальными накладными расходами, а, следовательно, эффективна. Дальнейшее развитие предполагает разработку методики рефакторинга Fortran-программ с целью преобразования их в такой вид, какой было бы удобно автоматически транслировать на язык Java. Литература 1. 2. 3. 4.
Б.Керниган, Д.Ритчи. Язык программирования Си. Санкт-Петербург, 2001 Фортран 77 ЕС ЭВМ. Справочное издание. Москва «Финансы и статистика», 1989 Фортран. Программированное учебное пособие. Киев «Вища школа», 1980 У.Савитч. Язык Java. Курс программирования. Москва – Санкт-Петербург – Киев «Вильямс», 2002 5. Ю.И. Рыжиков. Современный фортран. Санкт-Петербург «Корона принт», 2004 6. Артур Гриффитс. GCC. Полное руководство. Москва – Санкт-Петербург – Киев DiaSoft, 2004 7. С. Д. Устюгов, В. М. Чечеткин. Взрыв сверхновой при крупномасштабной конвективной неустойчивости вращающейся протонейтронной звезды. // Астрономический журнал, 1999, том 76, №11, с. 816-824.
41
Метод виртуального процессора в защите программного обеспечения П.В. Бойко (
[email protected]) Аннотация. В статье рассматривается метод защиты программного обеспечения от изучения с помощью переноса защищаемого кода в виртуальную среду исполнения. Проводится анализ эффективности, а так же недостатков метода. Предлагается вариант реализации, позволяющий снизить себестоимость разработки.
1. Введение Как известно, идеального способа защиты программного обеспечения (ПО) не существует, в связи с этим, разработчики защитных систем не стремятся лишить потенциального взломщика самой возможности нейтрализации защиты, но стараются максимально усложнить этот процесс. Защита может решать одну или комплекс из множества задач, таких как защита от копирования, нелегального использования, модификации и др., но какая бы конечная цель ни стояла перед таким продуктом, разработчикам каждого из них прежде всего необходимо решить общую для всех проблему – качественной защиты от изучения. Какие бы ни применялись алгоритмы защиты ПО, их стойкость к обратной инженерии определяет стойкость всей системы защиты в целом. Сегодня на рынке существует большое количество коммерческих защит, однако многие из них, в т.ч. до сих пор популярные, давно взломаны. Зачастую их подводит именно слабая защищенность от изучения. После анализа взломщиком алгоритмов работы защиты, серийные ключи генерируются, аппаратные – успешно эмулируются. Ситуацию могла бы исправить разработка эффективного метода защиты ПО от изучения, применяя который к алгоритмам других защит, позволила бы качественно поднять их уровень.
2. Методы защиты ПО от изучения Рассмотрим, какие методы существуют для защиты ПО от изучения: - запутывание – искусственное усложнение кода, с целью затруднить его читабельность и отладку (перемешивание кода, внедрение ложных процедур, передача лишних параметров в процедуры и т.п.); 43
- мутация – при каждом запуске создаются таблицы соответствия операций, сами операции заменяются на синонимы; - компрессия, шифрование – изначально программа упаковывается / шифруется, и производит обратный процесс по мере выполнения; - симуляция процессоров – создается виртуальный процессор; защищаемая программа компилируется под него, и выполняется на целевой машине с помощью симулятора. Существуют и другие методы, а так же их комбинации и разновидности, однако, нетрудно заметить, что все они основаны на одной простой идее: избыточности. В самом деле, что такое запутывание, как не избыточное кодирование программы? Лишние переходы, лишние параметры, лишние инструкции – ключевое слово метода «лишние». То же касается любого из перечисленных методов, и, вероятно, было бы естественным объединить все эти методы в одну группу «Методов избыточного кодирования». Чем же так хороша избыточность, ведь интуитивно понятно, что она увеличивает размер программы и снижает скорость ее работы? Дело в том, что во всех этих разновидностях защиты используется понимание «человеческого фактора» человеку тем сложнее понять логику какого-либо процесса, чем больше ресурсов этот процесс использует. Например, функциональность одной простой инструкции загрузки константы на регистр может быть «размазана» на десятки, а то и сотни инструкций, и проследить связь всех используемых ресурсов (регистров, памяти и др.) в этой последовательности человеку довольно сложно. Метод шифрования с этой точки зрения не является чем-то особенным – так же, как и в других методах, для выполнения простой инструкции (или группы) требуется избыточная последовательность команд – в данном случае это операции расшифровки, плюс операции расшифрованного кода. Однако то, что автоматически «запутано» или усложнено, может быть так же автоматически приведено в первоначальное состояние – разработчики механизмов запутывания обычно параллельно разрабатывают и «распутыватели», а методы мутации и шифрования и вовсе подразумевают содержание обратного механизма в защищенном коде. Особняком в этой группе методов стоит лишь метод симуляции виртуального процессора, который, во-первых, приводит к высокой и неснижаемой степени запутанности результирующего кода, а, во-вторых (при определенном подходе к реализации), защищенный код не содержит в явном виде методов восстановления оригинального кода. Рассмотрим этот метод подробнее.
3. Виртуальный процессор в защите ПО Суть метода такова: некоторые функции, модули, или программа целиком, компилируются под некий виртуальный процессор, с неизвестной потенциальному взломщику системой команд и архитектурой. Выполнение обеспечивает встраиваемый в результирующий код симулятор. Таким образом, 44
задача реинжиниринга защищенных фрагментов сводится к изучению архитектуры симулятора, симулируемого им процессора, созданию дизассемблера для последнего, и, наконец, анализу дизассемблированого кода. Задача эта нетривиальна даже для специалиста, имеющего хорошие знания и опыт в работе с архитектурой целевой машины. Взломщик же не имеет доступа ни к описанию архитектуры виртуального процессора, ни к информации по организации используемого симулятора. Стоимость взлома существенно возрастает. Почему же, учитывая высокую теоретическую эффективность, данный метод до сих пор не используется повсеместно? Видимо по двум основным причинам. Во-первых, метод имеет особенности, что сужает области его потенциального применения – об этом будет сказано ниже. Во-вторых, и, возможно, это более серьезная причина, сложность (а следовательно и стоимость) реализации метода весьма высока. Если же учесть принципиальную возможность утечки информации о только что созданной системе, которая моментально приведет к ее неэффективности и обесцениванию, становится понятно, почему фирмы-производители защитного ПО не спешат реализовывать этот метод. Стоит, однако, отметить, что с теми или иными вариациями и ограничениями данный метод все же реализован в таких новейших продуктах как StarForce3, NeoGuard, VMProtect и др. Видимо таких продуктов будет становиться все больше и больше, а существующие будут развиваться, т.к. появляющиеся реализации подтверждают высокую эффективность метода, хоть и имеют пока слабые стороны.
3.1. Реализация метода Одним из недостатков метода является высокая стоимость его реализации, однако она может быть заметно снижена. В основе системы защиты, реализующей данный метод, мог бы лежать компилятор с языка высокого уровня. Необходимо машинно-зависимая фаза в любом компиляторе всего одна – кодогенерация, от зависимостей в других фазах, как правило, можно избавиться. Если же компилятор изначально разрабатывается как мультиплатформенный, в нем, как правило, максимально упрощен процесс перенастройки на другую целевую платформу. Например, это может быть достигнуто автоматической генерацией кодогенератора по специальному описанию целевой машины. В этом случае разработчикам для смены платформы достаточно лишь изменить это описание. Но даже если собственного компилятора нет, можно воспользоваться свободнораспространяемыми с открытым кодом, например, GCC. А чтобы максимально упростить для пользователя работу с описываемой системой защиты, ее можно снабдить механизмами встраивания в популярные среды разработки, такие как MSVC. В этом случае схема работы такого комплекса могла бы выглядеть так, как изображено на Рис. 1. 45
Рис. 1. Схема защиты ПО Соответственно, функционирование защищенного таким способом образом продукта происходило бы по схеме на Рис. 2. Специфика использования компилятора налагает ряд особых требований к виртуальному процессору, тем не менее все они могут быть легко реализованы. Требований немного – нужно лишь обеспечить возможность доступа к внешней, относительно виртуальной машины, памяти, а так же возможность вызова внешних функций – это необходимо для взаимодействия защищенного и незащищенного кода. В остальном архитектура виртуального процессора может быть совершенно произвольной, и чем запутаннее и оригинальней она будет, тем более высокий уровень защиты будет достигнут. Сам компилятор, кроме изменения кодогенерационной фазы, нужно доработать для приобретения им возможностей: 46
- различать обращения к внутренней и внешней памяти относительно виртуального процессора (в том числе и вызовы функций); - создавать для каждой защищаемой функции так называемую оболочку, выполняющуюся на реальном процессоре, с вызовом защищенной функции через симулятор.
Начало
Незащищенные модули
Вызовы защищенных функций
Симулятор виртуального процессора
Рис. 3. Схема вызова защищенной функции
Конец Защищенные модули (псевдокод)
Рис. 2. Схема работы защищенного программного продукта Последнюю возможность следует описать подробнее. Как было отражено в схеме на Рис. 2, функционал защищенных функций будет реализован через вызов симулятора, с указанием, какую из защищенных функций нужно интерпретировать. Однако, до этого, необходимо выполнить специальный код, подготавливающий для защищенной функции параметры - "переместить" их с реальных регистров и памяти на виртуальные, способом, соответствующим архитектуре виртуального процессора. Всем этим будут заниматься специальные функции, сгенерированные нашим компилятором - "оболочки". Оболочки, в свою очередь, будут использовать специальные функции симулятора для доступа к виртуальным регистрам и памяти. Характерно, что наш компилятор будет генерировать оболочки на языке высокого уровня, которые, в свою очередь, будут компилироваться стандартным компилятором, использующимся пользователем для сборки незащищенной части своего проекта. Итак, вызов защищенной функции из незащищенного модуля может выглядеть так, как изображено на Рис. 3. 47
Конечно, конкретная реализация метода виртуального процессора может быть несколько отличной от описываемой, как и схема работы защищенного им продукта. Тем не менее, описанный вариант вполне жизнеспособен, и, кроме того, относительно прост. Сердце защищенного продукта – симулятор. Он будет включаться в любую сборку защищенного продукта. Однако не будем подробно рассматривать его реализацию, т.к. специальных требований к нему практически не предъявляется – он должен лишь симулировать архитектуру нашего виртуального процессора, включая операции доступа к внешней памяти. Стоит, однако, отметить, что с учетом специфики его применения, необходимо максимально автоматизировать процесс перенастройки симулятора на новые виртуальные архитектуры. Недостатки же метода – следствие его достоинств: - скорость работы перенесенного в виртуальную среду кода в разы (ориентировочно в 10-50, в зависимости от архитектуры виртуального процессора и симулятора) ниже, чем кода оригинального; - объем защищенной программы, как правило, будет несколько выше, чем незащищенной. Впрочем, последний недостаток несущественен, т.к. размер увеличится незначительно, а в некоторых случаях может даже снижаться. Первый же недостаток принципиален, и налагает некоторые очевидные ограничения на использование метода.
48
4. Заключение Рассмотренный метод защиты ПО весьма эффективен, учитывая то, что затраты на его разработку можно существенно сократить. Однако, особенности метода не позволяют рекомендовать его для защиты программ полностью. Так, метод не может применяться для защиты функций, критичных ко времени выполнения, а так же функций, замедление работы которых может заметно снизить эффективность использования программы пользователем. Тем не менее, аккуратное применение данного метода позволяет добиться очень высокого уровня защиты от изучения. В связи с этим, основной областью его применения видится повышение стойкости к изучению отдельных алгоритмов других систем защиты ПО. Кроме того, метод применим для защиты нересурсоемких алгоритмов ноу-хау, а так же для сокрытия содержания в защищаемой программе некоторых специальных данных, например, сведений об авторстве.
49
Использование информации о линейных зависимостях для обнаружения уязвимостей в исходном коде программ В.С. Несов, О.Р. Маликов
1. Введение Одним из методов обнаружения потенциальных уязвимостей в программе является статический потоково-чувствительный data-flow анализ. В ходе проведения такого анализа для каждой точки программы собирается информация о различных атрибутах объектов программы, которая затем проверяется на выполнение условий корректности операций с памятью и использования библиотечных функций в различных точках программы. Серьезной проблемой такого метода обнаружения уязвимостей является большое количество ложных предупреждений. Часто ложные предупреждения вызваны недостаточной точностью определяемой информации об атрибуте значение некоторой переменной (объекта программы). Самым простым подходом определения информации о целочисленных значениях является анализ на основе интервальных оценок. Каждому целочисленному атрибуту объектов программы в данной точке программы сопоставляется числовой интервал значений, при этом зависимости между атрибутами не учитываются. Например, если атрибуту x сопоставляется интервал возможных значений [a,b], атрибуту y – интервал [c,d], то результату операции сумма z=x+y сопоставляется интервал [a+c,b+d]. Такая модель хорошо работает для не связанных друг с другом атрибутов.
2. Анализ на основе линейных зависимостей Многие условия корректности операций в программе представляют собой линейные соотношения (равенства либо неравенства) между значениями числовых атрибутов объектов программы. Например, при обращении к массиву проверяется, лежит ли индекс, по которому происходит обращение, в пределах массива. В случае если и длина массива, и значение индекса в широких пределах произвольны, ответить на вопрос о возможности выхода за 51
пределы массива при отсутствии информации о зависимости между индексом и длиной массива невозможно. Подход, предлагаемый нами к использованию в рамках разрабатываемой системы обнаружения уязвимостей, состоит в поддержании системы линейных неравенств, выполняющихся для числовых атрибутов в данной точке программы. При потоково-чувствительном анализе потока данных в каждой точке программы (контексте) хранится информация о большом количестве числовых атрибутов. Так как одной из задач разрабатываемой системы являлась возможность анализа программ промышленного масштаба, были применены различные методы, ограничивающие вычислительные издержки, возникающие при учете линейных зависимостей. Если при анализе требуется определить соотношение между значениями атрибутов (проверить некоторое равенство или неравенство), то переносом всех атрибутов в одну часть соотношения задача сводится к определению множества возможных значений атрибута, равного полученному в этой части выражению. Например, при проверке выхода за пределы массива требуется проверить, меньше ли индекс в массиве x размера массива l, x=s1.len
i[1,1023], i>=s1.len i[0,+), i>=s1.len
s2.len=0
s2.len[0,1], s2.len= threshold» постоянным в процессе выполнения. Если это так, то одна из веток конструкции if-then-else, описываемой Switch-блоком, никогда не будет выполняться (т.е. на выход блока всегда будет подаваться сигнал с одного и того же входа) и может быть удалена из модели. 134
В соответствии с методом GraphOTK, на основе описания алгоритма оптимизации строится абстрактная модель тестов. В случае оптимизации Switch-блока в описании алгоритма используется следующие термины: блок Switch и различные блоки библиотеки Simulink, из которых могут быть составлены модельные конструкции для входов блока Switch. Для данного алгоритма оптимизации являются важными значения параметров блоков модели, влияющие на величину выходного сигнала блока (например, амплитуда сигнала у блока Sine Wave). Таким параметрам в абстрактной модели соответствуют свойства терминов. Шаблоном для оптимизатора является блок Switch c различными комбинациями значений порогового параметра и области возможных значений входа control. В процессе генерации строятся различные модели Simulink, содержащие блок Switch. В качестве входов блока Switch строятся различные модельные конструкции с различными параметрами. Целью генерации является получение набора тестов, удовлетворяющего следующим условиям: - набор должен содержать модели с блоком Switch; в качестве каждого входа блока Switch должны быть перебраны все наследники узла InputSystemBlock абстрактной модели тестов; - для блоков, имеющих более одного входа, в качестве каждого входа должны быть перебраны все наследники узла InputSystemBlock; если на вход должен подаваться непрерывный сигнал, то в качестве такого входа должны быть перебраны все наследники блока Signal; - для блоков с переменным количеством входов с минимально допустимым числом входов N тесты должны содержать модели, где каждый такой блок будет иметь N входов, и модели, где он будет иметь N+1 вход; - тесты должны содержать модели, где величина сигнала на входе control у блока Switch всегда не меньше порогового значения, тесты, где эта величина всегда меньше порогового значения, а также тесты, где значение булевского выражения «control >= threshold» изменяется в процессе выполнения модели; - для блоков с несколькими входами, над каждым из которых может быть произведена одна из операций некоторого фиксированного набора (например, у блока Sum для каждого входа можно указать знак – ‘+’ или ‘–‘), набор тестов должен содержать блоки со всеми возможными операциями (например, для упомянутого выше блока Sum тесты должны содержать блоки, где по крайне мере один аргумент имеет знак ‘+’, и блоки, где по крайне мере один аргумент имеет знак ‘–’).
135
Путем настройки параметров генератора можно получать тесты, не содержащие блоков-генераторов сигналов и блоков-преобразователей сигналов. По умолчанию в генерируемых тестах присутствуют как корректные, так и некорректные модели, выполнение которых в среде Matlab приводит к возникновению исключительных ситуаций. Возможна настройка генератора для генерации только корректных моделей. В этом случае, в частности, гарантируется соблюдение динамической семантики при выполнении математических функций, для чего в процессе генерации осуществляются следующие действия: - для математических функций, область определения которых является отрезком, интервалом или полуинтервалом (asin, acos, acosh, atanh, log, log10, sqrt) на пути входного сигнала помещается блок Saturation, ограничивающий величину сигнала; - для фунции reciprocal (1/x) и для блока Product в случае деления входной сигнал сравнивается с нулем (с помощью блока Relational Operator) и результат сравнения (1 – если сигнал равен нулю, 0 в противном случае) прибавляется к величине сигнала; - для блоков, осуществляющих побитовые операции (BitwiseLogicalOperator) берется абсолютное значение входного сигнала (с помощью блока Abs) и входной сигнал приводится к типу uint32 (с помощью блока DataTypeConversion); - для функции возведения в степень (блок Math Function, функция pow) в случае, если первый аргумент (основание степени) равен нулю, а второй (показатель степени) отрицателен, вместо нуля блоку передается значение ‘1’. (Сравнение значений осуществляется при помощи блоков Relational и Logic, результат сравнения прибавляется к первому аргументу блока, осуществляющего возведение в степень). В случае, когда требуется получать как корректные, так и некорректные модели, перечисленные выше действия не осуществляются. Таблица 1 содержит объем и время генерации сгенерированного множества тестовых данных тестов. В приложении A приведен аннотированный пример сгенерированных тестовых данных для оптимизации SwitchBlock. Количество тестов
Размер тестов, MB
Время генерации
3 112
64
5 m. 07 s.
Таблица 1. Характеристики сгенерированных тестов для оптимизации SwitchBlock.
136
3.2. Генератор тестовых данных для оптимизатора Flowchart Набор тестов предназначен для генератора кода, осуществляющего трансляцию и оптимизацию графа Flowchart блока Stateflow Chart, описывающего конструкцию if-then-else. Оптимизатор ищет в графе вершины, соединенные двумя и более дугами. Каждой дуге ставится в соответствие условие, в случае выполнения которого осуществляется переход по этой дуге, а также может быть определено действие, осуществляемое при переходе. Для каждой вершины графа одна из исходящих дуг не должна иметь условия – она соответствует ветви “else” конструкции “if-then-else”. Все дуги, соединяющие одни и те же вершины графа, заменяются оптимизатором на одну дугу. Все проверки условий и выполнение соответствующих действий описываются как действие новй дуги. Пример преобразования графа, осуществляемого оптимизатором, показан на Рис.3. LHS
RHS
J1
T3
T2
A3
J1
C2 A2
J2
T1
C1
T1
A1
J2
A’1 String Code= If (C1) { A1; } else { if (C2) { A2; } else { A3 ; } }
Рис.3. Пример преобразования, осуществляемого оптимизатором Flowchart В соответствии с методом GraphOTK, на основе описания алгоритма оптимизации строится абстрактная модель тестов. В случае оптимизации Flowchart в описании алгоритма используются следующие термины: StateflowMachine (часть блока Simulink Stateflow Chart, которая содержит описание flowchart-графа) и вершины графа. Шаблоном для оптимизатора является блок Stateflow Chart, который содержит не менее двух вершин, соединенных дугами. В процессе генерации для блока Stateflow Chart строятся различные циклические и ациклические графы, описывающие структуры if-then-else различной разветвленности и глубины вложенности. Гарантируется, что из 137
начальной вершины графа можно достичь любой другой его вершины. Число вершин в графах изменяется от 3 до 10. Число дуг, соединяющих произвольные две вершины, изменяется от 0 до 3. Каждой (кроме одной) дуге, исходящей из каждой вершины, поставлено в соответствие условие, заключающееся в проверке принадлежности входного сигнала блока заданному интервалу. Гарантируется, что условия conditionузлов дуг, исходящих из одной вершины, являются взаимоисключающими. Каждой дуге поставлено в соответствие действие; в результате выполнения действий формируется величина выходного сигнала блока в зависимости от величины входного сигнала. Для дуг, исходящих из начальной вершины графа, действие заключается в присваивании выходному сигналу величины входного сигнала, умноженной на некоторый коэффициент (различный для различных дуг). Для остальных дуг действие заключается в прибавлении к величине выходного сигнала величины входного сигнала, умноженной на некоторый коэффициент (различный для различных дуг). Каждый тест представляет собой модель, содержащую блок Statflow Chart. Входной сигнал подается извне (с помощью блока InPort), выходной сигнал подается на выход модели (блок OutPort). Целью генерации является получение набора тестов, содержащих блок Stateflow Chart и удовлетворяющих следующим требованиям: - тесты должны содержать графы с количеством конечных вершин (т.е. вершин, у которых нет исходящих дуг) от 1 до 5 (значение 5 выбрано в целях получения приемлемого количества тестов); - между начальной вершиной графа и каждой из конечных вершин должны быть пути (по дугам через другие вершины графа, без учета циклов) длины от 1 до 5 (длина равна числу дуг на пути); должны быть перебраны все возможные сочетания длин пути (т.е. должны быть графы, где все пути имеют длину 1, графы с путями длины 1 и 2 и т.д.); - для каждой упомянутой выше комбинации длин пути набор тестов должен содержать как ациклические графы, так и графы с циклами; - число дуг между вершинами графа на каждом из путей должно варьироваться от 1 до 3 (что соответствует безусловному переходу, конструкции “if-else” и конструкции “if-elseif-else”). Объем и время генерации сгенерированного множества тестовых данных тестов приведены в Таблица 2. В приложении A приведен аннотированный пример сгенерированных тестовых данных для оптимизации Flowchart. Количество тестов 1 335
Размер тестов, MB 60
Время генерации 3 m. 45 s.
Таблица 2. Характеристики сгенерированных тестов для оптимизации Flowchart. 138
4. Заключение В статье предложен метод автоматической генерации тестовых данных для тестирования оптимизирующих трансляторов графических моделей. Предложенный метод позволяет решить проблему автоматической генерации тестовых данных, а также за счет параметризации генератора позволяет варьировать количественные и качественные характеристики получаемых тестовых данных. В соответствии с предложенным методом были разработаны генераторы тестовых данных для нескольких оптимизаторов графических моделей, которые используются в коммерческих проектах в автомобильной промышленности.
Приложение A. Примеры сгенерированных тестовых данных Пример 1. Тестовые данные для оптимизации SwitchBlock. Графическая модель тестовых данных для примера 1 изображена на Рис. 4.
Литература [1]. [2]. [3]. [4]. [5].
[6]. [7]. [8]. [9]. [10]. [11]. [12].
The MathWorks, www.mathworks.com ETAS ASCET. http://en.etasgroup.com/products/ascet/ I-Logix. http://www.ilogix.com dSPACE, www.dspace.com Paul A. Barnard. Software Development Principles Applied to Graphical Model Development. // AIAA Modeling and Simulation Technologies Conference and Exhibit, San Francisco, California, Aug. 15-18, 2005. (https://tagteamdbserver.mathworks.com/ttserverroot/Download/28446_Barnard%20AIA A-2005-5888.pdf) Ranville S., Black P. Automated Testing Requirements – Automotive Perspective. // The Second International Workshop on Automated Program Analysis, Testing and Verification. 2001. (http://hissa.nist.gov/~black/Papers/autoTestReqsWAPATV.rtf) Conrad, M., Dörr, H., Schürr, A., Stürmer, I. Graph-Transformations for Model-based Testing. // GI-Lecture Notes in Informatics. 2002. N 12. P. 39-50. MathWorks Tools Help Land Unpiloted Boeing Spacecraft. MathWorks User Stories. (https://tagteamdbserver.mathworks.com/ttserverroot/Download/452_9797v00_Boeing_S MV_ROI.pdf) Glesner S., Geiss R., Boesler B. Verified Code Generation for Embedded Systems. // Electronic Notes in Theoretical Computer Science. 2002. 65. N 2. Grochtmann M., Grimm K. Classification-Trees For Partition Testing. // Software Testing, Verification and Reliability. 1993. N 3 (2). P. 63-82. Sturmer I. Integration of the Code Generation Approach in the Model-Based Development Process By Means Of Tool Certification. // Journal of Integrated Design and Process Science. 2004. Vol. 8 (2). P.1-11 С.В. Зеленов, С.А. Зеленова, А.С. Косачев, А.К. Петренко. Применение модельного подхода для автоматического тестирования оптимизирующих компиляторов // CIT Forum, 2003. http://www.citforum.ru/SE/testing/compilers/
139
Рис. 4. Графическая модель сгенерированных тестовых данных для оптимизации SwitchBlock (пример 1). В этой модели Swith2.threshold = Switch3.threshold = -1. Оба блока всегда будут передавать на выход сигнал с верхнего входа; в результате оптимизации блок Switch2 может быть удален из модели. Величина сигнала на входе control блока Switch1 не может быть оценена на основе анализа данной системы, поскольку этот сигнал подается извне. Пример 2. Тестовые данные для оптимизации Flowchart. Графическая модель тестовых данных для примера 2 изображена на Рис. 5. 140
Рис. 5. Графическая модель сгенерированных тестовых данных для оптимизации Flowchart (пример 2). Этот граф содержит два простых цикла. Условия переходов таковы, что в процессе исполнения ни при каких значениях входного сигнала на верхнем цикле зацикливания не произойдет, а на нижнем зацикливание возникнет при любых входных сигналах.
141
Интегрированная среда описания системы команд встраиваемых процессоров В.В. Рубанов, А.С. Михеев Аннотация. В статье рассматривается интегрированная среда MetaDSP для описания системы команд встраиваемых процессоров. Такое описание включает спецификацию синтаксиса и поведения команд процессора и позволяет автоматически настроить набор кросс-инструментария разработки (ассемблер, дисассемблер, симулятор, отладчик), а также сгенерировать документацию прикладного программиста для целевого процессора. Эти возможности позволяют использовать MetaDSP и соответствующий настраиваемый кросс-инструментарий на этапе дизайна аппаратуры для прототипирования встраиваемых процессоров.
1. Введение В последнее время за счет развития технологий и удешевления производства, появляется огромное количество так называемых встраиваемых процессоров и их модификаций. К таким процессорам, в частности, относят цифровые процессоры обработки сигнала (DSP) и микроконтроллеры. Встраиваемые процессоры характеризуются ориентированностью на оптимальное (с точки зрения стоимости, размера кристалла, производительности и энергопотребления) решение узкого класса конкретных задач. В процессе создания таких решений важным этапом является прототипирование возможных альтернатив дизайна (Design Space Exploration – DSE). Для этого важно уметь получать оценки эффективности реализации конкретных алгоритмов и программ для возможных модификаций предполагаемого процессора. Одним из методов решения этой задачи является использование настраиваемых кросс-средств разработки, которые позволяют получать искомые оценки с помощью симуляции и профилирования тестовых программ для целевого прототипа с использованием инструментальной машины [11]-[12]. Для настройки инструментальных средств (прежде всего, ассемблера и симулятора/профилировщика) на конкретный целевой процессор необходимо уметь эффективно и формально задавать спецификацию этого процессора. Заметим, что для построения ассемблера и симулятора нет необходимости задавать детали реализации процессора на низком уровне, как это делается в синтезируемых описаниях на Verilog или VHDL. Для целей проверки 143
функциональной корректности тестовой программы и ее временных характеристик достаточно описать систему команд процессора (синтаксис, поведение и свойства команд, а также регистры и подсистему памяти). В данной работе рассматривается интегрированная среда MetaDSP, которая позволяет визуально описывать систему команд встраиваемых процессоров. Необходимость разработки интегрированной среды с графическим интерфейсом обусловлена требованиями возможности быстрого внесения согласованных изменений и автоматической верификации описаний «на лету». Ввиду наличия во встраиваемых процессорах, как правило, нерегулярной системы команд с множеством различных форматов, внесение изменений напрямую в текст спецификации чревато большим количеством ошибок. Среда MetaDSP позволяет упростить внесение изменений, обеспечивая при этом средства контроля над согласованностью изменений в ассемблере, дисассемблере, симуляторе и документации пользователя. Статья состоит из введения и пяти разделов. В первом разделе представляется общая архитектура системы MetaDSP. Второй и третий разделы характеризуют возможности системы MetaDSP по описанию синтаксиса/бинарного кодирования и поведения команд соответственно. В четвертом разделе дается описание концепции иерархического описания системы команд и наследования кода операции, операндов и поведения. Пятый раздел содержит описание основных элементов интерфейса пользователя системы MetaDSP.
2. Архитектура системы MetaDSP Система MetaDSP предназначена для автоматизации описания системы команд встраиваемых процессоров с целью обеспечения последующей автоматической настройки ассемблера, дисассемблера, симулятора, отладчика и генерации документации прикладного программиста. При таком подходе вся необходимая информация содержится в одном месте, а именно в файле описания MetaDSP, что позволяет поддерживать целостность и согласованность этого описания для использования в процессе настройки соответствующих кросс-инструментов. При этом уменьшается количество ошибок, ускоряется процесс внесения изменений и повышается наглядность описания. Эти характеристики очень важны для использования рассматриваемой системы в процессе прототипирования встраиваемых процессоров. Общая схема форматов описания MetaDSP и их использование для настройки соответствующих кросс-инструментов показаны на Рис. 1. Из файла описания MetaDSP генерируется файл спецификации синтаксиса команд и бинарного кодирования на языке ISE [14], который используется для настройки ассемблера, дисассемблера и отладчика, а также декодера симулятора. Основная часть симулятора процессора генерируется из файлов на языке ISE-Exec, в которых определяется поведение каждой инструкции. 144
Документация прикладного программиста для целевой системы команд генерируется из описания MetaDSP в виде документа MS Word. Описание MetaDSP
Дефисы в этой строке не являются значимыми и используются для косметического разграничения групп битов. Символы 0 и 1 ставятся на местах, которые вместе образуют так называемый код операции (КОП). Символ X означает, что данная битовая позиция не используется (может быть как 0, так и 1). Другие символы обозначают, что на данных местах располагаются коды операндов (в данном примере заданы операнды YY, SS и AA).
3.2. Ассемблерный синтаксис инструкции
Синтаксис и кодирование команд на языке ISE
Поведение команд на языке ISE-Exec
Файл MS Word
Ассемблер и дисассемблер
Симулятор, профилировщик и отладчик
Документация прикладного программиста
Синтаксис команды задается строковым шаблоном, в котором можно использовать комбинацию статических символов и ссылок на операнды, заключенных в фигурные скобки. Ссылки на операнды должны быть разделены статическим текстом, пробелы не являются значимыми: IF {cond} XOR {GRs}, {GRt} Здесь IF, XOR и запятые задают статическую часть синтаксиса команды, а cond, GRs и GRt являются ссылками на операнды. Синтаксис операндов определяется их типом, который задается отдельно для каждого операнда.
Рис. 1. Форматы описаний в системе MetaDSP и их использование
3.3. Операнды инструкции Таким образом, для различных целей (настройки различных инструментов и генерации документации) требуется свое подмножество общего описания системы команд; при этом эти подмножества имеют различные пересечения. Например, информация о бинарном кодировании команд используется для настройки всех инструментов и для генерации документации. Информация о поведении команд используется только для настройки симулятора и профилировщика, а информация об ассемблерном синтаксисе инструкций – для настройки ассемблера, дисассемблера, отладчика и генерации документации. Использование среды MetaDSP позволяет согласованно вносить изменения в различные части описания системы команд и корректно учитывать эти изменения при настройке всех инструментов.
3. Описание синтаксиса и бинарного кодирования команд В этом разделе описываются возможности системы MetaDSP для спецификации бинарного кодирования инструкции, ее ассемблерного синтаксиса, статических свойств и ограничений, а также правил определения межкомандных конфликтов.
3.1. Бинарное кодирование инструкции Бинарное кодирование команды (формат) задается в виде строки вида:
Для каждой команды описывается ноль или более операндов. При этом для каждого операнда задаются следующие параметры: имя операнда, определяющее ссылку на операнд в строке синтаксиса команды (например, GRs); тип операнда (например, регистр общего назначения, адресный регистр, 8-битная константа и так далее). Типы операндов задаются отдельно и определяют семантику в виде ссылки на объект в состоянии симулятора, синтаксис, разрядность и кодирование в виде перечисления пар значений – {синтаксис=код}. Например, {{GR0=00}, {GR1=01}}. Заметим, что тип операнда не определяет место кодирования операнда в машинном слове; место кодирования операнда в бинарном коде инструкции в виде строки, в которой буквы, отличные от X, определяют положение кода операнда (наиболее значимый бит слева). Например, ХХХХ-XXXXXXXX-XXAA определяет положение двухбитового операнда AA в двух младших битах машинного кода команды. Коды различных операндов в принципе могут перекрываться, если это не вызывает конфликта, кроме того, код операнда может иметь разрывы, например, четырехбитный операнд AAAA может кодироваться, как ХХХХXXXX-XAXA-XXAA – такие возможности очень важны для описания нерегулярных систем команд.
00YY-0000-SSAA-XXXX 145
146
3.4. Ограничения на значения и связи операндов В ряде случаев для данной инструкции допустимыми являются не все возможные значения операнда данного типа. Например, если в данной инструкции в качестве операнда GRt могут использоваться только регистры общего назначения GR0, GR1, GR2, GR3, а не все 16 регистров, имеющиеся в процессоре, то необходимо отдельно описать ограничения на такой операнд. Ограничения можно задать в виде предикатов. Если предикат ложный, то ограничение не выполнено, и ассемблер выдаст сообщение об ошибке. Например, для операнда GRt ограничение можно задать так: Predicate : GRt =GRt*2 представляет собой пример допустимого предиката. Использование предикатов над несколькими операндами позволяет задать ограничения на связи операндов, например, GRs=GRt обозначает тождественность операндов в синтаксисе.
3.5. Межкомандные конфликты Каждой команде можно назначить некоторый набор свойств и задать для них значения и области активации. В качестве значения свойства может выступать либо константа, либо значение одного из операндов команды. Область активации задает диапазон соседних команд, на котором данное свойство активно. По умолчанию [1;1] область активации затрагивает только текущую команду. Пример:
указывается набор пар свойств (пары разделяются запятыми, свойства в паре – знаком «=»). Предикат истинен для пары команд, когда выполняются следующие условия: первая команда обладает всеми свойствами из левых частей пар, вторая обладает всеми свойствами из правых частей пар; при этом для каждой пары значения свойств совпадают на пересечении их областей активации. Предикаты совместимости оцениваются ассемблером для всех пар команд при ассемблировании программы - так обнаруживаются конфликтующие команды. Заметим, что оценки работают гарантированно корректно только на линейных участках. Пример: [write_acr=read_acr] % warning: “WAR conflict for ACRs” Данный предикат будет верен, если у пары команд значение свойства write_acr первой команды совпадет со значением свойства read_acr второй команды на пересечении областей активации этих свойств. В данном примере это отражает конфликт по данным (по аккумуляторным регистрам) типа WRITE AFTER READ. Зарезервировано специальное свойство «any», которым по умолчанию обладает любая инструкция. [any=X] дает истинный предикат, если вторая инструкция обладает свойством X (независимо от его значения).
3.6. Дополнительная информация об инструкции Дополнительно для каждой команды можно указать:
MAC {acr},{grs},{grt} [read_grn:grs, read_grn:grt, write_acr:acr:2;2] Данная команда обладает следующими свойствами: read_grn – двойное свойство со значениями, равными значениям операндов grs и grt. Область активации по умолчанию затрагивает только текущую команду (здесь это означает, что значения регистров, заданных операндами grs и grt, читаются на первом такте); write_acr – значение свойства равно значению операнда acr. Область активации [2;2] затрагивает следующую команду (здесь это означает, что значение acr будет записано на втором такте). На механизме описания свойств базируется способ задания ограничений на использование ресурсов. Задается список предикатов совместимости свойств. В предикате совместимости свойств в квадратных скобках 147
идентификатор команды;
текстовое описание на естественном языке;
указание на то, что инструкция состоит из нескольких параллельно выполняющихся частей;
различные метрики инструкции, такие как количество тактов, которое занимает выполнение данной инструкции, энергия, потребляемая процессором при выполнении данной инструкции, и т.п. Эти данные используются профилировщиком.
4. Описание поведения команд В этом разделе рассматриваются средства системы MetaDSP для описания поведения инструкций. Для этой цели используется язык ISE-Exec, являющийся расширением C++. Описание на этом языке проходит через генератор, который преобразует его в чистый С++. Цель разработки этого языка состоит в том, чтобы повысить уровень абстракции для учета специфических потребностей и более удобного описания поведения команд процессора. 148
4.1. Обращение к операндам и битовым полям При описании поведения инструкции необходимо знать конкретные значения операндов инструкции. В рассматриваемом языке эти значения можно получить двумя путями.
Путем использования просто имени операнда, как обычной переменной. Такая ссылка автоматически преобразуется в необходимый код, который извлечет нужное значение из машинного кода команды в процессе симуляции.
Путем непосредственного обращения к именованным битовым полям машинного слова. Это осуществляется с помощью использования синтаксиса: #[+]LLLL Здесь символ + является не обязательным; если он есть, то закодированное число нужно трактовать как знаковое. На месте LLLL может быть любое количество подряд идущих букв в бинарном коде инструкции. При задании этих букв нужно следить, чтобы их положение в бинарном шаблоне команды определялось однозначно (см. 3.1). Вот простой пример обращения к битовым полям инструкции: MOVE {XM0}({YAv} + {offset}), {GRs} с кодом: 00DX-0100-01AA-RRRR-MMMM-MMMM Данная инструкция осуществляет пересылку в память с именем XM0 (это может быть память данных DM0 или TM0) регистра общего назначения GRs (в качестве GRs может выступать один из регистров общего назначения GR0,GR1,…, GRF). Адрес является суммой явно заданной константы offset и значения адресного регистра YAv (это может быть один из адресных регистров DA0 или TA0). Здесь кодирование соответствует операндам следующим образом: D : Destination memory field (XM0) AA : Destination address pointer field (YAv): RRRR : General register field (GRs): MMMMMMMM : offset field constant [-128;127] При описании поведения возможны следующие выражения: GRs, #RRRR, YAv + #+MMMMMMMM
4.2. Обращение к состоянию процессора и системы Состояние процессора и системы задается значением регистров и всех памятей системы. Обращение к этим ресурсам происходит следующим образом.
Обращения к памяти осуществляются с помощью макроса: MEM(memory_name, address) 149
Здесь memory_name обозначает индекс памяти, а address – адрес, по которому идет обращение. Обращение к регистрам производится путем использования макросов вида: (register_name) Здесь register_type – тип регистра, а register_name – имя или код регистра этого типа. Например, для описанной выше инструкции MOVE XM0(YAv + offset), GRs поведение можно задать так: MEM(XM0, ARN(YAv)+offset) := GRN(GRs); Здесь YAv – адресный регистр типа ARN, а GRs – регистр общего назначения типа GRN. Стоит обратить внимание на операцию «:=», использованную в данном примере. Эта операция необходима, если в левой или правой части присваивания используется ресурс системы (регистр или память). При этом обращение транслируется в соответствующие функции доступа (set/get), которые кроме собственно чтения/записи значения обеспечивают сбор необходимых статистик для профилировки. Допустимые типы памятей и регистров, их разрядность и размер задаются разработчиком общей части симулятора.
4.3. Микрооперации в описании поведения При описании поведения инструкции, помимо стандартных операций С++, можно использовать описываемые дополнительно микрооперации (например REVERSEBITS(REG)). Стандартные микрооперации входят в библиотеку поддержки; разработчик общей части симулятора может определить свои микрооперации.
4.4. Временные переменные в описании поведения При описании поведения инструкции можно использовать любое число временных переменных. При этом для удобства эти переменные можно не объявлять, а можно просто написать имя переменной в левой части операции ‘=’. После обработки генератором все определения переменных будут сгенерированы автоматически.
5. Иерархичность описания команд в системе MetaDSP В среде MetaDSP система команд описывается иерархично в виде дерева. Листьями дерева являются команды, промежуточные узлы соответствуют группам команд (группы могут быть вложенными). Например, инструкции пересылки можно разместить в одной группе дерева, арифметические в другой, инструкции управления в третьей. При этом инструкции пересылки можно 150
далее дробить на более мелкие группы: пересылки память-память, регистрпамять и т. д. Иерархичность описания системы команд позволяет использовать наследование определенных свойств от родительских групп. Наследование возможно для следующих элементов: код операции (КОП), отдельные операнды и поведение. Наследование этих свойств может выполняться независимо и позволяет автоматизировать изменение групп инструкций, так как изменения у родителя вызывают аналогичные изменения у всех его потомков.
5.1. Наследование кода операции Под наследованием кода операции (КОП) подразумевается наследование битовых полей, установленных в бинарном коде инструкции в фиксированные значения – ‘0’ или ‘1’. Например, пусть есть две инструкции: MOVE GRs, GRt с кодом 0111-0011-GGGG-RRRR и MOVE ARs, GRt с кодом 0011-0011-AAAA-RRRR. Видно, что в этих двух инструкциях общим КОПом является: 0X11-0011-XXXX-XXXX В таких случаях в системе MetaDSP обычной практикой является вынесение описания общего КОП в родительский узел. При этом для каждого потомка этого узла можно указать, наследует ли он КОП родителя или нет (по умолчанию – да). Для узлов, наследующих КОП родителя, изменение значения зафиксированных в родителе битовых позиций запрещено, то есть в потомке можно определять только те позиции шаблона, в которых в родителе стоит X. Наследование КОП может быть многоуровневым в соответствии с организацией дерева системы команд. При добавлении новых потомков к родителю унаследованные биты КОП автоматически проставляются в потомке. Это ускоряет добавление новых инструкций.
5.2. Наследование операндов Под наследованием операндов подразумевается использование в инструкции родительских операндов. При этом изменение таких операндов возможно только на уровне родителя. В качестве примера возьмем те же инструкции, рассмотренные при описании наследования кода операции: MOVE GRs, GRt с кодом 0111-0011-GGGG-RRRR, где операнды GRs, GRt кодируются битами, помеченными в бинарном коде инструкции буквами GGGG и RRRR соответственно, и MOVE ARs, GRt с кодом 0011-0011-AAAA-RRRR, где операнды ARs, GRt кодируются битами, помеченными в бинарном коде инструкции соответственно буквами AAAA и RRRR. 151
Видно, что вторые операнды этих двух инструкций GRt имеют одинаковый тип и одинаковое положение в бинарном коде. Таким образом, если в дереве инструкций добавить родительский узел с определенным в нем операндом: Имя: GRt Тип: General Purpose Register Кодирование: XXXX-XXXX-XXXX-RRRR, а затем добавить к этому родительскому узлу двух потомков: MOVE GRs, GRt с операндами: Имя: GRs Унаследован: нет Тип: General Purpose Register Кодирование: XXXX-XXXX-GGGG-XXXX, Имя:
GRt Унаследован: да
и MOVE ARs, GRt с операндами: Имя: ARs Унаследован: нет Тип: Address Register Кодирование: XXXX-XXXX-AAAA-XXXX, Имя: GRt Унаследован: да то эти потомки будут содержать унаследованный операнд GRt. При изменении каких либо свойств этого операнда в родительском узле соответствующие изменения автоматически применятся к потомкам. Опыт авторов показывает, что в условиях должной организации дерева команд при добавлении новой инструкции большая часть операндов наследуется от родительского узла. Наследовать можно любое количество операндов, по-разному расположенных в бинарном коде родителя, в том числе и с перекрытием. При удалении операнда у родителя соответствующий унаследованный операнд удаляется у всех потомков.
5.3. Наследование поведения инструкций Поведение инструкции задается в виде кода на языке ISE-Exec, описанном в разделе 4. Под наследованием поведения подразумевается использование в описании поведения команды определенных частей родительского описания. Важность этого механизма обусловлена тем, что при описании поведения часто возникают ситуации, когда у нескольких дочерних инструкций описания очень похожи между собой. Чаще всего похожи начала или концы этих описаний (например, загрузка и выгрузка данных), а в середине они различны (обработка данных, специфичная для каждой команды). Поэтому в системе 152
MetaDSP существует возможность определить общие части поведения в родительском узле и наследовать их в потомках. Описание поведения у каждого узла дерева системы команд разделяется на две части: начало и конец. При этом в описании, принадлежащем данному узлу, можно использовать операнды, видимые на уровне этого узла. Дочерние узлы могут наследовать начало и конец описания родителя, то есть начало описания дочернего узла является конкатенацией начала описания родителя и своего начала, а конец описания дочернего узла является конкатенацией своего конца и конца описания родителя (матрешка). При таком подходе общий код в потомках большей частью может быть вынесен на уровень родителя, что обеспечивает более удобное и быстрое внесение изменений, а также уменьшает количество ошибок.
Основные окна программы: Instruction Set – это окно (Рис. 3) отображает дерево инструкций и является основным элементом навигации. При выделении определенного узла дерева информация об этом узле автоматически отображается в других окнах. Узлы дерева имеют контекстное меню, позволяющее удалять, копировать и добавлять новые узлы:
Рис. 3. Окно Instruction Set. Instruction Properties – это окно (Рис. 4, 5) отображает и позволяет редактировать свойства узлов, в частности бинарное кодирование, синтаксис, операнды и ограничения:
Рис. 2. Графический интерфейс системы MetaDSP.
6. Интерфейс системы MetaDSP Визуальная часть среды MetaDSP реализована на С++ с использованием графического интерфейса Windows и элементов управления библиотеки Codejock Xtreme Toolkit. Программа использует многооконный интерфейс с плавающими окнами (Рис. 2). 153
Рис. 4. Задание шаблона бинарного кодирования в окне Instruction Properties. 154
зону и зону, унаследованную от родителя (темный фон). Текст в унаследованных зонах заблокирован для редактирования (он задается в родителе - см. 5.3). Operand Types – в этом окне (Рис. 7) описываются глобальные типы операндов, которые потом используются при задании операндов в командах: Добавление, удаление и изменение типов осуществляется с помощью контекстного меню (Рис. 8).
Рис. 5. Задание ограничений в окне Instruction Properties.
Рис. 6. Окно поведения команды. Рис. 8. Диалог редактирования типов операндов. Additional Information – в этом окне задается дополнительная информация для системы команд в целом: описание межкомандных конфликтов, список свойств команд, список сообщений об ошибках. Свойства команд и сообщения об ошибках используются при задании ограничений (как внутрикомандных, так и межкомандных). Output – в это окно выводятся сообщения об ошибках или предупреждениях при автоматической верификации описаний, а также выводятся результаты аналитических запросов (в частности, статистика об использовании бинарного пространства и свободных кодах). Рис. 7. Окно типов операндов. Simulator Description – в этом окне (Рис. 6) описывается поведение команды. Окно разделено на две части, каждая из которых разделяется на собственную 155
156
7. Заключение В данной работе представлены возможности интегрированной среды MetaDSP по описанию системы команд для встраиваемых процессоров. Используя MetaDSP, можно определить синтаксис, бинарное кодирование и поведение команд в степени, достаточной для автоматической настройки основных кроссинструментов разработки: ассемблера, дисассемблера, симулятора с профилировщиком и отладчика. Кроме того, использование автоматической верификации описаний, графического интерфейса с встроенными контекстными редакторами и иерархичность описания команд позволяют значительно повысить эффективность редактирования процессорных описаний и внесения согласованных изменений, тем самым сокращая цикл внесения типовых изменений и их отладки для десятка команд до минут в сравнении с часами и даже днями без использования интегрированной среды. Это позволяет использовать эту систему для проведения этапа проектирования (DSE) в процессе разработки встраиваемых решений. При этом получаемые кросс-инструменты обладают качеством, достаточным для производственного применения при разработке прикладных программ для целевой системы. Система MetaDSP была успешно применена в коммерческих проектах с компаниями Freehand и VIA Technologies, в которых были получены наборы инструментальных средств кросс-разработки для пяти различных встраиваемых процессоров (включая процессоры цифровой обработки сигналов и RISC-контроллер) и десятков их модификаций.
12. 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. 13. Prabhat Mishra, Frederic Rousseau, Nikil Dutt, Alex Nicolau. Architecture Description Language Driven Design Space Exploration in the Presence of Coprocessors. SASIMI 2001. 14. В.В. Рубанов, Д.А. Марковцев, А.И. Гриневич. Динамическая поддержка расширений процессора в кросс системе. Труды ИСП РАН, том 5, 2004.
Литература 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. A. Fauth, J. Van Praet, M. Freericks. Describing Instruction Set Processors Using nML. Proc European Design and Test Conf., Paris, March 1995. 7. 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. 8. Sim-nML Homepage. http://www.cse.iitk.ac.in/sim-nml/ 9. ISDL Project Homepage. http://caa.lcs.mit.edu/caa/home.html 10. George Hadjiyannis, Silvina Hanono. ISDL: An Instruction Set Description Language for Retargetability. Srinivas Devadas. Department of EECS, MIT. DAC 1997. 11. EXPRESSION Homepage. http://www.cecs.uci.edu/~aces/index.html
157
158
Использование языков описания процессоров высокого уровня для генерации платформо-зависимых частей операционной системы Ю. Фонин Аннотация. В статье проанализированы языки описания архитектуры процессора. Рассмотрены основные элементы микропроцессора. Выделены базовые элементы архитектуры процессора, необходимые для генерации ядра операционной системы, их параметры и свойства.
1. Введение В настоящее время аппаратное обеспечение все чаще и чаще разрабатывается под конкретное системное программное обеспечение. Такой подход позволяет добиться оптимизации конечной программно-аппаратной системы по многим критериям: производительность, стоимость, потребляемая мощность. Основным достоинством данного подхода является возможность адаптировать аппаратные ресурсы под требования конкретного программного обеспечения. Процесс разработки носит интерактивный характер. При каждом изменение в аппаратном обеспечении требуется модификация системного программного обеспечения (компилятор, компоновщик, операционная система). Внесение таких изменений вручную может занимать до нескольких человеко-месяцев и тем самым значительно замедлять процесс разработки системы. Представленное в статье формальное описание архитектуры позволяет разрабатывать системы для автоматического анализа процессора и генерации системного программного обеспечения. Данное описание строится по аналогии с промежуточным представлением, используемым компиляторами языков высокого уровня с учетом специфики архитектуры процессора. В качестве генератора такого описания может выступать компилятор языка описания архитектуры (ЯОА). Подобные языки используются для разработки процессоров, причем как для создания непосредственно чипа или его программного симулятора, так и для автоматической генерации соответствующего программного обеспечения (компилятора, ассемблера, отладчика). Статья состоит из введения, трех разделов и заключения. Во втором разделе статьи представлен краткий обзор существующих языков описания 159
архитектур, приводятся основные конструкции таких языков. В разделе 3 перечисляются базовые элементы процессора, а также свойства и характеристики элементов, необходимые для генерации операционной системы. Последний раздел содержит описание базовых элементов операционной среды, полученных в процессе структурно-функционального проектирования архитектуры процес-сора. В заключении приводится план будущих направлений развития темы.
2. Языки описания архитектуры процессора В настоящее время существуют три различных стиля для описания архитектуры процессора: структурный, поведенческий и смешанный [1]. Зачастую при описании конкретной архитектуры используются все три типа стилей. Структурное описание используется в основном для проектирования цифровых схем, поведенческое, как правило, – для моделирования, так как содержит конструкции, которые невозможно реализовать в виде схемы.
2.1. Структурное описание (structural description) Структурное описание соответствует стилю описания, используемому в языках регистровых передач, когда архитектура представляется в виде иерархии связанных компонентов. Для спецификации аппаратуры на уровне регистровых передач (register transfer level — RTL) используются языки категории HDL (Hardware Description Languages), наиболее известными из которых являются Verilog [2] и VHDL [3]. В качестве примера языка структурного описания приведем язык MIMOLA [4]. Описание процессора на языке MIMOLA представляется в виде набора блоков, таких как арифметико-логическое устройство, регистры и шины для доступа к памяти, а также набора соединений между блоками. Анализировать такое описание для генерации компилятора или операционной системы сложно. Поэтому в языке MIMOLA предусмотрена возможность ввода дополнительной спецификации компонентов, а именно, предназначение регистров или расположение памяти программ: LOCATION_FOR_PROGRAMCOUNTER PCReg; LOCATION_FOR_INSTRUCTIONS IM[0..1023]; Такие спецификации позволяют получить дополнительную информацию об элементах процессора, необходимую для автоматической генерации компиляторов, операционных систем и создания отладочного программного обеспечения. В частности, в приведенном выше примере указано, что регистр PCReg является регистром счетчика команд, а область памяти IM[0..1023] предназначена для хранения инструкций. Однако отсутствие представления инструкций процессора в явном виде делает процесс автоматической генерации модулей операционной системы крайне сложным. 160
2.2. Поведенческое описание (behavioral description) Для решения задачи автоматической генерации компонентов операционной системы предназначены языки поведенческого класса ADL (Architecture Description Languages), в которых функциональность каждой инструкции описывается в явном виде. Рассмотрим более подробно некоторые из таких языков. К языкам класса ADL относится язык nML [5]. В nML система команд процессора описывается с помощью атрибутных грамматик. Атрибуты включают в себя поведение (action), ассемблерный синтаксис (syntax) и отображение в машинные коды (image). В исходном варианте nML отсутствовали механизмы описания многотактовых команд. В последних версиях nML поддерживается синтез VHDL-описания. В nML инструкция или группа инструкций описывается в виде отдельного блока, например: op num_instruction(a:num_action, src:SRC, dst:DST) action { temp_src = src; temp_dst = dst; a.action; dst = temp_dst; } op num_action = add | sub | mul | div op add() action = { temp_dst = temp_dst + temp_src } ... Данный пример содержит функциональное описание блока инструкций. Описывается группа инструкций num_instruction, выполняющих базовые арифметические операции: сложение, вычитание, умножение и деление. При вызове данной инструкции выполняются следующие операции: 1. Значение аргумента src заноситься в переменную temp_src; 2. Значение аргумента dst заноситься в переменную temp_dst; 3. В зависимости от значения аргумента a выполняется одна из четырех возможных операций (a.action); 4. Результат операций сохраняется в dst. Множество возможных операций определяется типом аргумента a (num_action). В приведенном примере это множество состоит из четырех операций: add | sub | mul | div. Для каждой операции разработчик должен описать ее функциональность в блоке action (см. пример описания операции add). Как видно из примера, функциональность инструкции или группы инструкций в nML может быть описана в виде иерархии функциональных блоков или групп 161
функциональных блоков. В приведенном примере такой группой является группа из блоков add, sub, mul и div. Подобное описание позволяет получить в явном виде дерево каждой инструкции, описывающее ее функциональность, которое может быть использовано для генерации компилятора или операционной системы. Последователем nML стал язык Sim-nML [6]. Основное отличие состоит в присутствии в грамматике описания команд дополнительного атрибута использования ресурсов (uses), что позволяет специфицировать использование ресурсов и, тем самым, обнаруживать конфликты между командами. В рамках проекта Sim-nML были разработаны генераторы, позволяющие автоматически генерировать программные коды симулятора, ассемблера и дисассемблера на основе спецификации процессора на языке Sim-nML.
2.3. Смешанное описание Языки смешанного типа похожи на поведенческие языки, однако они позволяют при описании инструкций специфицировать использование конкретных аппаратных блоков, например, арифметико-логического устройства или специальных умножителей, а также описывать конвейер инструкций. В смешанных языках, как и в поведенческих, инструкции описываются в явном виде. Но при создании дерева инструкций могут возникать трудности, связанные с извлечением информации о функциональности внешних блоков. Язык EXPRESSION [7] позволяет создавать интегрированное описание структуры и поведения подсистемы процессор-память. Спецификация на EXPRESSION состоит из шести секций (первые три отвечают за поведение, последние три – за структуру): спецификация операций: набор атомарных команд с кодами, описанием параметров и семантики (поведения); описание формата команды: команда состоит из ячеек, ответственных за определенный функциональный модуль, которые могут заполняться атомарными операциями для параллельного выполнения; отображение общих операций компилятора на машинные операции, описанные в первой секции; данное описание используется в кодогенераторе компилятора; описание компонентов: функциональные устройства, шины, порты и т.п.; описание конвейера и связей компонентов; описание иерархии памяти: регистровая память, кэш, SRAM, DRAM. Язык LISA [8] разрабатывался в качестве средства описания аппаратуры для генерации симуляторов. К ключевым характеристикам LISA можно отнести подробное описание конвейера на уровне операций с возможностью задания зависимостей и блокировок. Конвейерные конфликты задаются явно. Каждая команда специфицируется в виде набора операций, которые определяются как регистровые пересылки за время одного такта синхронизации. Описание 162
аппаратуры на языке LISA состоит из двух основных частей: спецификации ресурсов и описания операций. Описание операций в свою очередь содержит следующие секции: DECLARE: определение объектов и групп через другие объекты и операции – фактически, правила грамматики; CODING: описание бинарного кодирования операции; SYNTAX: описание ассемблерного синтаксиса и параметров; BEHAVIOR и EXPRESSION: описание поведения операции в виде кода на языке C/C++; ACTIVATION: описание задержек (timings) и поведения конвейера. Языки LISA и EXPRESSION позволяют детально описать архитектуру процессора, что важно для синтеза микросхемы. С другой стороны, поскольку инструкции процессора описаны в явном виде, создание систем автоматической генерации операционных систем на основе EXPRESSION или LISA-описаний процессора существенно проще, чем создание таких систем на основе структурных языков. К недостаткам решения на основе этих языков по сравнению с поведенческими языками следует отнести относительную трудоемкость описания архитектуры, связанную с необходимостью детально описывать структурную составляющую. В этом смысле языки EXPRESSION и LISA стоят между чистыми поведенческими ADL-решениями (типа nML) и структурными описаниями уровня HDL.
одной стороны, можно получить из ADL-описания процессора, а с другой стороны, являются необходимыми для генерации ОС.
3.1. Структурное и поведенческое описание процессора Структурные элементы описываются набором свойств, соответствующих типу элемента. Функциональные элементы описываются деревом функциональности. Узлами дерева являются микрооперации, указатели на структурные элементы или множества элементов. Функциональный базис определяет множество возможных элементарных операций, которые могут быть применены при описании инструкций. ASG
ADD REG
1
2.4. Выводы Анализ современных ADL высокого уровня показывает, что из ADL-описания процессоров можно получить сведения о структуре и функциональности процессора. Фактически, вопрос состоит только в степени сложности использования того или иного языка категории ADL для автоматической генерации операционной системы. Отметим также, что для генерации операционной системы требуется лишь некоторое подмножество информации об архитектуре, которая может быть получена из описания процессора. Поэтому целесообразно разработать некий формат промежуточного представления (ПП) процессора, аналогичный представлению, применяемому в компиляторах языков программирования высокого уровня. Такое представления, в первую очередь, должно быть удобным и полным для генерации ОС, а с другой стороны, должна существовать возможность создания ПП на основе конструкций языков ADL.
3. Компоненты промежуточного представления архитектуры, необходимые для автоматической генерации ОС
ARG
2
1
Рис. 1. Пример функционального дерева для инструкции ADD Ri, #IMM На Рис 1 приведен пример представления инструкции сложения регистра с константой. При описании инструкции использованы следующие микрооперации: ADD (op1,op2) – сложение двух операндов; ASG (dst,src) – присвоение элементу dst значения выражения src; REG (lst,idx) – регистр с индексом idx из списка регистров с номером lst; ARG(NUM) – значение аргумента инструкции с номером NUM.
3.2. Базовые элементы архитектуры микропроцессора Архитектура процессора описывается на основе набора базовых элементов. Рассмотрим более подробно базовые элементы, приведенные на Рис.2.
Для автоматической генерации ОС на основе ADL-описания процессора необходимо, выделить список базовых элементов процессора, которые, с 163
ARG
164
номер бита в регистре; ассемблерное имя.
Базовые элементы
Структурные
Функциональные
Регистры/массивы регистров Флаги Шины памяти Сигналы прерывания
Инструкции Аппаратные обработчики прерываний
Регистр флагов также является частью контекста. Однако возможна ситуация, при которой одна часть флагов одного регистра принадлежит контексту, а другая часть определяет состояние процессора в целом и не принадлежат контексту. В таком случае при переключении контекста операционной системой должна быть восстановлена только та часть регистра флага, которая определяет состояние исполняемой программы.
3.2.3. Память процессора
Рис. 2. Базовые элементы процессора.
3.2.1. Регистры Регистры процессора предназначены для хранения промежуточных результатов вычислений (регистры данных), адресов (адресные регистры) и информации о режиме работы процессора (системные регистры). Каждый регистр описывается следующими параметрами: размер регистра в битах; ассемблерное имя (если есть); список подрегистров (если есть). Множество регистров, используемых для хранения промежуточных данных пользовательской программы, называется контекстом. Если операционная система поддерживает многопоточность (multi-threading), то ее частью является функция переключения контекста. При переключении контекста операционная система должна сохранить регистры прерываемой задачи и восстановить регистры загружаемой задачи.
3.2.2. Флаги Флаги – это элементарные однобитовые ячейки памяти. Флаги могут быть использованы для хранения результатов арифметических операций, например, бита переполнения или знака результата. Кроме того, специальные флаги могут использоваться для управления системой прерываний. Часто флаги являются битами регистров, и изменение состояния флага возможно только через изменение значения регистра. Флаги характеризуются следующими свойствами: имя регистра, которому принадлежит флаг; 165
Информацию о доступной процессору памяти можно описать в виде набора из трех компонентов: шины, блоки памяти и соединения. Рассмотрим составляющие каждого из компонентов. Шины Шина предоставляет интерфейс для работы процессора с памятью и описывается следующим набором характеристик: размер шины адреса (в битах); размер шины данных (в битах). Блоки памяти Блок памяти определяет имеющуюся физическую память и описывается следующим набором характеристик: размер блока в байтах; размер одной адресуемой ячейки памяти (в битах); тип памяти: только для чтения или для чтения и записи. Соединения Соединение описывает отображение блоков физической памяти на адресное пространство и определяется следующим набором характеристик: блок памяти; шина памяти, через которую осуществляется обращение к блоку; стартовый адрес, с которого начинается блок. Информация о блоках памяти необходима для конфигурации менеджера памяти операционной системы. Как правило, операционная система сама отвечает за выделение памяти под стек. Кроме того, во многих современных ОС (включая ОС для встроенных систем) поддерживается динамическое выделение памяти. Таким образом, при портировании ОС на новую архитектуру необходимо иметь информацию о размере, адресах и типах блоков физической памяти, доступной процессору.
3.2.4. Прерывания Прерывания описываются следующим набором характеристик: номер сигнала – запроса на прерывание; 166
приоритет прерывания или регистр, значение которого определяет
приоритет прерывания; процедура обработки запроса на прерывания. Одной из задач операционной системы является корректная обработка прерываний процессора. Во многих современных ОС для встроенных систем имеются стандартные функции пролога и эпилога. Функция пролога сохраняет регистры и флаги процессора, которые могут быть модифицированы при запуске стандартных функций. Функция эпилога восстанавливает регистры процессора, сохраненные функцией пролога, а также осуществляет корректный возврат из прерывания. Наличие в ОС функций пролога и эпилога позволяет реализовывать драйверы устройств, а также стандартные обработчики прерываний (исключения и программные прерывания) на языке высокого уровня, не задумываясь об особенностях архитектуры конкретного процессора. Еще одной функцией ОС, связанной с обработкой прерываний, является динамическая инициализация обработчиков прерываний, а также динамическое управление приоритетами прерываний. Операционная система предоставляет набор функций для подключения обработчика прерывания и установки приоритета того или иного прерывания. Очевидно, что для реализации перечисленных функций необходима информация о прерываниях, аппаратных обработчиках прерываниях и приоритетах прерываний или способах установки приоритетов.
3.2.5. Инструкции Одним из основных компонентов архитектуры является набор инструкций. Каждая инструкция имеет следующий набор свойств:
длина кода инструкции – сколько байт в памяти занимает инструкция; шаблон бинарного кода инструкции; список аргументов; ассемблерный синтаксис – шаблон инструкции для языка ассемблера; дерево, описывающее функциональность инструкции; список режимов, в которых данная инструкция может быть выполнена; количество тактов, необходимых для выполнения инструкции. Аргумент инструкции:
стартовый бит в коде инструкции; длина аргумента в битах; шаблон аргумента для ассемблера. Информация о наборе инструкций процессора необходима для реализации функций операционной системы. 167
4. Выбор базовых элементов для построения ядра ОС Проведенный в разд. 2 анализ языков описания процессоров показывает, что в процессе структурно-функционального проектирования архитектуры процессора появляется также возможность выявления базовых элементов, необходимых для автоматической генерации ОС. Из модели описания архитектуры процессора явным образом можно выделить следующую информацию:
список регистров процессора; список флагов процессора; список сигналов «запрос на прерывание»; операции, выполняемые процессором при возникновении прерывания; адресные пространства памяти; список инструкций для генерации кода. Данный набор элементов архитектуры процессора является необходимым, но не достаточным для построения ядра ОС. Помимо перечисленных выше элементов, для построения операционной системы необходимо дополнительно описать следующие элементы:
список регистров контекста – множество регистров, которые должны быть сохранены при сохранении состояния задачи; указатель контекста – регистр, который содержит адрес в памяти для сохранения контекста; регистры состояния системы прерываний; регистры управления системой прерываний; счетчик команд. Для ряда процессоров перечисленная информация может быть получена из анализа архитектуры, однако это возможно не всегда. Например, в процессоре ARM7 любой из 16 регистров общего назначения может выполнять функции указателя контекста. В таких случаях необходима дополнительная спецификация элементов. Также существуют параметры, которые невозможно получить явным или неявным путем из описания архитектуры процессора. Такие параметры должны быть определены разработчиком при проектировании системы: список volatile-регистров, значения которых не восстанавливаются после вызова функций; распределение приоритетов прерываний, которое может быть определено только пользователем в соответствии с потребностями всей системы.
168
5. Заключение В статье рассмотрены особенности выделения и описания базовых элементов архитектуры процессора, необходимых для генерации ядра ОС, приведен обзор языков описания архитектуры процессора, а также описаны ключевые моменты, позволяющие достичь эффективного решения поставленной задачи. Дальнейшее развитие технологии автоматической генерации ОС на основе описания архитектуры процессора заключается в разработке методологии анализа структуры и функциональности процессора и создании алгоритмов генерации функций ОС на основе данного анализа. Литература 1. Architecture Description Languages for Retargetable Compilation. Wei Qin, Sharad Malik Department of Electrical Engineering Princeton University. 2. IEEE Standard Hardware Description Language Based on the Verilog® Hardware Description Language, IEEE Std 1364-1995. 3. IEEE Standard VHDL Language Reference Manual, IEEE Std 1076-1987. 4. The integrated design of computer systems with MIMOLA. Peter Marwedel University of Kiel.
169
Анализ и трансформации исполняемых UML моделей Е.Д. Волкова, А.Д. Страбыкин Аннотация. В статье1 рассмотрены конечные автоматы языка UML, представлен подход к анализу исполняемых моделей UML. На основании выборки моделей, использованных в промышленных проектах, исследованы их количественные свойства и продемонстрирована актуальность трансформации моделей. Выделены образцы, часто используемые при построении автоматов. Предложены новые трансформации, улучшающие структуру модели, описан процесс их применения к реальной системе.
1. Введение При создании сложных инженерных систем принято использовать приемы моделирования. Сложность большинства создаваемых сегодня программных систем не уступает сложности многих инженерных сооружений, поэтому моделирование программных систем является весьма актуальной задачей. Более того, в таких концепциях, как MDA (Model Driven Architecture – архитектура на основе моделей) и MDD (Model Driven Development – разработка на базе моделей), моделям отводится центральная роль в процессе создания программного продукта. Основной идеей этих концепций является представление процесса создания программного продукта в виде цепочки трансформаций его исходной модели в готовую программную систему. Почти во всех инструментальных средствах, воплощающих идеи MDD, в качестве языка моделирования используется язык UML (Unified Modeling Language – унифицированный язык моделирования), целиком или какие-либо его части. UML – это язык, предназначенный для визуализации, специфицирования, конструирования и документирования программных систем. Слово «унифицированный» в названии языка означает, что UML может использоваться для моделирования широкого круга приложений от встроенных систем и систем реального времени до распределенных webприложений. Выразительные средства языка позволяют описать систему со всех точек зрения, имеющих отношение к разработке и развертыванию.
1
Работа выполнена при поддержке РФФИ, проект 05-01-00998-а. 171
В свете инициатив MDA и MDD роль моделей в жизненном цикле программного обеспечения (ПО) претерпевает значительные изменения. Если ранее моделирование рассматривалось как одно из удобных средств документирования, и, соответственно, жизненный цикл моделей был близок к жизненному циклу артефактов документации, то в последнее время работа с моделями становится все более похожа на работу с исходными кодами. Подобный подход ставит перед исследователями новые задачи исследования применимости к моделям методик и приемов работы, используемых для работы с исходными кодами. Одной из таких методик является рефакторинг. Рефакторинг – это изменение внутренней структуры ПО, имеющее целью облегчить понимание и упростить модификацию, но не затрагивающее при этом наблюдаемого поведения. Рефакторинг, как набор методик преобразования программ, помогает решать две глобальные задачи: облегчение процесса повторного использования каких-либо компонентов программной системы и снижение расходов на поддержку и сопровождение системы. Первые рефакторинги появились в результате обобщения опыта нескольких экспертов в области объектно-ориентированного проектирования. В этом отношении рефакторинги достаточно близки к широко известным на сегодняшний день паттернам проектирования. Существует много исследовательских работ и публикаций, посвященных методам и алгоритмам применения рефакторинга. Полноценная поддержка рефакторинга ставит перед производителями следующий ряд задач: 1. Поиск плохо спроектированных участков кода (модели), для которых требуется проведение рефакторинга; 2. Определение рефакторинга (синтез из поддерживаемых базовых рефакторингов), который следует применить; 3. Проверка или доказательство неизменности поведения системы после выполнения преобразований; 4. Реализация применения рефакторинга и, в частности, разработка пользовательского интерфейса и диалогов, поддерживающих процесс применения рефакторинга; 5. Сохранение целостности модели, то есть распространение произведенных изменений на другие части модели (диаграммы, тесты); 6. Оценка эффекта, полученного в результате применения рефакторинга. По каждому из указанных пунктов ведутся научные разработки, но лишь в немногих из них учитывается специфика UML. Анализ существующих UML моделей, приводимый в данной статье, показывает, что их структура сложна для понимания и содержит недостатки, которые можно было бы устранить путём проведения эквивалентных трансформаций. Особое внимание уделяется анализу и поиску методов рефакторинга для конечных автоматов языка UML, которые являются основой для полностью автоматической генерации исполняемого кода по UML172
моделям. На базе проведённого анализа и выявленных описывается новая трансформация, специфичная для UML.
недостатков Название модели
2. Анализ исполняемых UML-моделей
Aircraft Simulator
С целью выявления особенностей использования конечных автоматов UML в реальных промышленных проектах было проведено статистическое исследование набора моделей. Все рассмотренные модели описывают поведение системы с использованием конечных автоматов, по которым можно сгенерировать исполняемый код. Конечные автоматы UML могут описывать поведение следующих элементов исполняемых моделей: активный класс (active class); операция (operation); составное состояние (composite state). В зависимости от своего происхождения, все исследованные модели UML можно разделить на два класса: 1. Модели, изначально спроектированные на языке UML (например, в таких программных системах, как Rational Rose, Telelogic Tau G2, ILogix Rhapsody, Borland Together); 2. Модели, изначально спроектированные на языке SDL (например, в таких программных системах, как Telelogic SDL Suite, Verilog ObjectGeode) и трансформированные в UML вручную или при помощи специальных утилит (например, Telelogic Tau G2 — Import SDL). Исполняемые UML-модели второго класса в основном описывают различного рода коммуникационные системы (то есть такие классы систем, для моделирования которых предназначен язык SDL). Исполняемые модели первого класса в связи с универсальностью языка UML описывают гораздо более широкий спектр систем.
Central Interface IOS Algorithms Llama Simulator MMI MV-IOS6 3gN ATM and Banklib Local Exchange Access Control
Mobile Pager cc_layer common Executor 1xevdo ATC_ENV CpCallm S SS_RCS Tarif_c7 DC2000_5 23 модели
173
Симулятор самолета Система контроля доступа Система ввода/ вывода
Банкомат
Система контроля доступа
DEL_REL Inres
2.1. Характеристика конечных автоматов Общая статистика по исследованным моделям представлена в таблице 1. Перечисленные модели были заимствованы из реальных проектов коммерческих компаний. Для сбора и анализа необходимой информации был разработан дополнительный модуль к промышленной среде UMLмоделирования Telelogic Tau G2. Ожидалось, что модели, используемые в реальных проектах, будут иметь достаточно высокий уровень сложности. Тем не менее, более 90% от всех описанных автоматов содержат не более трех состояний, а доля автоматов без состояний (включающих только один начальный переход) близка к 75% (Рис. 1). Причем доля таких автоматов растет вместе с размером модели.
Предмет моделирования
Мобильный телефон Пейджер
Происхо- Объем ждение (Кб)
Кол-во автоматов, реализующих Общее количество активпассивДиагсоставные ные опера-ции ные типы раммы состояния классы данных2
UML
371
1
2
0
0
34
UML
253
4
0
1
8
24
UML
1 611
11
41
2
70
203
UML
894
6
2
0
31
126
UML UML UML
3 267 675 8 660
17 5 12
20 0 175
0 0 0
45 14 2708
112 118 нет инф
SDL
144
4
1
0
4
12
SDL
178
3
5
0
2
13
SDL
281
8
1
0
10
34
SDL SDL
190 121
3 4
2 0
0 0
21 4
22 15
SDL
772
14
0
0
27
156
SDL SDL
161 1 066
3 3
4 19
0 0
4 45
14 39
SDL
1 396
5
39
0
12
89
SDL SDL SDL SDL SDL SDL
21 817 5 710 67 295 380 20 572 881
21 17 9 1 3 2
482 62 760 9 94 25
0 0 0 0 0 0
350 867 2262 0 175 4
1457 226 1009 34 547 104
SDL
19 420
33
226
0
447
1483
189
1969
3
7110
5871
8
86
0
309
267
7 - UML 152 М 16 - SDL В среднем: 6.6 М
Таблица 1. Следует отметить, что автомат без состояний практически не обладает семантикой автомата и может использоваться только в качестве одной из форм записи некоторой последовательности действий, выполняемой в процессе во время начального перехода. Более того, текстовый синтаксис кажется намного более удобным средством для подобных спецификаций. Таким образом, оказывается, что в промышленных проектах примерно в половине случаев 2
174
В колонке «пассивные типы данных» учитывались следующие типы: пассивный класс, тип данных (datatype), перечислимый тип (enum), синоним типа (syntype), объединение (choice)
конечные автоматы используются не по своему прямому назначению. Причиной этому может служить недостаточный уровень владения инструментом у разработчиков модели или же, например, требование унифицировать все описания поведенческих аспектов системы с использованием для этого конечных автоматов.
>6 состояний 9%
0 состояний 1%
4-6 состояний 18% 1 состояние 45%
2-3 состояния 8%
4-6 состояний >6 состояний 2% 4%
1 состояние 11%
2-3 состояния 27%
0 состояний 75%
Рис. 2. Количество состояний в конечных автоматах, реализующих классы
Рис. 1. Количество состояний в конечных автоматах На основе полученных данных использование конечных автоматов без состояний может быть объяснено следующим образом. В рассмотренных моделях операции практически не обладали семантикой состояний, поэтому 99% операций описывались автоматами без состояний, вырождаясь в императивную последовательность действий. Таким образом, использование автоматов для спецификации операций, как правило, не оправдано, и, тем не менее, широко применяется на практике. Если рассмотреть автоматы, реализующие классы, то распределение количества состояний значительно изменяется (Рис. 2). Для спецификации классов практически не используются автоматы без состояний, в то время как преобладают автоматы, имеющие одно состояние. Такая структура характерна для классов, не обладающих сложной внутренней логикой, а реализующих некоторый сервис для других компонентов системы. В единственном имеющемся состоянии, которое очень часто носит имя “Idle” или “Wait”, класс ожидает запроса на выполнение какой-либо операции. Получение запроса инициирует срабатывание перехода, в процессе которого выполняются необходимые действия. По завершении обработки класс вновь возвращается в исходное состояние. 175
Автоматы, специфицирующие иерархические состояния, составили чуть менее 2% от всех обнаруженных автоматов и были найдены всего лишь в нескольких из рассмотренных моделей, что позволяет сделать вывод об их достаточно редком использовании, несмотря на их выразительную мощность. Причиной тому может служить тот факт, что составные состояния не являлись частью языка SDL до его версии SDL-2000. Большинство крупных промышленных моделей SDL, впоследствии трансформированных в UML, было разработано до того, как появился новый стандарт SDL-2000. На Рис. 3 приведена статистика количества переходов, которые могут сработать в каждом из состояний автомата. И здесь снова 84% процента состояний достаточно просты в понимании, так как имеют не более 6 переходов. Однако состояния с большим числом переходом могут заметно затруднить понимание автомата, а их доля приближается к 15%; более того, как правило, эти состояния являются ключевыми в понимании алгоритмов, заложенных в конкретный автомат. Таким образом, в среднем, автомат, реализующий класс, содержит 3 состояния и около 12 переходов и 4 диаграмм, при этом около 90% автоматов содержат не более 6 состояний, и, следовательно, их понимание не должно вызывать серьезных затруднений у разработчиков. Однако внутренняя логика работы системы, как правило, реализуется оставшимися 10%, среди которых встречаются автоматы, насчитывающие до 30 состояний. Вполне очевидно, что умственные затраты на понимание такого автомата достаточно велики; соответственно, значительно затрудняется процесс его модификации, поиска 176
ошибок и проч. Поэтому средства, уменьшающие сложность автоматов, сохраняя их внешние свойства, действительно востребованы на практике.
>6 переходов 15%
препятствовать пониманию. В то же время для 10% автоматов, описывающих внутреннюю логику работы системы и содержащих более 6 состояний и переходов, количество диаграмм, на которых описан автомат, возрастает до пятидесяти, что очень сильно затрудняет понимание целостной картины работы системы.
2.2. Используемые конструкции
0 переходов 1%
Для повышения уровня выразительности и упрощения описания сложных систем в состав средств описания конечных автоматов UML был включен ряд специальных конструкций. Их использование позволяет во многом упростить и сократить описание сложных автоматов, и поэтому одной из целей проведенного исследования было выявление характера использования подобных конструкций. Далее приведен обзор полученных результатов. За счет использования операторов ветвления в действиях, выполняемых при срабатывании перехода в автомате, один и тот же переход может в различных условиях перевести автомат в различные состояния. Максимально возможное использование ветвления означало бы наличие в каждом состоянии не более чем одного перехода для любого сигнала. В этом случае выбор состояния, в которое перейдет автомат, происходил бы в процессе интерпретации действий, приписанных переходу. Результаты статистического исследования приведены на Рис. 5.
1 переход 23%
4-6 переходов 18%
2-3 перехода 43%
Рис. 3. Количество переходов из состояния
Ветвистость переходов
Распределение количества символов по диаграммам
31-35 символов 4%
>35 cимволов 10%
4 ветви 6% 3 ветви 10%
0-5 символов 8%
26-30 символов 5%
5 ветвей >5 ветвей 3% 3%
6-10 символов 28%
21-25 символов 10%
2 ветви 17% 16-20 символов 20%
1 ветвь 61%
11-15 символов 15%
Рис. 5. Ветвистость переходов Рис. 4. Распределение количества символов на диаграммах Анализ диаграмм состояний показал (см. Рис. 4), что, в среднем, автомат, реализующий класс, включает в себя 3-4 диаграммы, каждая из которых содержит около 9 символов и 9 линий, что не должно в значительной степени 177
Как и следовало ожидать, большинство переходов не разветвляются, а около 90% из них имеет не более трех ветвей. Однако 3% переходов, имеющие более 5 ветвей, могут заметно усложнить понимание логики работы системы. Абсолютный максимум составил 21 ветвь в одном переходе. 178
Использование графического синтаксиса позволяет проводить графическую декомпозицию диаграмм состояний – распределять сложные автоматы по нескольким графическим сущностям, не упрощая при этом структуру автомата. Этот подход позволяет облегчить процесс понимания деталей работы сложного автомата, однако затрудняет восприятие автомата как единого целого, что немаловажно для понимания логики работы сложной системы. Одним из средств графической декомпозиции UML являются метки. Они позволяют графически отделить участки диаграммы состояний, чтобы, например, перенести их на другую диаграмму или расположить отдельно на исходной диаграмме. Кроме того, введение меток способствует повторному использованию фрагментов диаграмм, так как переход на единожды описанную метку может быть выполнен многократно из различных частей автомата. Статистика использования меток приведена на Рис. 6. Распределение переходов на метки
>4 переходов 3% 4 перехода 3% 2 перехода 8%
2.3. Типичные способы построения конечных автоматов
3 перехода 4%
1 переход 20%
перечислить несколько имен состояний, и тогда все переходы, выходящие из этого символа, будут относиться ко всем перечисленным состояниям. Кроме того, если в качестве имени состояния указать символ «*», то переходы, выходящие из этого символа, будут относиться ко всем состояниям автомата. Также имеется возможность исключить определенные состояния из множества состояний, описываемого символом «*». Умелое использование этих возможностей позволяет значительно упростить описание переходов, применимых более чем к одному состоянию. Результаты статистического исследования показали, что символ * присутствует в 12% символов состояния, что свидетельствует о достаточно активном использовании этой подстановки и необходимости более детального изучения вариантов ее использования и возможных трансформаций с выделением или заменой символа «*». Кроме того, при описании состояния, в которое должен быть совершен переход, UML позволяет использовать символ «-», означающий состояние, в котором был инициирован исходный переход. Согласно статистике более трети символов состояния содержит символ «-». Это снова свидетельствует об удобстве и востребованности этой конструкции, а также о необходимости исследовать затрагивающие ее трансформации.
0 перходов 62%
Анализ полученной выборки не выявил каких-либо стандартов или «правил хорошего тона» при разработке конечных автоматов. Единственным «паттерном» можно считать применяемую одной из компаний методику, когда при описании автомата для каждого перехода из заданного состояния используется отдельная диаграмма, и еще одна диаграмма используется для всех общих описаний. Естественным недостатком такого подхода является сложность получения целостного представления о моделируемом автомате по причине разрозненности отдельных диаграмм, описывающих состояния.
3. Улучшение структуры конечных автоматов UML Рис. 6. Распределение переходов на метки
3.1. Трансформация «выделение метода» для конечных автоматов UML
Распределение количества команд перехода на метки очень похоже на распределение количества ветвей. В обоих случаях наиболее простые варианты (одна ветвь и отсутствие переходов на метки) обеспечивают около 60% случаев, а следующие по сложности варианты (две ветви и одна команда перехода на метку) – около 20%, в то время как остальные варианты имеют по 3-4%. Однако в автоматах встречались и переходы, перегруженные командами перехода на метки. Для некоторых переходов в автомате максимальное количество команд перехода на метку превысило 20. Чтобы избежать дублирования переходов для различных состояний, можно использовать несколько приемов. В UML в символе состояния можно 179
Идея трансформации “Extract method” состоит в создании нового метода и переносе части исходного автомата в добавленный метод. Данная трансформация во многом аналогична известному рефакторингу «Extract Method» для объектно-ориентированных языков программирования, описанному в каталоге Фаулера [1]. Суть традиционной трансформации состоит в выделении участка кода и перемещении его в другой метод. Это позволяет сделать код исходного метода более понятным и повышает вероятность повторного использования выделенного метода. Для корректного выполнения традиционного рефакторинга “Extract method” требуется тщательный анализ потока данных в выделяемом участке кода, так 180
как все используемые переменные должны быть переданы в метод в качестве параметров, а все изменения переменных должны быть тем или иным образом возвращены исходному методу, если измененные переменные используются в нем далее. Для первичного рассмотрения проблемы выделения метода в автомате эту проблему можно обойти следующим образом. Если используемая переменная является атрибутом автомата или сущности, содержащей автомат, то она будет видна и в выделенном методе и, следовательно, ее не нужно передавать в качестве параметра. Если же используемая переменная является локальной для действий, выполняемых в переходе, то при перенесении всех действий перехода в выделяемый метод определение локальной переменной и все ее использования будут также перенесены. Для выделения метода, в который помещаются не все действия, выполняемые в переходе, требуется дополнительный анализ потока данных. Следует подчеркнуть исключительную важность автоматизированной поддержки рефакторинга при проведении подобных преобразований, ибо сложность проводимого анализа будет способствовать ошибкам. Идея, лежащая в основе традиционного рефакторинга “Extract method”, может быть применена к конечным автоматам несколькими способами.
Для конечных автоматов UML можно применить традиционную трансформацию «выделение метода», которая состоит из выделения подпоследовательности действий одного из переходов конечного автомата в метод. В рамках описываемого исследования был разработан новый вариант трансформации «выделение метода», специфичный только для конечных автоматов UML, – «выделение в метод части конечного автомата», который подразумевает перенос в выделяемый метод не только действий, связанных с переходом, но и самих переходов и состояний.
3.2. Выделение в метод части конечного автомата Рассмотрим определение части конечного автомата, представленное на Рис. 7. Выбрав часть перехода вместе со следующим состоянием, можно выделить метод, в который войдет часть состояний конечного автомата, начиная с состояния Y. Будем называть такую трансформацию Extract Sub State Machine. Применимость данной трансформации связана со следующим свойством. Состояния, переносимые в выделяемый метод, перестают принадлежать исходному автомату и, следовательно, команды перехода, приводящие из состояний исходного автомата в состояния, перенесенные в выделенный автомат, некорректны. Такие команды перехода (смены состояния) должны быть заменены командами вызова выделяемого метода. Однако у автомата, реализующего метод, может быть только одна входная точка, поэтому либо все 181
такие команды должны осуществлять переход в одно и то же состояние, либо можно использовать целочисленный параметр для передачи номера того состояния, с которого должно начаться выполнение метода. Но введение такого параметра и добавление его обработки в начальном переходе усложняет выделяемый автомат и затрудняет его понимание. X
Y
Sig1()
Sig2()
Sig3()
Sig1()
/* 1 */
/* 2 */
/* 3 */
/* 4 */
Z
Z
Y
X
Риc. 7. Часть автомата, допускающая выделение метода Для обработки обратных переходов из состояний выделенного метода в состояния исходного автомата может быть применен следующий прием. Все состояния исходного метода, в которые можно попасть из выделяемого метода, нумеруются последовательными натуральными числами. Все команды перехода, ведущие из состояний выделяемого метода в состояния исходного, заменяются командами возврата из метода, использующими в качестве возвращаемого значения номер того состояния, в которое должен был бы осуществиться переход. После замены тела выделенного метода его вызовом возвращаемое им значение присваивается новой локальной переменной, и после возврата из метода оно анализируется для определения состояния, в которое должен был осуществиться переход. Описанный прием, хотя и позволяет при выделении метода не накладывать ограничений на количество обратных переходов, на практике зачастую только затрудняет понимание автомата, что противоречит целям проведения рефакторинга. Таким образом, несмотря на то, что количество вариантов применения предлагаемой трансформации достаточно велико, далеко не все из них служат цели упрощения понимания автомата. Тем не менее, можно выделить несколько специальных случаев, когда все прямые и все обратные переходы ведут в одно состояние. Введём несколько обозначений. Обозначим через RS(x, y) множество, содержащее все состояния автомата, в которые можно попасть из состояния y, 182
не проходя при этом через состояние x, включая y и исключая x. Специальный символ stop добавляется в множество RS(x, y), если из состояния y за некоторое количество переходов можно дойти до действия, завершающего работу автомата (stop). Обозначим множество всех переходов некоторого конечного автомата A через All_T(A), а переход из состояния а в состояние b по сигналу z – через t(a, z->b).
упрощает его понимание Результат преобразования представлен на Рис. 8. Выделенный метод показан на Рис. 9. Выделенный метод можно использовать повторно для уменьшения дублирования кода. X
Определение 1. Множество состояний S замкнуто на множестве переходов T, если не существует перехода t(x’,e->s)T : sS, x’S Трансформация Extract Sub State Machine для перехода t(x,e -> y) конечного автомата A, может быть применена при выполнении следующих трех условий:
Sig1()
Sig2()
/* 1 */
/* 2 */
Sig3()
P();
1) x != y, иначе RS пусто и это будет случай выделения автомата без состояний; 2) множество RS(x,y) замкнуто All_T(A)\t(x,e->y);
на
множестве
переходов Z
Z
-
3) stop RS(x, y). Трансформация Extract Sub State Machine для перехода t(x,e заключается в следующем.
->
y)
Рис. 8. Часть автомата после проведения преобразования Extract Method
1) Создаётся и добавляется в активный класс метод P с реализацией в виде конечного автомата.
Y
RS(X,Y) = { Y }
2) В этот метод перемещаются все состояния из множества RS(x, y) . 3) Действия, приписанные переходу t(x,e -> y), становятся действиями, приписанными начальному переходу конечного автомата метода P(). Вместо них в исходный конечный автомат вставляется вызов метода P() и команда перехода в исходное состояние x.
/* 3 */
4) Все команды перехода в состояние x в созданном конечном автомате заменяются на команды возврата из метода (return). Часть автомата, выделенная в метод, обладает следующей семантикой: получив сигнал Sig3(), автомат выполняет некоторые действия, начиная с состояния y, по завершении которых возвращается в состояние x. Подобная логика близка по смыслу к вызову метода: выполнение задачи с последующим возвратом в исходное состояние. Именно это и служит основанием для выделения метода. В результате преобразования выделяется структурная единица автомата – метод, а диаграмма, описывающая конечный автомат, уменьшается, что 183
Y
Sig1()
/* 4 */
Рис. 9. Описание выделенного метода Существует несколько частных случаев трансформации Extract Sub State Machine. 184
1) Ни для одного состояния из RS(x, y) нет перехода в x. Это значит, что возврат из созданного метода невозможен, в конечном автомате найден бесконечный цикл; возможно, это «серверная составляющая» исходного автомата. 2) Множество RS(x,y) содержит символ stop, и ни для одного состояния из RS(x, y) нет перехода в x. Это означает, что выделенная в метод часть автомата рано или могла завершить его работу: либо выделенные действия реализуют необходимую подготовку к завершению работы автомата (аналог деструктора в объектно-ориентированном программировании), либо найдена «серверная составляющая» исходного автомата (только если есть цикл). Во втором случае выделение метода корректно при выполнении следующих условий: a) в выделенном методе все команды завершения работы автомата (stop) должны быть заменены командами возврата из метода (return); b) вместо действий, приписанных исходному переходу, должен быть добавлен вызов метода P() и команда завершения работы автомата (stop). В рассматриваемом случае преобразованный автомат будет выглядеть так, как показано на Рис. 10.
3.3. Пример «Мобильный телефон» Продемонстрируем применение трансформации «Выделение части конечного автомата в метод» на одном из конечных автоматов системы Mobile, моделирующей работу мобильного телефона. В исходной системе конечный автомат представлен на 28 диаграммах, каждая из которых описывает ровно один переход (Рис. 11).
X
Sig1()
/* 1 */
Z
Sig2()
/* 2 */
Sig3()
Рис. 11. Исходный вид конечного автомата Такое представление не позволяет понять цельную структуру конечного автомата. Для упрощения понимания была создана дополнительная диаграмма, схематично описывающая весь конечный автомат, иллюстрирующая все состояния и переходы со всеми ветвлениями (Рис. 12). Приведённый алгоритм позволяет найти и выделить из данного конечного автомата три метода. На первом шаге в метод Initialize() выделяются четыре последовательных состояния (Рис. 13).
P();
Z
Рис. 10. Результаты применения второго варианта трансформации
185
186
На втором шаге выделяется метод TalkingThePhone() (Рис. 14), после чего становится возможным выделить ещё один метод, который назовём Working().
Рис. 12. Краткое описание всего конечного автомата Рис. 14. Выделение метода TalkingThePhone Обратим внимание на то, что выделение метода Working возможно только после выделения метода TalkingThePhone. Процесс применения трансформации итеративный. Поиск частей конечного автомата, которые можно вынести в отдельный метод, можно автоматизировать. В результате применения трансформаций исходный конечный автомат сильно упростился и свободно помещается на одной диаграмме (Рис. 15). Теперь он содержит только одно состояние (вместо четырнадцати состояний в исходном автомате) и вызов двух методов. Выделены три метода Initialize(), TalkingThePhone() (Рис. 16) и Working() (Рис. 17), содержащие 4, 5 и 4 состояния соответственно.
4. Заключение. Таким образом, задача трансформации моделей UML является достаточно актуальной. Проведенные исследования подтвердили гипотезу о возможности улучшения структурных качеств и упрощения понимания моделей, применяемых в реальных промышленных проектах. Это ставит перед исследователями задачи поиска новых трансформаций, в которых учитывается
Рис. 13. Выделение метода Initialize 187
188
специфику моделей UML. Для оценки применимости и полезности трансформаций необходимо продолжение работы по формализации подмножества конечных автоматов UML, описанию семантики их выполнения, а также создание инструментальных средств, автоматизирующих сбор необходимой информации и процесс трансформации моделей.
Рис. 15. Результат трансформации
Рис. 16. Метод Working 189
190
Литература 1. Фаулер М., Бек К., Брант Д., Робертс Д., Апдайк У. Рефакторинг: улучшение существующего кода. - СПб.: Символ-Плюс, 2002. - 432 с. 2. William F. Opdyke, "Refactoring Object-Oriented Frameworks". PhD Thesis, University of Illinois at Urbana-Champaign. Also available as Technical Report UIUCDCS-R-921759, Department of Computer Science, University of Illinois at Urbana-Champaign. 3. Tom Mens. A Survey of Software Refactoring, IEEE Transactions on Software Engineering, Vol. 30, No. 2, February 2004. 4. Van Gorp, P.; Stenten, H.; Mens, T. and Demeyer, S. Towards Automating Source Consistent UML Refactorings, in Proc. Unified Modeling Language Conf. 2003, 2003. 5. Astels. D., 'Refactoring with UML', in Marchesi, M and Succi, G (eds). XP 2002 Proceedings of the 3rd International Conference on eXtreme Programming and Flexible Proceses in Software Engineering, 2002. 6. Tom Mens, Niels Van Eetvelde, Dirk Janssens, and Serge Demeyer. Formalising refactorings with graph transformations. Fundamenta Informaticae, 2003. 7. Robert France, Dae-Kyoo Kim, Sudipto Ghosh, and Eunjee Song, “A UML-Based Pattern Specification echnique,” IEEE Transactions on Software Engineering, Vol.30, No.3, pp. 193-206, March 2004. 8. Marciniak J. J. The Encyclopedia of Software Engineering // Wiley Publishers. 2002. – 2076p.: il. 9. Буч Г., Рамбо Д., Джекобсон А. UML Руководство пользователя // М.: ДМК Пресс. 2001. – 432 с.: ил. 10. Меллор С., Кларк Э., Футагами Т. Разработка на базе моделей // Сайт журнала «Открытые Системы»: URL: http://www.osp.ru/os/2003/12/030.htm (2005. 25
июня). 11. Селич Б., Практические аспекты разработки на базе моделей // Сайт журнала «Открытые системы»: URL: http://www.osp.ru/os/2003/12/033.htm (2005. 25 июня). 12. Zs. Pap, I. Majzij, A. Pataricza, A. Szegi. Completeness and Consistency Analysis of UML Statechart Specifications // I.Maizik homepage: URL: http://home.mit.bme.hu/~majzik/publicat/ddecs2001.pdf (2005. 25 июня). 13. Unified Modeling Language: Superstructure // OMG official website: URL: http://www.omg.org/docs/formal/05-07-04.pdf (2005. 25 июня). 14. UML 2.0 OCL Specification // OMG official website: URL: http://www.omg.org/cgi-bin/apps/doc?ptc/03-10-14.pdf (2005. 25 июня). 15. H. Eriksson, M. Penker, B. Lyons, D. Fado. UML2 Toolkit // Indiapolis: Wiley Publishing Inc. 2004. – 511 p. il.
Рис. 17. Метод TalkingThePhone 191
192
Использование ролей в сценариях взаимодействия А. Волков (
[email protected]) Аннотация. Сценарий взаимодействия описывает поведение системы через описания взаимодействий некоторых объектов. Такими объектами выступают компоненты системы и внешние объекты, называемые акторами (actors). Обычно в сценарии взаимодействия подразумевается уникальность каждого объекта системы, т.е. предполагается, что описываются физически различные экземпляры объектов. Однако в ряде случаев это приводит к дублированию при описании сценариев. В работе предлагается расширить аппарат сценариев взаимодействия, разрешив использование ролей объектов. Роль соответствует некоторому срезу поведения определенного физического объекта. При таком подходе к описанию поведения возникает задача композиции поведения объектов в различных ролях. В данной статье рассматривается возможность систематического использования понятия роли в сценариях и исследуются средства, позволяющие строить общее поведение для объектов моделируемой системы по их поведению в различных ролях. Для представления сценариев используется модель взаимодействий UML (UML Interactions). В качестве абстрактных моделей для описания общего поведения объектов рассматриваются автоматные модели и модели, основанные на сетях Петри, в нотации UML (машины состояний и активности соответственно).
1. Введение Модельно-ориентированный подход (Model Driven Architecture, MDA), предложенный консорциумом OMG, направлен на достижение интероперабельности разрабатываемых систем. В нем используется идея разделения бизнес-логики проектируемой системы и конкретной технологии ее реализации. Для описания бизнес-логики используются платформонезависимые модели проектируемой системы. В рамках этого подхода основополагающую роль играет построение моделей системы, проверка их корректности и отображение в модели других уровней. Для унификации моделирования различных аспектов системы в рамках подхода MDA предлагается использовать универсальную нотацию – язык UML [1]. На ранних фазах проектирования программных системы, особенно на фазе анализа требований, с успехом используется сценарный подход, заключающийся в определении вариантов использования (use cases) системы и описания сценариев ее поведения в каждом таком варианте. Каждый сценарий представляет собой описание последовательности взаимодействий, 193
направленной на достижение некоторой цели. Сценарии могут быть заданы с помощью какой-либо нотации, позволяющей описывать поведение, однако, как правило, для описания сценариев используются нотации, обладающие высокой степенью наглядности. Построение формализованной сценарной модели позволяет производить как статический анализ требований, так и генерировать исполняемый прототип системы для динамического исследования системы; тем самым достигается возможность проверки требований. Для построения поведенческих моделей в языке UML 2.0 существуют следующие средства: взаимодействия (interactions), семантика которых задает отношение частичной упорядоченности событий в различных компонентах системы и акторов, активности (activities), семантически эквивалентные иерархическим раскрашенным сетям Петри, машины состояний (state machines), использующие семантику расширенных конечных автоматов в алфавите событий системы. По сути, взаимодействия UML обеспечивают абстракцию трасс системы, активности – абстракцию потоков (управления и данных) в системе, а машины состояний – абстракцию последовательности состояний для каждого компонента системы. Как правило, для описания сценариев на ранних фазах наиболее адекватно соответствует семантика взаимодействий UML, так как в сценариях, по существу, описываются трассы взаимодействий с будущей системой. Далее, говоря о сценариях, мы будем подразумевать, что они описываются в рамках модели взаимодействий UML. Семантика моделей взаимодействий носит декларативный характер. При определенных ограничениях возможно статическое исследование таких моделей (например, см. в [2] использование линеаризаций последовательностей событий и анализ формальных языков, получающихся в результате их рассмотрения). Для определения исполняемой семантики модели взаимодействий возможен подход, заключающийся в построении специальной абстрактной машины (вариант такого построения можно найти в [3]). Однако при составлении требований основной акцент делается, как правило, на описание ожидаемых ситуаций в системе. Кроме того, поведение описывается для некоторой совокупности объектов системы совместно, в то время как во многих случаях подразумевается задание протокола взаимодействия существенно независимых объектов. Абстрактная реализация модели поведения будет полностью следовать описанным сценариям, однако для указанных систем в ходе разработки сценариев может остаться неучтенной это существенная независимость объектов системы. В отличие от моделирования требований, для описания прототипа системы строятся, как правило, модели, описывающие поведение каждого объекта системы в отдельности; такие модели могут быть с легкостью отображены в 194
целевой код прототипа. Для описания этих моделей хорошо подходят событийные автоматы, которым соответствуют машины состояний UML. Различие в поведении такого прототипа системы и поведении, задаваемом моделью требований в виде взаимодействий, в некоторых случаях свидетельствует о недопонимании требований к системе. Таким образом, для анализа требований системы в форме сценариев взаимодействия оказывается полезным исследовать поведение системы, которое описывается моделями, отличными от модели последовательностей. Для этого важна возможность преобразования одних модели поведения в другие. При этом встает вопрос о соотношениях между различными моделями поведения системы, т.е. вопрос об эквивалентности поведений, задаваемых разными моделями или, по крайней мере, о степени точности аппроксимации поведения одной модели поведением другой. Исследование неточностей, появляющихся в результате такой аппроксимации может помочь выявить те особенности подразумеваемого поведения системы, которые не были учтены в исходных сценариях. Привлекательной является возможность автоматического преобразования исходной сценарной спецификации, моделируемой последовательностями UML, в другие модели, аппроксимирующие исходную. На текущий момент существует алгоритм построения по сценариям, записанным в нотации диаграмм последовательностей, автоматной модели для каждого объекта, входящего в систему; совокупность этих автоматов аппроксимирует исходную модель. Этот алгоритм реализован в семействе инструментов Bridge, разрабатываемых в Институте Системного программирования РАН совместно с компанией Klocwork Inc. Данная работа ведется в рамках этого проекта. Для описания UML-взаимодействий в данной работе используются диаграммы последовательностей (sequence diagrams) UML, а для описания композиции поведения – обзорные диаграммы взаимодействий (interaction overview diagrams). Заметим, что сходную нотацию предоставляет стандарт MSC [4], который включает базовые (basic) и высокоуровневые (high-level) MSCдиаграммы. Отметим, что обзорные диаграммы взаимодействий имеют в некоторых случаях недостаточно определенную семантику для адекватного объединения поведения компонентов системы в различных сценариях, что затрудняет и статический анализ требований. Каждое описание взаимодействий производится для определенного контекста, который определяется набором экземпляров объектов, принадлежащих системе, и внешними акторами. Возможность абстракции такого контекста от остальной системы может быть ценной при необходимости повторного описания таких взаимодействий для другого аналогичного контекста, так как тогда расширяется возможность повторного использования (reusability) описанных взаимодействий. Если в качестве абстракции экземпляров объектов традиционно рассматриваются классы объектов, то в качестве абстракции 195
объектов в рамках определенного контекста могут быть рассмотрены роли. В спецификации UML явно говорится о том, что проявления типов объектов в некотором контексте имеет смысл рассматривать как роли этих объектов. Абстракция роли достаточно исследована со стороны ее структурной реализации, но не с точки зрения объединения поведения в различных сценариях. Данная статья посвящена построению аппарата, позволяющего систематически использовать понятие роли при написании сценариев, определению средств нотации диаграмм последовательностей UML, которые могут быть использованы для этого, и исследованию того, каким образом полученная сценарная модель может быть отображена в другие модели. Далее работа построена следующим образом: во втором разделе приводятся примеры, иллюстрирующие использование понятия роли в моделях взаимодействия; в третьем разделе производится некоторая формализация понятия роли; в четвертом разделе рассматриваются средства нотации диаграмм последовательностей и обзорных диаграмм взаимодействия UML для описания композиции поведения объектов в различных ролях; пятый раздел посвящен исследованию возможности отображения модели взаимодействий в другие поведенческие модели, рассматривается расширение алгоритма синтеза событийных автоматов при использовании средств композиции поведения в различных ролях, рассмотренных перед этим.
2. Роли в моделях взаимодействия Описание взаимодействий в виде диаграммы последовательностей представляет собой набор осей (lifelines), некоторым образом сопоставляемых объектам, каждая из которых задает порядок наступления определенных событий для соответствующего объекта и выполнения им некоторых действий. Мы будем придерживаться следующего соглашения об использовании синтаксиса именования оси: ::= [] [: ] (причем не может быть пустым). Трактоваться будет следующим образом: обозначает имя роли объекта, которому данная ось ставится в соответствие, а – тип объекта. В случае, когда опущено имя роли, предполагается, что объект играет некую, так называемую, анонимную роль. Если опущено имя класса, предполагается, что тип объекта может быть произвольным. 196
В качестве близкого к реальным системам примера рассмотрим модель сети мобильной связи, в которой есть телефоны (Telephone), передатчики (Transmitter) и центральный коммутатор (Switch). Для такой системы можно выделить следующие протоколы: установление соединения; передача данных (разговор); разрыв соединения; регистрация в сети; смена станции в сети. Мы не будем описывать полную сценарную спецификацию для этой системы, однако приведем ее некоторые возможные сценарии (Рис. 1): запрос на установление соединения (Connection), передача данных (Transmitting), смена станции (Relocation).
Рис. 1. Сценарии системы мобильной связи Далее, во избежание громоздкости, в качестве модельного примера будет рассматриваться следующая спецификация достаточно простой системы, ее можно считать сильным упрощением описанной системы мобильной связи. Итак, рассмотрим систему обмена данными (Рис. 2), состоящую из двух узлов A и B, которые могут по очереди обмениваться сообщениями с данными (data) до тех пор, пока один из них не пошлет сообщение о завершении серии обменов (stop). По существу, в рассматриваемой спецификации имеются только два различных взаимодействия (Рис. 3; здесь опущены конкретные имена типов объектов) – это протокол передачи данных и протокол завершения обмена данными; для данного модельного примера эти протоколы тривиальны. Протокол передачи данных описывает поведение двух сторон – объекта, играющего роль отправителя данных (DataSender), и объекта, играющего роль получателя данных (DataReceiver). В контексте завершения сеанса передачи можно говорить о роли объекта, инициирующего завершение (TerminationInitiator), и роли объекта, извещаемого о завершении (TerminationAcceptor). В этом примере следует обратить внимание, на то, что, прибегая к абстрагированию, можно говорить не об описании поведения объектов, а об описании поведения ролей, которые объекты могут выполнять.
sd Transmiting Sender : Telephone
Inbound : Transmitter
Outbound : Transmitter
Receiver : Telephone
VoiceData (Data) VoiceData (Data) VoiceData (Data)
197
198
В данной спецификации эти протоколы пришлось продублировать для вариантов разных сочетаний объектов A и B и их возможных ролей. Теперь рассмотрим следующие два вопроса: если объекты A и B – различных типов, то как избежать дублирования описания общего для них поведения? если объекты A и B одинакового типа, то как описать композицию поведения объектов этого типа? С использованием понятия ролей эти вопросы могут быть переформулированы следующим образом: как для объектов различных типов, которые могут выполнять в некотором контексте одну и ту же роль, описывать включение поведения в этой роли в их суммарное поведение и строить такой результат? как для объектов одного типа, но выполняющих разные роли, описывать композицию поведений в них и строить результат этой композиции? При успешном решении этих задач выделение понятия роли в сценариях позволит избежать дублирований при их описании. Случаи осмысленного выделения ролей, соответствуют ситуациям, когда в описаниях сценариев имеются: объекты одного типа, участвующие в одном и том же взаимодействии различным образом (т.е. в различных ролях); объекты разных типов, которые в некоторых взаимодействиях могут вести себя одинаково (т.е. выполнять одну и ту же роль).
3. Формализация понятия роли Этот раздел посвящен уточнению понятия роли для последующего использования этого понятия в моделях. Сначала мы рассмотрим свойства ролей, рассматривающиеся в литературе, а затем обозначим контекст использования нами этого понятия в сценариях взаимодействий.
Рис. 2. Спецификация модельной системы обмена данными
3.1. Свойства ролей
Рис. 3 Взаимодействия в системе обмена данными. 199
В литературе понятие роли используется преимущественно в контексте моделей данных и в архитектурных моделях. В таких работах исследуются средства структурной композиции свойств объекта из свойств его ролей; нас же будет интересовать, прежде всего, объединение функциональности, соответствующей поведению в различных ролях. Тем не менее, сами свойства ролей, как в структурном, так и в поведенческом аспектах сходны. Основываясь на обзоре, произведенном в [5], отметим следующие свойства ролей: констектуальность: роли имеют смысл только в контексте некоторого взаимодействия; 200
объекто-зависимость: экземпляры роли не существуют без объектов; множественность: объект может играть несколько ролей одновременно (в частности, несколько экземпляров одной и той же роли); иерархичность: роли могут образовывать иерархии ролей. Эти свойства ролей прослеживаются и в сценариях. Подчеркнем различие между классами и ролями: классы задают свойства отдельных объектов; роли задают позицию и ответственность (responsibility) объекта в рамках некоторой системы или подсистемы. Удобно различать понятие роли и экземпляра роли – по аналогии с различением понятий класса и экземпляра класса. Под существованием во время выполнения (run-time) экземпляра роли мы будем понимать факт выполнения экземпляром агента или компонента системы данной роли в процессе некоторого взаимодействия. В процессе функционирования системы каждый из ее объектов выполняет (или играет) некоторую роль (возможно, несколько ролей одновременно); таким образом, можно говорить о существовании экземпляров ролей (одного или нескольких, если объект выполняет сразу несколько ролей одновременно), соответствующих объекту в каждый момент времени. В случае отсутствия явного выделения роли объекта можно говорить о выполнении им некоторой анонимной роли. Метамодель, иллюстрирующая эти соотношения, может быть описана диаграммой, представленной на Рис. 4.
Абстракция роли достаточно исследована с точки зрения ее структурной реализации, например, модели данных, использующие роли [6], связь понятия роли и интерфейса [7], шаблоны реализации ролей [8]; однако с точки зрения объединения поведения в различных сценариях роли практически не исследуются. Произведем краткий обзор шаблонов для представления ролей, рассматриваемых в работе [8]: объединение в единый тип для ролей (single role type) – все особенности каждой из ролей объединяются в один общий тип; использование отдельного типа для каждой роли (separate role type) – каждая роль трактуется как отдельный тип; использование ролевого объекта (role object) – особенности, присущие роли, объединяются в специальный объект; основной объект является хостом (host object), объединяющим несколько таких ролевых объектов; при обращениях внешних объектов он использует нужный из ролевых объектов в зависимости от контекста; использование ролевого отношения (role relationship) – специальный объект, объединяющий особенности данной роли, моделирует связь основного объекта в данной роли с некоторым внешним объектом. Структурировать описание поведения можно различным образом; при рассмотрении поведений, соответствующих различным ролям в рамках некоторой архитектурной ролевой модели, можно достичь соответствия между ролями в их структурном и поведенческом понимании.
Рис. 5. Фрагмент упрощенной модели взаимодействий UML
3.2. Роли в сценариях взаимодействия Говоря об описании взаимодействий в системе, можно предложить следующее определение роли: роль – это абстракция агента или компонента системы в рамках его ответственностей в некотором взаимодействии. По сути, в результате такого абстрагирования, мы получаем некоторый срез поведения
Рис. 4. Метамодель, описывающая соотношения между ролями, классами и их экземплярами 201
202
объекта. Ответственности участников взаимодействия определяются логикой описываемого сценария. В модели взаимодействий UML при описании некоторого сценария каждой роли естественно сопоставлять оси с одинаковым именем на различных диаграммах. В контексте некоторого упрощения метамодели взаимодействий UML (Рис. 5) взаимосвязь ролей с моделью взаимодействий можно проиллюстрировать диаграммой, представленной на Рис. 6.
Рис. 6. Роли в метамодели взаимодействий
3.3. Взаимосвязь с аспектами Использование ролей близко соотносится с аспектно-ориентированным программированием. Под аспектом понимается некоторый срез системы, который объединяет функциональность ее различных частей, соответствующую некоторому классу задач. Таким образом, отчетливо видна связь между описанием сценариев системы и ее аспектами поведения, так как по существу каждый сценарий является описанием какого-либо аспекта системы; при этом каждому аспекту соответствует некоторый набор ролей – эта связь отражена на диаграмме, представленной на Рис. 7.
Рис. 7. Взаимосвязь ролей и аспектов с взаимодействиями UML Исследования взаимосвязей в использовании ролей и аспектов можно найти, например, в [9] и [10].
4. Композиция поведения в разных ролях В данном разделе будут рассматриваться подходы, позволяющие решать задачу описания построения композиции поведения в различных ролях. Для этого будут рассмотрены некоторые расширения семантики диаграмм 203
взаимодействия. Прежде чем перейти к рассмотрению расширений, уточним семантику обзорных диаграмм взаимодействия.
4.1. Уточнение семантики композиции Каждая диаграмма последовательностей естественным образом предполагает наличие постоянного контекста описываемого взаимодействия, т.е. в ней описывается своего рода транзакция взаимодействия объектов. Набор осей задает классы объектов и их возможные роли, которые они могут выполнять. В дальнейшем под обзорными диаграммами взаимодействия, мы понимаем соответствующие диаграммы UML (UML Interactions Overview Diagrams), им родственна нотация высокоуровневых диаграмм MSC (High-level MSC, HMSC). Обзорные диаграммы взаимодействия декларируются в спецификации UML как вариант диаграмм активностей, однако же это отражено лишь в нотации. Спецификация UML определяет семантику этих диаграмм декларативно; для целей сравнения поведений имеет смысл определить их исполняемую семантику – как вариант семантики диаграмм активности. Семантика же диаграмм активностей определяется в UML в стиле семантики сетей Петри, т.е. через поток маркеров (tokens) по графу, состоящему из мест, переходов и дуг, их соединяющих. В рассматриваемом случае этим местам соответствуют активности, каждая из которых описывается диаграммой взаимодействия, а переходам соответствуют условные и параллельные ветвления потока маркеров. Для определения поведения сопоставим каждому объекту набор маркеров. Каждому маркеру ставится в соответствие экземпляр некоторой роли, выполняемой объектом; понятия маркера и экземпляра роли, таким образом, можно в определенном смысле отождествлять. Нахождение маркера для экземпляра роли в некоторой активности, означает, что объект, которому соответствует этот экземпляр роли, участвует во взаимодействии, описываемом сопоставленной этой активности диаграммой взаимодействия. Состояние объекта определяется набором ролей, которые он исполняет, т.е. соответ-ствующим множеством экземпляров ролей и их состояниями. Состояние всей системы определяется текущей разметкой диаграмм маркерами. Возможность активации перехода для маркера означает, что для объекта, соответствующего этому маркеру одновременно: в активности, в которой он находится, выполнены все взаимодействия; в диаграмме, в которую ведет переход, выполнены предусловия, задаваемые первым событием, находящимся на оси, которая соответствуюет данному объекту. Предусловие зависит от вида такого события следующим образом: для проверки условного выражения предусловие перехода соответствует этому выражению; 204
для приема сообщения предусловие заключается в наличии такого сообщения во входной очереди сообщений объекта; для других видов событий (так называемых, активных событий) предусловие соответствует тождественно истинному выражению, и переход может быть произведен (активирован) в любом случае. При активации перехода происходит перемещение маркера: маркер, соответствующий данному объекту, убирается из активности, в которой он находился, а в активность, в которую ведет сработавший переход, помещается маркер, соответствующий той роли, которую объект будет в ней выполнять. В случае перехода с распараллеливанием маркеры помещаются во все активности, в которые ведут ветви перехода. Для перехода, объединяющего параллельные ветви, условиями его срабатывания являются наличия маркеров, соответствующих одному и тому же объекту. Отметим, что такое описание композиции поведения объектов сходно с использованием сетей Петри для описания композиции ролей, предложенном в [11], где рассматривалась программная среда для разработки приложений, основанных на агентной архитектуре. Рассмотрим теперь следующие методы описания композиции поведения в различных ролях: использование специальных меток для «склейки» поведения; использование параметризуемых по осям диаграмм; задание потоков объектов на обзорных диаграммах взаимодействий.
4.2. Композиция через конструкции «продолжения» Спецификация UML предлагает дополнительный способ композиции поведения через конструкцию продолжения (continuation) осей. Семантика таких конструкций носит характер «склейки» поведения по меткам: после фрагмента взаимодействий, заканчивающегося конструкцией продолжения с именем “X”, допустимо продолжение по тем ветвям следующего фрагмента взаимодействий, которые начинаются с конструкции продолжения с тем же именем “X”. Это может быть проиллюстрировано примером, взятым из спецификации UML: диаграмма Continue со ссылкой на диаграмму Question (Рис. 8) эквивалентна диаграмме, представленной на Рис. 9.
sd Question :A
:B ask
Рис. 9. Пример из спецификации UML: результат композиции с помощью конструкции «продолжения»
alt DoSth
Для целей композиции поведения объектов в различных ролях разрешим использование конструкции продолжения не только в варианте, когда она покрывает все оси объектов, участвующих во фрагменте взаимодействия. Кроме того, дополнительно будем использовать следующее правило композиции: на диаграмме, следующей за данной диаграммой, в качестве возможных осей, которые соответствуют продолжению описания поведения, задаваемого осью на данной диаграмме взаимодействий (следование задается переходом между диаграммами на обзорной диаграмме), рассматриваются оси с тем же типом, роль же может быть другой. Естественно, что в качестве продолжения при исполнении выбирается лишь одна ось, в соответствии с выполнением предусловий для данного объекта.
OK nonono notOK
Рис. 8. Пример из спецификации UML: композиция с помощью конструкции «продолжения» 205
206
Тогда можно рассмотреть спецификацию системы обмена данными, представленную на Рис. 10, которая будет эквивалентна исходной (Рис. 2), в предположении, что объекты A и B в исходном случае – это узлы некоторого одного типа Node.
взаимодействия, вследствие необходимости отслеживать имена меток конструкций продолжения. Следует отметить, что в этой спецификации есть некоторая неопределенность, связанная с тем, что в самом начале взаимодействия не задан способ выбора роли (Sender или Receiver) объектом типа Node. Эта неопределенность может приводить в данном случае к тупиковым ситуациям в функционировании системы, когда объекты совместно начинают выполнять роль Receiver, в результате чего бесконечно ожидают приема сигнала.
sd Calc_f1_f2
ref
Calc_f1
ref
Calc_f2
Рис. 10. Спецификация модельной системы обмена данными с помощью конструкций «продолжения» Данная спецификация задает поведение объектов типа Node. Каждый вариант взаимодействия в этой спецификации описан один раз для своего набора ролей, однако несколько утеряна наглядность, присущая диаграммам 207
Рис. 11. Спецификация системы вычислителя с несколькими терминалами 208
Такое расширение композиции через конструкции продолжения дополнительно обеспечивает следующую заслуживающую внимания возможность. Рассмотрим систему, состоящую из вычислителя (Calculator), который может вычислять функции f1 и f2 и терминалов (Terminal), обращающихся к нему за вычислением этих функций. Пусть терминал должен запрашивать вычисление функций, чередуя f1 и f2, а вычислитель должен обладать возможностью производить вычисления функций в любом порядке. Поведение этой системы может быть описано с помощью диаграмм, представленных на Рис. 11. Тогда в соответствии с правилом композиции описанное здесь поведение для терминала может быть проиллюстрировано обзорной диаграммой взаимодействий, изображенной на Рис. 12.
Будем считать параметризацию осей возможной. Тогда, используя ее, рассматриваемую модель обмена данными можно описать с помощью диаграмм, представленных на Рис. 13. sd Transfer (Sender, Receiver) Sender
Receiver data
sd Termination (Initiator, Partner) Initiator
Partner stop
sd Calc_f1_f2_for_Terminal
ref
ref
Calc_f1
Calc_f2
Рис. 12. Поведение вычислителя В рассмотренном варианте задания композиции элементы, собственно специфицирующие эту композицию, оказываются инкапсулированными внутрь описания отдельного взаимодействия. Это приводит к снижению наглядности описания системы. Помимо этого, использование такой нотации привносит некоторую автоматоподобную семантику описания, причем в рамках каждого отдельного объекта системы, что не слишком соответствует логике нотации моделей взаимодействий и увеличивает вероятность создания внутренне противоречивых моделей.
4.3. Композиция через параметризацию диаграмм по осям Рассмотрим альтернативный вариант композиции, в котором используется параметризация диаграмм. Спецификация UML не говорит явно о возможности параметризации имен осей, однако заметим, что стандарт MSC позволяет задавать имена осей в качестве параметров MSC-диаграммы. 209
Рис. 13. Спецификация модельной системы обмена данными с помощью параметризации диаграмм по осям Можно рассматривать статическую и динамическую семантику параметризации. Для статического случая результат соответствует макроподстановке диаграммы вместо ссылки на нее; динамическому случаю соответствует вызов поведения некоторой подсистемы. Связывание фактического параметра, соответствующего некоторому объекту определенного типа, и формального параметра, соответствующего роли в данном взаимодействии, означает вовлечение (acquirement) этого объекта в данную роль. В зависимости от семантики параметризации можно говорить либо о статическом «обладании» объектом своими ролями, либо о 210
динамическом «принятии» в роли; это согласуется с различиями архитектурного моделирования ролей. Заметим, что в данном случае пришлось продублировать описания ссылок на описания протоколов; вместо этого можно попытаться явно описывать задающие значения параметров потоков объектов между диаграммами.
4.4. Композиция через задание потоков объектов Снимем некоторые ограничения обзорных диаграмм взаимодействия, приблизив их к диаграммам активности. Рассмотрим возможность ограничения на потоки объектов между диаграммами путем задания их типа. Для этого мы будем использовать символы объектов на дугах диаграмм. Мы будем считать, что такой переход может сработать для маркера, если он поставлен в соответствие объекту, имеющему тип, который соответствует типу, указанному на этом переходе (в качестве вариантов можно рассматривать как строгое соответствие, так и соответствие какому-либо более общему типу). Для переходов с отсутствием такой спецификации предполагается, что они могут срабатывать для маркеров любого типа. По смыслу, такое описание (рис. 14) сходно с параметризацией, но с явным указанием входных и выходных потоков фактических параметров. Применение таких потоков позволило избежать дублирования ссылок, но при этом сделало более сложным само описание композиции.
5. Отображение в другие модели
Рис. 14. Спецификация модельной системы обмена данными с помощью явного задания потоков объектов 211
Необходимость композиции поведения объектов в различных ролях приводит к еще одному источнику нежелательного поведения системы, не отраженного в сценарной модели; мы столкнулись с одним из таких примеров в предыдущем разделе. Как говорилось во введении, аппроксимация поведения модели взаимодействия другими моделями может помочь выявить пробелы в понимании требований к системе. Ниже мы рассмотрим возможность отображения модели последовательностей в две другие модели UML, позволяющие описывать поведение системы – это автоматные модели (машины состояний) и активности. Модель машины состояний хорошо подходит для описания поведения отдельного объекта. Для описания систем, состоящих из некоторого набора взаимодействующих объектов, используются модели, представляющих собой набор таких машин состояний, каждая их которых дает описание поведение отдельного объекта системы. При этом предполагается, что существует некоторое окружение (среда поддержки), которое отвечает за передачу сообщений между экземплярами таких машин. Это окружение относится уже к платформо-зависимому уровню системы, сами же машины достаточно просто отображаются в код, поэтому такие модели широко используются для прототипирования. С другой стороны, в таких моделях утеряны явные связи между отдельными объектами системы, модели же активностей, моделирующие как потоки управления, так и потоки данных в системе, позволяют исследовать поведение системы не покомпонентно, а в целом. Поэтому интерес представляет отображение в обе эти модели.
212
5.1. Отображение в модель машин состояний Для спецификации поведения объектов системы применяются подходы, основанные на событийных автоматах; в таком случае поведение каждого компонента системы задается расширенным конечным автоматом. Событийные автоматы довольно легко отображаются в код на целевых языках; кроме того, существуют такие распространенные нотации как SDL [12] и машины состояний UML, в которых используется семантика автоматов. Под машинами состояний (State Machines) мы понимаем расширенные конечные автоматы в алфавите событий, возможных в системе. Для этих автоматов должны выполняться некоторые дополнительные требования, которые заключаются в выделении некоторых типов состояний автомата, различающихся видами событий, по которым возможны переходы из этих состояний. Эти виды следующие: активные состояния, из которых возможен только один переход, происходящий по активному событию (выполнение действия (Action), посылка сигнала и т.д.); состояния проверки условия, из которых возможны переходы по проверке условий; состояния ожидания получения сообщения; из них возможны переходы по событиям приема сообщений. Состояния ожидания автоматов соответствуют собственно состояниям машин, остальные состояния автоматов соответствуют так называемым псевдосостояниям.
5.1.1. Алгоритм построения машин состояний по диаграммам последовательностей Сделаем обзор алгоритма построения машины состояния, работающего в случае анонимных ролей: синтаксический разбор (parsing); построение графов, соответствующих диаграммам (ordering/linking); объединение поведений, заданных диаграмма (placement/integration); построение срезов (slicing); построение автоматов, их преобразование в детерминированные автоматы, трансформация в машины состояний (automata generation & minimization); кодогенерация (codegeneration). Кратко опишем эти фазы. Фазы синтаксического разбора и построения графов диаграмм зависят от синтаксиса их записи. В результате для каждой диаграммы обзора взаимодействий строится внутреннее представление графа, который состоит из диаграмм и связей между ними, задающих их последовательность. Для диаграмм последовательностей строятся события (и так называемые 213
псевдособытия) и связи, задающие их последовательность на данной оси. Для inline-конструкций и ссылок на другие диаграммы строятся псевдособытия. Также строятся связи между множествами событий (и псевдособытий) на разных осях, если они взаимосвязаны – т.е. для пар событий посылки-приема сообщения, псевдособытий, соответствующих началам и концам ссылок на другие диаграммы, началам и окончаниям inline-конструкций. Для объединения поведений в соответствии с графом использования (через ссылки) диаграммами друг друга выбирается диаграмма самого верхнего уровня (считается недопустимым случай рекурсивных ссылок диаграмм друг на друга), и, начиная с этой диаграммы, рекурсивно применяется подстановка поведения используемых в ней диаграмм. После этого производится объединение поведений, заданных различными диаграммами: для каждой пары следования фрагментов взаимодействия происходит построение связей между псевдособытием «конца» каждой оси из предшествующего фрагмента с псевдособытием «начала» оси последующего фрагмента. По срезам модели, построенным для каждого объекта системы взаимодействий, строятся автоматы: каждое событие среза отображается в переход автомата по этому событию, а каждая связь между событиями на одной оси – в состояние автомата. Для псевдособытий строятся пустые переходы. После этого производится преобразование автоматов в эквивалентные детерминированные автоматы, после чего полученные автоматы структуризируются в соответствии с требованиями машин состояний. Таким образом, в полученной машине состояний событиям соответствуют те элементы диаграмм взаимодействия, которые носят конструктивную семантику – т.е. посылка и прием сообщения, выполнение действия, порождение объекта. Элементам, семантика которых носит характер ограничений, как, например, конструкции временных ограничений, инварианты, соответствуют некоторые атрибуты событий, задающие условия, невыполнение которых означает динамическую ошибку. Описанный алгоритм реализован для MSC-диаграмм в синтезаторе Bridge, разработанном в Институте системного программирования РАН совместно с компанией Klocwork. По построенным автоматам может генерироваться модель системы на языке SDL (очень близком к протокольным машинам состояний UML), прототип системы на языках Си/C++ или Java, тесты для системы на языках TTCN и PPL. Для рассмотренного в начале примера спецификации системы обмена данными будут сгенерированы (с точностью до имен состояний) автоматы, изображенные в форме машин состояний на Рис. 15. Степень аппроксимации исходных сценариев автоматными моделями, построенными таким образом, обсуждается в работе [13]. 214
Рассматриваемые расширения алгоритма синтеза касаются фаз подстановки и построения срезов.
5.1.3. Структуризация поведения по ролям Построение структурированной модели машин состояний делает их более масштабируемыми, что расширяет возможности дальнейшего применения получаемых моделей. Наличие взаимосвязи между структурой этой модели и структурой исходной модели взаимодействий дает возможность более тесно сочетать использование обеих этих моделей при описании поведения системы, что позволяет рассматривать поведение системы с разных точек зрения. Далее мы рассматриваем вариант расширения алгоритма синтеза, заключающийся в структуризации поведения по ролям, т.е. генерации иерархической структуры, состоящей из машин состояний, в которых происходит вызов других машин состояний (т.е. подмашин) в соответствии с использованием ролей. Для этого вместо подстановки поведения, соответствующего роли, для каждой роли генерируется конструкция вызова подмашины, которая состоит из: переходов, соответствующих событиям, которые происходят в данной роли; состояний, все переходы в которые происходят по событиям, происходящим в данной роли. Для рассматриваемого примера обмена данными такие подмашины весьма тривиальны (Рис. 16). ReceiveProtocol
SendProtocol
Рис. 15. Машины состояний для объектов модельной системы обмена данными.
data
data
5.1.2. Расширение алгоритма синтеза при использовании средств для композиции ролей В настоящее время для приведенного алгоритма в синтезаторе Bridge реализовано расширение, заключающееся в возможности использования параметризованных ссылок; в том числе, параметризованы могут быть и оси диаграммы. Для этого на фазе интеграции поведений в момент подстановки копии диаграммы, на которую идет ссылка, производится замена формальных параметров на фактические; по существу, это соответствует выполнению параметризованной макроподстановки. Для возможности построения композиции с помощью конструкций продолжения требуется некоторое расширение алгоритма, позволяющее производить такую «склейку» осей. 215
Рис. 16. Подмашины состояний, соответствующие поведению объектов в различных ролях 216
Другими словами, каждая подмашина состоит просто из отрезка перехода между состояниями по событию принятия или посылки соответствующего сигнала. В данном случае производить такую инкапсуляцию не слишком целесообразно. Тем не менее, если протокол пересылки носит более сложную форму, то такая группировка может быть гораздо более значимой. Конкретное представление такой иерархии можно рассмотреть в контексте задачи генерации прототипа архитектурной модели системы. Существуют различные способы структурной реализации ролей. Тривиальный способ заключается в простой комбинации всех поведений; простая подстановка именно этому способу и соответствует. В качестве менее тривиального способа структурной реализации ролей можно рассмотреть шаблон, соответствующий использованию ролевого объекта в работе [5] (Рис. 17).
Рис. 17. Шаблон «ролевой объект» для представления ролей в структуре системы
Рис. 18. Машины состояний для объектов модельной системы обмена данными, структурированные по ролям
Если в системе существует поведение, связанное с некоторой ролью, то для такой роли заводится интерфейс Role и реализация этого поведения – Role_Impl. Если объекты типа Class могут выполнять эту роль, то такой класс должен быть унаследован от интерфейса Role, и он должен агрегировать объект типа Role_Impl, который по своей сути соответствует экземпляру роли. Поведение же, соответствующее данной роли, должно делегироваться в Class из Role_Impl. Для примера с передачей данных, если считать типы объектов A и B разными, структура системы будет описываться диаграммой на Рис. 18. Этот пример показывает, что по описанию взаимодействий может быть автоматически построен и прототип архитектурной модели системы, структура которого соответствует логике исходных сценариев.
217
5.2. Отображение в модель активностей Диаграммы активностей, используя семантику, сходную с семантикой сетей Петри, хорошо описывают работу системы в целом, так как явным образом моделируют и передачу сообщений. Построение моделей активностей UML по сценариям, описанным с помощью моделей взаимодействий, могло бы позволить производить статическую проверку требований к системе. Соображения о возможности построения отображения из моделей взаимодействий UML в модели активностей основываются на возможности использования для обзорных диаграмм взаимодействия семантики в стиле сетей Петри, а также возможности отображения отдельных взаимодействий в активности, что продемонстрировано на Рис. 19.
218
Отметим, что существуют работы, в которых рассматриваемся формализация исполняемой семантики взаимодействий через сети Петри – см. [14]. Результат фазы интеграции в алгоритме построения машин состояний, описанном в предыдущем разделе, практически соответствует диаграмме активности и может быть отображен в нее. Можно рассматривать вопрос и о структурировании диаграмм активностей в соответствии с имеющимися сценариями и общими в них ролями. Также возможно отображение машин состояний в диаграммы активностей [15]. Можно сделать предположение, что существо различия между моделью активностей, построенной по UML-взаимодействиям, и моделью активностей, построенной по машинам состояний, которые сгенерированы их тех же UMLвзаимодействий, заключается в том, что моделирование передачи сообщений в первом случае происходит отдельными потоками сообщений между активностями посылки и приема, а во втором представляет собой некоторый общий поток, соответствующий каналу передачи. В этом случае модель активностей потенциально может являться некоторым базисом для сравнения поведений.
Выполнение действия:
Пересылка сообщения:
6. Заключение В статье было продемонстрировано, что, в отличие от традиционной интерпретации, каждое описание взаимодействий может трактоваться как ориентированное не на собственно объекты, а на роли, выполняемые ими в данном взаимодействии. Для более широкой применимости моделей взаимодействий и более формального их использования можно использовать рассмотренный аппарат для оперирования этими ролями. В данной работе показано, как можно адаптировать имеющуюся нотацию UML для описания ролей, прежде всего, в плане задания их композиции. Для этого было рассмотрено использование конструкций продолжения и расширение возможностей параметризации UML-взаимодействий, однако у каждого из этих способов имеются свои недостатки. Следует отметить, что композиция через конструкции продолжения ближе к машинам состояний, так как семантика этих конструкций близка семантике к переходам на метку; композиция же через параметризацию – ближе по смыслу к семантике UMLактивностей, так как она тем или иным образом задает потоки объектов. В качестве модели для абстрактного выполнения были рассмотрены машины состояний UML, которые удобны для целей симуляции и генерации прототипа компонентов системы. Было рассмотрено расширение алгоритма синтеза машин состояний по UML-взаимодействиям на случай использования композиции различных ролей, и указаны те из этих расширений, которые поддерживаются разрабатываемым инструментом Bridge, позволяющим автоматически производить подобный синтез. Кроме этого, была обозначена возможность отображения модели UML-взаимодействий в модель
Создание объекта:
Рис. 19. Отображение взаимодействий в активности 219
220
активностей, которая удобна для анализа поведения системы в целом. Анализ моделей, поведение которых дает аппроксимацию поведения, задаваемого описаниями требований к системе в виде моделей взаимодействий, обеспечивает возможность выявлять пробелы в понимании требований к системе. Другим результатом экспериментов с новой нотацией является вывод о том, что при композиции различных ролей, как и вообще при композиции сценариев, могут возникать неопределенности. В статье был приведен типичный пример возникновения неопределенности с выбором роли, в результате которого у системы может существовать поведение, приводящее к тупиковой ситуации. Еще одним следствием использования ролей при использовании для описания сценариев модели взаимодействий является достижение взаимосвязи с аспектно-ориентированным программированием. В качестве развития данной тематики имеет смысл рассмотреть следующие задачи: описание преобразований UML-взаимодействий в UML-машины состояний в терминах метамодели языка UML или некоторого ее упрощения; строгая формализация исполняемой семантики композиции UMLвзаимодействий через диаграммы обзора взаимодействий; исследование ситуаций возникновения неопределенностей, связанных с композицией ролей, на основе расширении алгоритма синтеза машин состояний по взаимодействиям UML; исследование возможности генерации модели активностей UML по моделям последовательностей и их взаимосвязь с исходными моделями и с моделями машин состояний, полученными по тем же моделям взаимодействий.
7. F. Steimann. Role = Interface: a merger of concepts. Journal of Object-Oriented Programming 14:4, 2001 8. M. Fowler. Dealing with Roles. Working Draft (http://martinfowler.com/apsupp/roles.pdf), July 1997. 9. E. A. Kendall. Aspect-Oriented Programming for Role Models. Lecture Notes Computer Science, Vol. 1743, 1999. 10. G. Georg, R. B. France. UML Aspect Specification Using Role Models. OOIS 2002: Object-Oriented Information Systems, 8th International Conference, Montpellier, France, 2002. 11. M. Becht, T. Gurzki, J. Klarmann, M. Muscholl. ROPE: Role Oriented Programming Environment for Multiagent Systems. Proceedings of the 4th IFCIS Conference on Cooperative Information Systems (CoopIS'99), Edinburgh, Scotland, September 1999. 12. ITU-T Recommendation Z.100 System Description and Definition Language (SDL2000). International Telecommunication Union (ITU), Geneva, 1999. 13. N. Mansurov, D. Vasura. Approximation of (H)MSC semantics by Event Automata. SAM'2000 workshop, Grenoble, France, 2000. 14. St. Heymer. A Semantics for MSC Based on Petri-Net Components. SAM 2000, 2nd Workshop on SDL and MSC, Col de Porte, Grenoble, France, 2000. 15. Z. Hu, S. M. Shatz. Mapping UML Diagrams to a Petri Net Notation for System Simulation. Proceedings of the 16th International Conference on Software Engineering & Knowledge Engineering (SEKE'2004), Banff, Alberta, Canada, 2004.
Литературы 1. UML 2.0 Superstructure Specification FTF. October 8, 2004, OMG Document: ptc/0410-02 (convenience document). 2. B. Bollig, M. Leucker, T. Noll. Generalised Regular MSC Languages. Proceedings of the 5th International Conference on Foundations of Software Science and Computation Structures (FOSSACS '02), Grenoble, France, 2002. 3. B. Jonsson, G. Padilla. An Execution Semantics for MSC-2000. SDL 2001: Meeting UML, 10th International SDL Forum Copenhagen, Denmark, 2001. 4. ITU Recommendation Z.120 Message Sequence Charts (MSC-2000). International Telecommunication Union (ITU), Geneva, 1999. 5. F. Steimann. On the Representation of Roles in Object-Oriented and Conceptual Modelling. Data & Knowledge, Volume 35, Issue 1, October 2000. 6. R. K. Wong, H. L. Chau, F. H. Lochovsky. A Data Model and Semantics of Objects with Dynamic Roles. Proceedings of the Thirteenth International Conference on Data Engineering table of contents, 1997
221
222
Применение методов выявления закономерностей для классификации химических соединений Г.Т. Маракаева Аннотация. Целью статьи является постановка задачи классификации неизвестных химических соединений. С помощью классификации выявляются признаки, характеризующие группу, к которой принадлежит тот или иной объект. Это делается посредством анализа уже классифицированных объектов и формулирования некоторого набора правил. Целью различных алгоритмов классификации является построение классификационной модели, называемой классификатором, которая будет предсказывать класс для заданного примера на основании имеющихся значений атрибутов. Как правило, классификация рассматривается, как задача Data Mining, что по-русски язык означает “обнаружение знаний в базах данных”, “выявление закономерностей”. В рамках исследования задачи совместно с экспертами предметной области были проанализированы возможности формализации экспертных знаний в системе. Кроме того, были изучены формат данных и значения атрибутов химических соединений в нескольких лабораториях. Результатами этих работ стали выводы о возможности применения различных алгоритмов классификации для определения классов химических соединений. Эти выводы являются предметом следующей статьи.
1. Введение Целью статьи является постановка задачи классификации химических соединений. Работа лаборатории заключается в проведении экспериментов над различными пробами по определению их свойств (например, содержание серы, вязкость и т.д.), а также по определению класса пробы (например, питьевая вода, природная вода и т.д.). Каждый полученный результат фиксируется в лабораторном журнале. В данном случае ключом записи является идентификационный номер пробы, значения ее параметров и класс пробы. После некоторого времени в лаборатории накапливается достаточно большое число записей о пробах, содержащих значения параметров и класс. Каждая проба может исследоваться, во-первых, на значение атрибутов, а во-вторых, на принадлежность к одному из классов химических проб. Задача классификации состоит в определении класса новой пробы по неполному набору значений атрибутов. В лабораторию поступает новая проба 223
неизвестного класса. Задача сотрудника – определить класс пробы. В общем случае сотрудник должен по внешним факторам экспертно определить возможный класс и выполнить полный набор экспериментов, призванных подтвердить или опровергнуть его гипотезу. Если гипотеза не подтверждается, то проводится следующая серия экспериментов для исследования другой гипотезы. Среди экспертов химической области наблюдается больший интерес к использованию информационных систем в своей работе. С привлечением все большего числа специалистов будут накапливаться базы информации об исследуемых соединениях, пробах и т.д. и, следовательно, возникнет необходимость анализа этих данных. Так как описание проб с помощью признаков является унифицированным для всех экспертов, то накапливаемая база может использоваться повсеместно. Классификация очень часто рассматривается, как один из способов выявления закономерностей в большом объеме данных (Data Mining) [1, c. 19]. Под понятием «выявления закономерностей» понимается итеративный автоматический или ручной процесс изучения данных. [2, c.2]. Выявление закономерностей делятся на следующие категории [2, c.2;1, с.19]. Классификация (classification) – c помощью классификации выявляются признаки, характеризующие группу, к которой принадлежит тот или иной объект. Это делается посредством анализа уже классифицированных объектов и формулирования некоторого набора правил [1, c.20]. Целью различных алгоритмов классификации является построение классификационной модели [4, c.29] называемой классификатором, которая будет предсказывать класс для заданного образца на основании имеющихся значений атрибутов [2, с.139]. Другими словами, классификация – это процесс определения ярлыка с дискретным значением (класс) для непомеченной записи, а классификатор – это модель (результат классификации), которая предсказывает один атрибут – класс образца – если заданы некоторые другие атрибуты этого образца. [2, с. 139]. Кластеризация (clustering) – очень близка к определению классификации, за исключением того, что изначально классы предметной области не заданы Ассоциация (dependency model) – выявление правил взаимосвязей между атрибутами или между значениями атрибутов во всем множестве данных или в его подмножестве. Последовательность – выявление цепочек событий, связанных во времени. Прогнозирование (predictability) – изучение данных с целью прогнозирования реальных значений. 224
Определение изменений и отклонений (change and deviation detection) – исследование наиболее значимых отклонений во множестве данных. Основные термины, участвующие в постановке задачи приводятся в разделе 2. В этом разделе приводятся как формальные термины для задачи классификации, так и специфические понятия для заданной предметной области, а также их соответствие между собой. В разделе 3 приводится общая постановка задачи классификации, использующей вышеописанные термины. Раздел 4 содержит описание девяти алгоритмов классификации, наиболее часто встречающихся в литературе. В разделе 5 приведен подход к классификации пакетов и описаны наиболее распространенные системы. Раздел 6 содержит краткое описание выбранного алгоритма для классификации химических проб. В “Заключении” подведен итог работы и кратко описаны следующие статьи по данной тематике.
2. Терминология Введем некоторые термины: Признаком
назовем
пару
x имя, множество _ значений .
Множество
значений признака обозначим через Т. Множество значений может быть задано типом признака: целое или вещественное, перечисление или диапазон. Словарь признаков представляет собой множество всех признаков xi ni , Ti , i 1,..., N , где ni – имя, Тi – множество значений для признака xi. Пространство признаков представляет собой декартово произведение множеств значений признаков Ti , i=1,..,N: T1 T2 ... TN Объект
– представляет собой пару имя , ( x1 ,..., x N ) , где x1 ,..., x N –
точка в признаковом пространстве. Множество всех объектов обозначим через W. Множество W является конечным или счетным, и все объекты могут быть занумерованы. Пусть на множестве объектов W определено m классов 1 ,..., m . Для каждого класса существует характеристическая функция: 1, (1) 1,
Таким образом, класс представляет собой пару имя , , где χ – характеристическая функция, определенная формулой (1). Если для всех j=1,..,m заданы характеристические функции χj, то для каждого объекта W можно определить его класс j . Таким образом, множество χj определяет классы объектов. 225
Обучающая выборка – это множество объектов V 1 ,..., l1 , l1 1 ,..., l2 ,..., lm 1 ,..., lm , для которых известны включающие
их классы: 1 ,..., l1 1 , l1 1 ,..., l2 2 ,..., lm 1 ,..., lm m Помимо характеристических функций χj будем рассматривать функции fj(x,V), про которые известно, что fj(x,V)=-1, если x j , fj(x,V)=1, если x j . Такие функции будем называть разделяющими функциями. Если задана обучающая выборка, то по ней можно построить разделяющие функции. Классификация – это сопоставление каждому объекту определенного класса, то есть определение множества пар объект, класс Тестовый объект – объект с некоторым заданным набором значений признаков и неизвестным классом. Задача классификации. Заданы множество имен классов и обучающая выборка. Требуется построить разделяющие функции для этих классов. Далее следуют пояснения к терминам рассматриваемой предметной области и их соответствие вышеописанным терминам: Проба – некоторое количество (вообще говоря, неизвестного) химического соединения, достаточное для проведения экспериментов по выявлению количественных и качественных характеристик соединения, которые требуются для идентификации соответствующего химического соединения. В алгоритмах классификации проба – это объект предметной области. Идентификация химического соединения состоит в определении класса, которому принадлежит проба. Пробе соответствует объект. Атрибут пробы – какое-либо химическое или физическое свойство соединения. У каждого атрибута пробы имеется тип, описывающий его возможные значения. Атрибут пробы является признаком объекта. Обучающая выборка в терминах предметной области – это набор проб, для которых известны классы (вообще говоря, с некоторой степенью вероятности).
3. Постановка задачи классификации Для тестовой пробы, или, другими словами, тестового объекта класс неизвестен. Поэтому для программиста задача ставится как нахождение класса для тестового объекта по некоторым заданным значениям атрибутов этого объекта. Для нахождения класса строится система, другими словами, модель, или классификатор. Обучение системы происходит с помощью обучающей выборки, то есть множества объектов, для которых значения их классов достоверно известны. Кроме того, в систему должны вводиться экспертные знания о классификации проб с помощью шаблонов, то есть система должна аккумулировать множество экспертных шаблонов. Будет считаться, что все данные, используемые на стадии обучении системы, являются истинными. 226
У задачи классификации для химической предметной области имеется ряд важных особенностей, которые существенно влияют на выбор решения. Вопервых, данные для построения и обучения системы носят не только экспериментальный, но и экспертный характер. В системе необходимо учитывать экспертные шаблоны. Во-вторых, типы многих атрибутов являются числовыми, поэтому многие шаблоны задаются с диапазонами значений атрибутов, а не перечислением. Шаблоны же, полученные на стадии обучения, в предикатных условиях которых содержится знак равенства, должны какимлибо образом быть преобразованы в шаблоны, задающие диапазонные предикаты. В-третьих, множество классов является бесконечным. Поэтому система никогда не будет окончательно сформировавшейся, она всегда будет обучаться новыми пробами.
4. Обзор алгоритмов решения задач классификации Существует достаточно много различных алгоритмов классификации. Каждый из них может давать хорошие результаты для одного класса задач и плохие результаты для другого класса задач. Например, работа классификатора на основе нейронной сети будет давать хороший результат при достаточно большом объеме данных, на которых проводится обучение, и при наличии примерно одинакового числа тестовых объектов в каждом классе. Если же во входных данных находится очень много объектов одного класса, то результат работы сети будет часто склоняться именно к этому классу, независимо от значимости остальных объектов. Для оценки методов классификации можно использовать следующие критерии: точность и правильность прогнозирования – способность корректно определять класс для новых данных; скорость работы – параметр вычислительных затрат на использование модели; робастность – способность делать корректный прогноз при “зашумленных” входных данных или данных с неполным набором атрибутов; масштабируемость – способность поддерживать эффективность метода при увеличении объема подаваемой на вход информации; интерпретируемость – характеристика метода, отвечающая за уровень понимания и способность проникновения в суть. Ниже перечислены основные алгоритмы классификации, упоминаемые в литературе и применяемые в промышленных системах. Каждый из этих алгоритмов обладает определенными свойствами, позволяющими делать предположения об их применимости на конкретном классе задач. Кроме того, у каждого из алгоритмов может иметься множество разновидностей, как, например, в п. 4). Как правило, в литературе приводятся общие принципы к построению классификатора, тогда как для реализации 227
требуется подробный анализ предметной области и правильный подбор детализированных алгоритмов.
4.1. Статистический метод Статистические заключения – это наилучшая форма анализа данных, имеющих причинные связи. Теория статистических заключений состоит из методов, таких что на основе одного из них можно сделать заключение или обобщение о всем пространстве объектов. Такие методы могут быть разбиты на две основные группы: вычисления и проверка гипотез.
4.2. Дерево решений Дерево решений – это определенный вид дерева, в котором каждый внутренний узел представляет собой контрольный критерий для атрибута, каждая ветвь представляет собой результат теста, а лист – это класс или подкласс. Самый верхний узел дерева – корень. Для классификации нового образца используется тестирование значений атрибутов этого образца в узлах дерева. Дерево решений может быть легко трансформировано в классификационные правила. На рис. 1 представлен пример графического представления дерева решений: o
o Правило 3
Правило 2
x>3.75
o
нет X
Правило 1
o Правило 4
X
o 3
нет
да
x
да
7
X
Правило 6 Правило 5
Ответ “о”
Ответ “о”
…
10
Рис. 1. Графические представления дерева решений
4.3. Алгоритмы обратного распространения (нейронные сети) Алгоритм обратного распространения является одним из наиболее популярных. Для него требуется задание набора параметров (например, топологии сети), определение которых лучше всего производить эмпирически. Нейронные сети критикуются за низкую способность к интерпретации. [3, с.27] Плюсами является высокая толерантность к зашумленным данным, а 228
также способность классифицировать данные, которые ранее не участвовали в обучающей выборке. Кроме того, уже разработано несколько алгоритмов, способных извлекать из нейронных сетей закономерности или правила.
4.4. Моделирование подмножества данных Примеры вариантов моделирования подмножества данных представлены на Рис. 2. o o oxx x xx o xx oo
o o oxx x xx o xx oo
o o oxx x xx o xx oo
o o oxx x xx o xx oo
пар “атрибут-значение”, а y – это класс. Правила, требующие минимальных предопределенных условий, называются повторяющимися. Правило, требующее минимальной специфики, называется точным. Метод ассоциативной классификации состоит из двух шагов. На первом шаге ищется набор всех вероятных правил для точных и повторяющихся правил. Используется итеративный метод, где знания от предыдущих шагов используются для упрощения поиска правила. На втором шаге для конструирования классификатора используется эвристический метод, в котором полученные правила располагаются в порядке значимости, основанной на их значениях точности и повторяемости. Алгоритм может требовать нескольких прогонок над множеством данных, в зависимости от длины самого длинного найденного правила. Когда классифицируется новый образец, для классификации используется первое найденное правило. Классификатор также содержит правило по умолчанию, имеющее наименьшую значимость и определяющее "типичный" класс для образца, класс которого не был рассмотрен в обучающем наборе данных. В третьем методе, называемом CAEP (Classification by Aggregating and Emerging Patterns), используются знания об объектах данных для получения “выявленных шаблонов”, на основе которых в дальнейшем конструируется классификатор. Алгоритм CAEP является достаточно хорошим (по параметру точности) по сравнению с другими алгоритмами. Он также показывает хороший результат, когда в наборе данных основной класс содержит мало тестовых наборов по сравнению с другими классами.
4.6. Классификация по k-ближайшему соседу
Рис. 2. Моделирование подмножества данных
4.5. Ассоциативные правила Существует несколько разновидностей классификаторов, основанных на ассоциативных правилах. Первый метод извлекает ассоциативные правила, основанные на кластеризации, и затем использует эти правила для классификации. В ARCS (Association Rule Clustering System) используется метод ассоциативных правил по формуле A(quan1) Λ A(quan2) => A(cat), где A(quan1) и A(quan2) – это тесты над множеством значений атрибутов (где значения определяются динамически), и A(cat) – символизирует класс для атрибутов, представленных в тестовых данных. Ассоциативные правила наносятся в двухмерную картинку. Алгоритм проходит по этой картинке в поисках правил, составляющих прямоугольные кластеры. Примыкающие наборы появляющихся числовых атрибутов могут быть скомбинированы в кластерные правила. Кластеризованные ассоциативные правила, полученные в результате работы алгоритма ARCS, могут применяться для классификации. Второй метод – ассоциативная классификация. Метод характеризуется правилами в форме condset => y, где condset – это множество наборов 229
Классификатор по ближайшему соседу основан на изучениях аналогий. Обучающая выборка описывается в n-мерном пространстве атрибутов. Каждый образец представляется в виде точки этого пространства. Если классификатору на вход дается неизвестный объект, то он ищет k ближайших к нему объектов из обучаемого множества. Степень близости определяется понятиями евклидового пространства. Для объектов X=(x1, x2,…,xn) и Y=(y1,y1,…,yn)d(X,Y) = √∑ (xi-yi)². Неизвестному объекту назначается класс, наиболее часто встречающийся среди k ближайших соседей. Такой алгоритм является “ленивым”, так как начинает строить классификатор, только когда дается неизвестный пример. В то же время, например, алгоритм с построением дерева, строит структуру независимо от того, надо классифицировать что-то или нет. Поэтому метод k-ближайших соседей может быть очень долгим для большого числа данных и большого заданного k. Для ускорения процесса можно вводить индексы.
4.7. Классификация, основанная на прецедентах В отличие от предыдущего алгоритма, где данные представлялись в виде точек Евклидова пространства, этот алгоритм преобразует данные или “случаи” как 230
сложные символические описания. Алгоритм используется для решения проблем, относящихся к обслуживанию клиентов, когда, например, случаи описывают диагностическую проблему, связанную с продуктом. Также он применяется в таких областях, как инженерия и право, где случаями являются технический проект или законы соответственно. Когда для классификации подается новый случай, сначала проверяется, не существует ли уже точно такая же ситуация (прецедент). Если подобная ситуация найдена, то в качестве решения выдается решение прецедента. Если не находится ни одного прецедента, то алгоритм пытается найти ситуации, в которых повторяются компоненты. Концептуально, эти обучающие ситуации могут рассматриваться как ближайшие соседи для новой ситуации. Если ситуации представляются в виде графа, то поиск ведется по подграфам, похожим на подграфы неизвестной ситуации. Затем алгоритм пытается сопоставить все решения “соседей”, чтобы выдать решение по новой ситуации. Если по какому-либо решению появляется несовместимость, то делается откат в поисках других решений. В этом алгоритме могут использоваться какие-либо дополнительные знания и выдавались правдоподобные стратегия решения задачи, чтобы комбинированные решения. Сложными задачами в данном алгоритме является поиск хорошей метрики для сравнения подграфов, разработка эффективной техники индексирования обучающих ситуаций и методы комбинирования решений.
4.8. Генетические алгоритмы. Обучение нейронной сети Подход генетических алгоритмов [3, с.27] является попыткой объединить идеи природной эволюции. Начальная популяция создается по случайным правилам. Каждое правило может быть представлено набором или строкой битов. В качестве простейшего примера можно рассмотреть тестовую выборку с двумя классами С1 и С2, представленную двумя атрибутами A1 и A2. Тогда правило “если А1 и не А2, то С2” может быть закодировано строкой “100”, где два левых бита представляют атрибуты А1 и А2, а правый – класс. Аналогично, правило “если не А1 и не А2, то С1” представляется в виде “001”. Вообще, если у атрибута имеется 2k различных значений, то для кодирования значения этого атрибута могут быть использованы k бит. Основываясь на правиле сохранения подходящих данных, новая популяция формируется из правил, подходящих для текущей популяции, а также “отпрысков” (объектов, порожденных этими правилами) этих правил. Обычно подходящие правила проверяются на пригодность на основе использования набора тестовых данных. “Отпрыски” создаются путем применения генетических операторов перехода и мутации. В переходе меняются местами подстроки из пары правил, образуя 231
новую пару правил. В мутации инвертируются (меняются местами) произвольно выбранные биты строки. Процесс формирования новой популяции, основанный на правилах предшествующих популяций, продолжается до тех пор, пока популяция P “развивается” и каждое правило из Р удовлетворяет предопределенным подходящим условиям. Генетический алгоритм легко распараллеливается и используется как для классификации, так и для решения задач оптимизации. При поиске закономерностей он может использоваться для оценки пригодности других алгоритмов.
4.9. Классификация для неточных множеств Теория неточных множеств может использоваться для классификации и выявления структурных связей в нестрогих или зашумленных данных. Этот подход применяется для атрибутов, имеющих дискретные значения. Если атрибуты принимают не дискретные значения, то они должны быть дискретизированы. Теория неточных множеств основана на установлении эквивалентных классов для заданной обучающей выборки. Все образцы множества, относящееся к эквивалентному классу, являются неразличимыми, т.е. эти образцы считаются идентичными, несмотря на наличие различий в значениях атрибутов. Для множества данных из реальной жизни часто оказывается, что классы не могут быть различаться в терминах возможных значений атрибутов. Неточные множества могут использоваться для неточных или “грубых” классов.
Класс С Верхняя аппроксимация С Нижняя аппроксимация С
Рис. 3. Графическое представление верхней и нижней аппроксимаций
232
Неточные множества могут использоваться для будущего восстановления (когда могут быть выявлены и удалены атрибуты, не способствующие классификации) и анализа (когда значения каждого атрибута определяются с учетом поставленной задачи). Задача нахождения минимального подмножества (предела) атрибутов, которые могут описать все концепции имеющегося множества, является NP-сложной. Пример. У классификаторов, основанных на правилах, имеется тот недостаток, что они строго разделяют непрерывные атрибуты. Рассмотрим, например, приложение для подтверждения потребительского кредита. Изначально правило говорит, что приложение подтверждает кредитоспособность клиентов, работающих более двух лет и обладающих достаточно высоким доходом (например, 50000 в год): Если {стаж_работы 2} & {доход 50000}, то кредит = “подтвержден”. В соответствии с этим правилом клиент получит кредит, если он работает более двух лет и получает, например, 50000, но никак не 49000. Такой строгий порог может выглядеть несправедливым. Нечеткая логика допускает более “мягкие” правила или границы. Вместо того, чтобы строго нарезать множества по категориям, нечеткая логика использует истинностные значения от 0.0 до 1.0 для представления степени принадлежности определенного значения данной категории. Таким образом, при использовании нечеткой логики мы можем пропустить и доход в 49000, но не с такой высокой степенью достоверности, с какой будет одобрен доход в 50000. Нечеткая логика применима для систем поиска закономерностей, выполняющих классификацию. Это позволяет использовать преимущества работы с высоким уровнем абстракции. В общем случае, использование нечеткой логики в системах, основанных на правилах, предполагает следующее. Значения атрибутов переводятся в нестрогую форму. Они разбиваются на дискретные категории: высокую, среднюю и низкую. Как правила, системы, основанные на нечеткой логике, сопровождаются графическими инструментами для пользователей, чтобы они могли задавать эти категории. Для нового объекта могут применяться несколько нестрогих правил. Каждое подходящее правило способствует нахождению этого объекта в нужной категории. Обычно истинностные значения для каждой предполагаемой категории суммируются. Суммы, полученные на предыдущем шаге, комбинируются в выходное значение. Этот процесс может проводиться путем взвешивания истинностных сумм для каждой категории путем умножения на среднюю величину правдивости категории.
233
Нестрогая логика используется в ряде систем классификации, например для здоровья, и финансовой сфере.
5. Существующие пакеты для классификации В химической инженерии развитые модели используются для описания реакций и взаимодействий различных химических процессов. Современные средства разрабатываются также для визуализации этих структур и процессов [2, c.336]. Одной из разработок, поддерживающей подобные функции, является Paviolion Technologies Process Insights, в которой комбинируются нейронные сети, нечеткая логика и статистические методы. Это приложение успешно используется Eastman Kodak и другими компаниями для разработок в химическом производстве и контроле приложений для уменьшения потерь, улучшения качества продукции и повышения производительности. Это показывает большой интерес экспертов химической области к использованию в своей работе информационных систем. С привлечением все большего числа специалистов будут накапливаться базы информации об исследуемых соединениях, пробах и т.д. и, следовательно, возникнет необходимость анализа этих данных. Поскольку описание проб с помощью признаков является унифицированным для всех экспертов, накапливаемая база может использоваться повсеместно. Для химической области можно провести некую аналогию с фармацевтикой. На сегодняшний день в медицинской и фармацевтической областях используется классификация. В фармацевтике накоплен огромный объем знаний, разработаны системы для предоставления доступа пользователей к этой информации и организована подписка на обновление данных. Таким образом, пользователи во всем мире могут использовать экспертные знания. Если говорить о пакетных решениях в области выявления закономерностей, то, как правило, они делятся на три категории: профессиональные, универсальные и специализированные. Профессиональные пакеты рассчитаны на пользователя-специалиста в области статистики. Все универсальные пакеты имеют много пересечений по составу статистических процедур. Специализированные пакеты ориентированы на одну предметную область или несколько смежных областей, их алгоритмы заточены под определенные данные и наиболее актуальные задачи предметной области. В некоторых пакетах реализованы алгоритмы классификации [1, c. 35]. Описания некоторых пакетов приведены ниже: Наиболее старым продуктом на рынке считается система SAS. Этот пакет включает более 20 различных программных продуктов. Традиционно сложилось, что основными пользователями системы в России являются крупные предприятия, ВПК, государственные структуры. Для классификации в SAS представлены следующие модули: 234
BASE SAS – ядро системы со встроенным языком программирования 4GL и поддержкой языка работы с базами данных SQL, средств управления данными, индексов баз данных, возможностей доступа к широкому набору форматов данных, процедур описательной статистики и генерация отчетов; FSP обеспечивает полноэкранный доступ к данным, ввод, редактирование, преобразование данных, генерацию отчетов; GRAPH поддерживает деловую, научную, рекламную графику, различные шрифты и карты; STAT включает в себя многофункциональный набор статистических процедур анализа данных Основным достоинством SAS считают мощное интеллектуальное ядро, поддержку архитекторы клиент-сервер, возможность доступа и интеграции данных из любых источников. Главный недостаток системы – ее громоздкость, трудности в освоении, высокие требования к квалификации пользователя. Система считается универсальной. Пакет SPSS является представителем универсальной категории, хотя в первую очередь предназначен для работы статистиков-профессионалов [1, c.38]. Пакет обладает весьма полным набором статистических (более 60) и графических процедур, а также процедур создания отчетов. Кроме того, пакет отличается простым и удобным интерфейсом, и отличается высокой точностью вычислений. Пакет STATISTICA также ориентирован на пользователей-профессионалов. В нем имеется широкий спектр функциональных алгоритмов. По своей структуре STATISTICA состоит из нескольких связанных между собой “мини-пакетов”. Эти пакеты взаимодействуют между собой, поддерживая один и тот же формат системных файлов.
класса выдают ответ о принадлежности объекта с такими атрибутами к классу соответствующей разделяющей функции. Построение функций для каждого класса производится независимо друг от друга. Объекты обучающей выборки разбиваются на группы, принадлежащие одному классу и содержащие «подряд идущие значения атрибутов». Если рассмотреть отрезки, в которых содержатся объекты группы, то в них разделяющая функция определяется порядковым номером класса этого объекта. Граничные точки будут определяться по некоторой формуле от тестового объекта и обучающей выборки. Определение класса неизвестного объекта (пробы) производится с помощью разделяющих функций. Объект принадлежит тому классу, который выдает истинное значение на значениях атрибутах тестового объекта. Если разделяющие функции для всех классов не дают положительного результата, то считается, что тестовый объект принадлежит неизвестному классу.
7. Заключение В данной статье поставлена задача классификации, сделан обзор алгоритмов и решений по этой тематике, а также описан алгоритм классификации химических проб. В последующих работах будет представлено обоснование алгоритма, описанного в разделе 5, а также будет описана реализация этого алгоритма и результаты тестирования на реальных данных предметной области. Литература 1. Дюк В., Самойленко А. «Data Mining: учебный курс». СПб: Питер, 2001. 2. Mehmed Kantardzic, “Data Mining. Concepts, Models, Methods and Algorithms”. Wiley-Interscience, 2003 3. Роберт Калан, “Основные концепции нейронных сетей”. Вильямс, 2003 4. Ю.А. Шрейдер, А.А. Шаров “Системы и модели”, Москва «Радио и связь», 1982.
6. Как будет решаться поставленная задача В качестве основы для реализации классификации химических проб был выбран алгоритм классификации на основе разделяющей функции. В алгоритме используются знания объектов данных (обучающей выборки) для построения разделяющих функции, которые в дальнейшем применяются для конструирования классификатора. Описание алгоритма в литературе дает лишь общие принципы работы, а как его реализации могут существенно различаться. Ниже представлено описание реализации алгоритма для классификации. Работа классификатора делится на два больших этапа: обучение системы и классификация тестового объекта. Рассмотрим первый этап, на котором строится классификационная модель. Входными данными для этого этапа служит обучающая выборка. Проводится построение разделяющих функций, которые по набору значений атрибутов 235
236
Формирование профессиональных компетенций современного разработчика ПО В. В. Кулямин, В. А. Омельченко, О. Л. Петренко {kuliamin, vitaliy, olga}@ispras.ru Аннотация. Разработка программного обеспечения (ПО) состоит не только из инженерно-технических видов деятельности. Она включает также когнитивные и социальные аспекты, адекватное внимание к которым не менее важно для успеха, а в сложных проектах играет решающую роль. Важность этих аспектов также повышается в тех проектах, где используются новые подходы к разработке ПО, включая формальные методы. Поэтому для обеспечения успешного применения подходов такого рода, участники таких проектов должны обучаться не только используемым в них техникам, но и навыкам социального характера, позволяющим прилагать их к практическим задачам в рамках определенного контекста. Серьезную помощь в этом могут оказать курсы и тренинги на основе активных методов обучения, поскольку они гармонично сочетают в себе обучение обоим видам необходимых умений — содержательно такой курс учит формальным методам, а форма процесса обучения способствует развитию необходимых когнитивных и социальных навыков.
1. Введение Развитие современной науки и техники связано с использованием информационных технологий в различных областях. Эффективность информационных технологий и качество их результатов во многом определяются характеристиками используемого программного обеспечения (ПО). В настоящее время большинство требований к этим характеристикам формируются не самими программистами, а другими группами пользователей информационных технологий, которые чаще всего не знакомы с особенностями и спецификой работы программистов. Поэтому требования к ПО разнообразны и часто противоречивы. Они описывают такие его характеристики, как надежность, понятность интерфейса, удобство обучения работе с ПО, его пригодность для использования в заданной предметной области, производительность, набор платформ, на которых оно должно работать, и т.д. Для удовлетворения всех этих требований необходим адекватный анализ потребностей пользователей и ограничений предметной области в рамках каждого конкретного проекта по разработке ПО, и, конечно же, нужны 237
специалисты, умеющие проводить такой анализ. Чтобы обеспечить стабильное развитие отрасли производства ПО на дальнюю перспективу и соответствие ее возможностей нуждам современного общества необходимо готовить специалистов, владеющих необходимыми знаниями и навыками для решения задач такого рода. Обычно разработка программного обеспечения описывается как деятельность, связанная с решением технических задач и увязкой этих решений с необходимыми экономическими показателями производимых продуктов и услуг. Практика показывает, что есть неучитываемые таким подходом, но играющие ключевую роль в успешности проектов виды человеческой деятельности, включенные в разработку ПО. Решения, принимаемые всеми разработчиками на различных этапах, и способность членов проектной команды эффективно обмениваться информацией как внутри команды, так и с другими заинтересованными лицами, играют в успешности проекта большую роль, чем используемые в нем техники разработки. Навыки принятия решений в условиях нехватки информации и умение эффективно общаться важны не только для людей, играющих ключевые роли в проекте, таких как его руководитель, бизнес-аналитик или архитектор, но и для обычных разработчиков. Много раз в ходе проекта им приходится принимать минирешения, о том, реализовать ли некую функциональность в виде одного компонента или двух, использовать ли тот или иной алгоритм, и, конечно же, им очень часто приходится общаться между собой, с архитектором, тестировщиками и руководителем проекта, а иногда и с пользователями. Сферы деятельности, в которых должен разбираться разработчик ПО для создания программ высокого качества, представлены на Рис. 1. Навыки, необходимые любому разработчику, могут быть (не слишком строго) разделены на три вида. Технические навыки, которые чаще всего рассматриваются как единственные необходимые. Они характеризуют знание разработчиком основных методов и техник разработки программ и умение использовать их на практике в контексте решаемых на практике задач. Когнитивные навыки, связанные с пониманием требований и ограничений в рамках новой предметной области, умением отделять существенное от несущественного для данной задачи, упорядочиванием задач по их приоритетности, построением решений на основе неполной информации о требованиях и выбором из них наиболее подходящего. Социальные навыки, заключающиеся в умении поддерживать эффективное общение с другими людьми, принимать цели проекта, умении работать в команде и координировать свою работу с нуждами ее членов. Социальные навыки также определяют стиль общения человека — то, как он/она слушает других людей, реагирует на услышанное, участвует в обсуждениях и выдвигает аргументы в пользу собственной точки зрения. 238
Внимание к социальным навыкам было, наверное, впервые привлечено осознанием в 50-е-60-е годы в США того факта, что большинство людей живут и работают в группах, но чаще всего не отдают себе отчета в том, как они в них участвуют, какими их видят другие люди, какие реакции вызывает у окружающих их поведение. Одной из первых работ, в которых эта идея развивалась в приложении к разработке ПО, является книга Ф. Брукса «Мифический человеко-месяц» [1]. Методы моделирования Цели проекта Изобретение решений
Командная работа Разработчик
Предметная область
Техническое общение Оценка рисков
Используемые технологии Рис. 1. Области, в которых должен разбираться разработчик современного ПО. Проблемы овладения такими навыками достаточно актуальны в более широком контексте. В частности, меморандум Европейской Комиссии о постоянном обучении [2] подчеркивает важность для эффективного обучения таких социальных умений, как умение действовать уверенно, умение направлять собственные действия на достижение нужных результатов и умение принимать рискованные решения, а также таких когнитивных навыков, как способность учиться, приспосабливаться к изменяющемуся окружению, быстро воспринимать необходимые новые навыки и находить нужную информацию в широком информационном потоке, обрушивающемся на каждого включенного в общественную жизнь человека в наше время. Обычно эти навыки считают необходимыми только для тех студентов, чья будущая профессиональная деятельность связана с общением с людьми, т.е. для обучающихся на менеджеров, учителей, социальных работников и пр. Но в тех случаях, когда в проекте используются новые подходы к разработке ПО, например, формальные методы, такие навыки становятся критическими как для успеха проекта самого по себе, так и для успешного приложения новых техник. Это вызвано значительно более сложными познавательными проблемами в рамках таких проектов — нужно не только вникнуть в предметную область и понять задачи, которые предстоит решить, но и изложить полученные знания в 239
новой, необычной форме, необходимой для эффективного использования формальных подходов. Кроме того, само понимание задач должно быть гораздо более глубоким и детальным, иначе формальные методы становятся гораздо тяжелее традиционных в использовании. А число микро-решений, которые необходимо принять, становится значительно больше. Серьезные социальные навыки необходимы, чтобы сделать эту работу понятной и полезной для различных заинтересованных лиц и других разработчиков, не использующих формальные методы напрямую. Применяя новые техники, нужно помнить, что люди обычно не любят иметь дело с новыми вещами, что нужно уметь разговаривать с живыми людьми, для которых формальное доказательство — не решающий аргумент, а лишь средство давления, используемое против них, — а персональные привязанности, эмоции, амбиции и привычки имеют большое значение. Нужно уметь работать в разных организациях, учитывая доминирующий в них вид организационной культуры при получении необходимой информации и представлении результатов проекта. Таким образом, успешность создания ПО, связана не только с техническими знаниями участников проектной команды, но и с их умением адаптировать свои личные качества и навыки к контексту проекта и сочетать их с интересами коллектива. Иначе «невежество, амбициозность, эгоизм, леность, слабость и разного рода страсти приводят к тому, что общие интересы ослабевают, уступая место интересам личным, и это обстоятельство порождает вечную борьбу» [3], а не успех. Итак, для обеспечения успеха при применении формальных методов на практике, нужно обучать персонал не только их методологическим основам, но и прививать ему необходимые когнитивные и социальные навыки. Эти навыки должны стать для такого инженера или студента не менее привычными, чем умение доказывать теоремы. Мы утверждаем, что активные методы обучения [4,5] являются гораздо более эффективным инструментом обучения передовым методам разработки ПО, и формальным методам в частности, чем традиционные подходы к обучению. Активные методы эффективно вырабатывают у студентов необходимые социальные навыки за счет акцента на автономную работу, самостоятельный выбор направления действий, самостоятельное принятие решений, необходимость общения с другими учащимися, необходимость подстраиваться под изменения в рамках образовательного процесса. В то же время классические подходы к обучению подталкивают обучаемых к пассивному восприятию информации и превращают их в хорошо информированных людей, неспособных без внешнего руководства использовать свои огромные знания на практике в постоянно меняющемся контексте. Активное обучение построено на том, что преподаватель более не является просто источником информации, а вовлекает студентов в процесс обучения, координирует их самостоятельную деятельность, вынуждает их 240
самостоятельно размышлять над материалом курса и применять изучаемые методы на практике. Классический подход к обучению, основанный на предоставлении информации, напротив, нацеливает учащихся на запоминание и воспроизведение в дальнейшем некоторого объема знаний. Такой подход делает акцент на внимании и запоминании данных, в то время, как для эффективного овладения социальными и когнитивными навыками должны быть задействованы все аспекты восприятия и эмоциональной сферы обучаемого. Активные методы обучения — это методы, не направленные на изложение готовых знаний и запоминание их студентами, а побуждающие учащихся к активной мыслительной и практической деятельности в процессе овладения учебным материалом. Активная деятельность в обоих этих направлениях должна стать основой самостоятельного овладения ими знаниями и умениями. Многие авторы ([6]) выделяют следующие признаки активных методов обучения: принудительная активизация мышления, вынуждающая обучаемого быть активным независимо от его желания; достаточно длительное время вовлечения обучаемых в учебный процесс, поскольку их активность должна быть не кратковременной и эпизодической, а в значительной степени устойчивой и длительной; самостоятельная творческая выработка решений и повышенная степень мотивации. В рамках одной статьи невозможно описать все техники, которые могут помочь при развитии необходимых разработчикам ПО когнитивных и социальных навыков. Далее мы попытались предоставить несколько примеров таких техник, которые подталкивают студентов к активному мышлению и использованию получаемых при обучении знаний в практической деятельности.
2. Активное обучение формальным методам Для каждого вида профессиональной деятельности важны те или иные технические, когнитивные и социальные навыки. Для области формальных методов мы выделили следующие группы социальных и когнитивных навыков, имеющих большое значение: умение выслушивать оппонентов; умение эффективно общаться с другими людьми в рамках профессиональной деятельности, где под эффективностью понимается способность получения необходимой информации в кратчайшие сроки и с наименьшими затратами со стороны коллег; умение адаптировать свои знания к изменяющимся реальным условиям. 241
Далее рассматриваются несколько приемов, которые позволяют развить у студентов наряду с техническими навыками перечисленные выше когнитивные и социальные. Эти техники были использованы на практике и продемонстрировали хорошие результаты. Это ролевая игра, кластер, мозговой штурм и дебаты.
2.1. Ролевая игра Ролевая игра является одной из техник, нацеленных на выработку навыков самостоятельного решения проблем, хотя в обучении техническим и инженерным предметам он используется не очень часто [7,8]. Ролевая игра — это искусственно сконструированная последовательность ситуаций, имитирующая те или иные важные стороны реальной деятельности. Во время игры ее участники играют определенные роли и ведут себя, исходя из соответствующих точек зрения на определенную ситуацию. Цель такой игры заключается в том, чтобы найти возможные решения проблем, которые возникают в рассматриваемых ситуациях. Например, следующая игра может быть организована для студентов старших курсов с целью оценки ценности предложенной научной идеи. Участники разыгрывают различные роли, чтобы получить оценку идеи с различных точек зрения. ‘Пропагандист’ объясняет идею, ее перспективы и возможные положительные последствия ее разработки и применения; ‘Теоретик’ рассматривает связи идеи с основами предметной области и другими теоретическими вопросами; ‘Технический эксперт’ оценивает полезность и важность идеи с точки зрения эффективного применения ее на практике, а также удобство ее использования; ‘Менеджер’ выясняет влияние и последствия использования идеи на практике на промышленные процессы, распределение работ, командную работу; ‘Инвестор’ оценивает потенциальные выгоды от возможных применений идеи, возможность и экономическую оправданность разработки коммерческих продуктов на ее основе, или интеграции практических применений идеи в различные существующие решения. В Таб. 2 представлен пример результата ролевой игры — оценки идеи с различных точек зрения. Ролевые игры позволяют повысить интерес к изучаемому материалу, выявить пробелы в знаниях и развить социальные навыки. Однако, ролевая игра ведется по жестким правилам и не может отразить многообразие ситуаций и динамизм, присущие реальной жизни. Очень трудно составить набор ролевых игр, которые позволят отработать большинство важных реальных ситуаций в данной области. 242
Идея: Генерация тестовой последовательности в результате обхода графовой модели тестируемой системы как неизвестной местности Пропагандист
Технический эксперт Явные графовые Идея актуальна Графовые мокак достаточно дели сложных модели дают надежный метод возможность систем могут лучше контро- контроля быть предкачества. ставлены очень лировать ход компактно. тестирования.
Достаточно сложные ситуации могут быть протестированы автоматически. Качества такого тестирования очень высокое.
Теоретик
Менеджер
Инвестор
Идея обещает некоторое повышение качества ПО.
Идея может быть реализована в виде продукта, только если продукт будет нацелен на использование при разработке ПО с повышенными требованиями к надежности. Нет ясной связи Нужно предМожет исполь- Неявные гразоваться как фовые модели между тестиложить менее способ посттяжелее описать, рованием и трудоемкий роения адапособенно тем, требованиями — способ описания зачем нам тести- графов. тивных тестовых кто прежде с ровать все эти последователь- ними не сталкивался. ситуации? ностей. Этот подход Для того, чтобы Идея может нужно сделать научиться использоваться более удобным использовать для создания для испольэтот метод, модулей зования. тестировщикам тестирования, необходим подключаемых к специальный средам тренинг. разработки. Необходим инструмент с графическим пользовательски м интерфейсом, который будет помогать строить модели такого рода.
активности, и человек приобретает умение, с одной стороны, успешно выходить из критической ситуации, а с другой, позитивно отражать эти ситуации в своем социальном опыте. Иначе говоря, в соответствии с этим методом надо не только не бояться сложных, негативных ситуаций, но использовать их для поступательного развития у студентов навыков принятия решений и уверенности в собственных силах.
2.2. Кластер Методы активного обучения предполагают не только создание новой методики обучения и изменение критериев оценки подготовки студентов, но, прежде всего, осознание преподавателем своей новой роли, в которой главной является помощь обучаемым в самостоятельном овладении предметом, а не его преподавание. При активном обучении приоритетными являются не усвоение и воспроизведение готовых знаний, а самостоятельное приобретение и особенно применение полученных знаний. Активные методы обучения вынуждают студентов вести активную работу со знанием, задумываясь над ним, анализируя его и сравнивая с уже имеющимися у них знаниями. При активном обучении не должен поддерживаться подход к обучению некоторых студентов, когда они говорят: “А вы скажите как нужно, мы так и сделаем”. Некоторые способы изменения отношения к учебному материалу основаны на личностном принятии знаний, в результате которого полученное знание становится не пересказом какого-либо учебника, а собственным знанием студента. Отмечено, что студенты, обучающиеся по такой системе, хорошо объясняют полученные знания, так как они ими приняты. Для привязки знаний к личному опыту можно использовать кластер [9]. Кластер создает условия для построения ассоциативных связей между новым материалом и имеющимся опытом, причем эти связи основаны не только на подобии, но и на эмоциональном восприятии, интуиции, а также на основе предположений, возможно ошибочных. Перед началом лекции по новой теме каждый студент рисует кластер на эту тему. Последовательность действий при рисовании кластера следующая: 1. Посередине чистого листа написать ключевое слово или фразу, ключевую для данной темы. 2.
Вокруг него без какого-либо плана или упорядоченности записываются слова или фразы, выражающие идеи, факты, образы, подходящие для данной темы или кажущиеся как-то связанными с ней.
3.
По мере записи, появившиеся слова соединяются связями с ключевым понятием. Такое соединение может быть иерархическим. При этом должны соблюдаться следующие правила:
Таб. 2. Пример результатов ролевой игры. Эффективность ролевых игр можно повысить за счет использования метода "развивающего дискомфорта". Действенность этого метода основана на психологической перестройке личности под воздействием стихийно возникающих или специально организованных эмоционально негативных ситуаций. В результате такой перестройки меняется характер проявляемой 243
не нужно бояться записывать все, что приходит на ум. Дать волю воображению и интуиции; 244
продолжать работу, пока не кончится время или не иссякнут идеи; стараться построить как можно больше связей и не следовать по заранее определенному плану. Бесполезны на практике С трудом интегрируются в современные процессы разработки Интересный подход
Позволяют добиться высокой надежности ПО
Формальные спецификации Очень сложны
Мотивируют людей к приобретению новых умений
Предназначены для построения правильного ПО
Многие люди не могут их понять
Вызов для способностей разработчика
Рис. 3. Пример кластера понятия ‘Формальные спецификации’. На Рис. 3. представлен пример кластера понятия ‘Формальные спецификации’. Перед началом рисования кластера преподаватель должен четко сказать, сколько времени отводится на эту работу. Когда кластер у каждого нарисован, нужно попросить одного студента (только по желанию!) нарисовать свой кластер на доске. Если желающих рисовать нет, то преподаватель рисует свой собственный кластер. Обсуждать ничего не нужно. Каждый самостоятельно сравнивает свой кластер с тем, который нарисован на доске и при желании может внести изменения в свой кластер. После окончания лекции каждый студент может дорисовать кластер: добавить новое знание, или что-нибудь убрать. Очень полезно при возможности организовать обсуждение кластера в малых группах или в парах. Результатом такого обсуждения должны стать невыясненные вопросы, ответы на которые должны быть получены на последующих занятиях. Кроме того, такое обсуждение позволяет повысить коммуникабельность студентов.
245
2.3. Мозговой штурм Для студентов старших курсов, начинающих исследовательскую деятельность, очень важно иметь некоторый набор идей в качестве отправной точки исследований. Для получения стартового набора идей может использоваться мозговой штурм [10]. Мозговой штурм организуется в несколько этапов. 1. Участники штурма должны быть ознакомлены с темой исследований студента. Эта часть может быть организована следующим образом. (a) Студент и его руководитель подготавливают конспект по теме, проблемам исследуемой области и используемым в ней методам. (b) Каждый участник штурма читает подготовленный конспект. (c) Участники формулируют вопросы, касающиеся проблем в рассматриваемой области. Эти вопросы записываются на доске. (d) Студент делает доклад на заданную тему, в котором должны быть сформулированы его интересы в исследуемой области и даны ответы на вопросы участников штурма. (e) После доклада вопросы, на которые были получены ответы (то, что ответ на вопрос получен, должен подтвердить участник, задавший этот вопрос), отмечаются знаком “+”. Никаких новых вопросов задавать нельзя. 2. Участники предлагают идеи возможных направлений дальнейшего исследования. При этом должны соблюдаться следующие правила. (a) Каждый участник имеет право на выступление в течение 30 секунд. Во время такого выступления должно быть сформулировано не больше одной идеи. (b) Количество выступлений одного участника неограниченно. (c) Выступление нельзя прерывать. (d) Каждый участник имеет право ничего не говорить. (e) Идея выступления должна быть сформулирована по возможности четко, желательно в одном предложении. (f) Во время выступления нельзя обсуждать, критиковать и оценивать предыдущие выступления. (g) Запрещено использование в выступлениях выражений “очевидно, что...”, “вы не понимаете...”, “не была дана научная концепция...”, “я хочу уточнить...”, “я хочу объяснить...” и т.п. (h) Порядок и корректность выступлений обеспечивает ведущий штурма. (i) Все предложенные идеи записываются ведущим. 3. Участники оценивают все предложенные идеи на субъективной основе, но в то же время некоторым систематическим образом, например, на основе таблице ПМИ (Плюс-Минус-Интересно). Этот процесс может быть организован следующим образом. 246
(a) Для каждой предложенной идеи и каждого участника подготавливаются листы бумаги, содержащие название идеи и три колонки для записей. В первую колонку вписываются аргументы в поддержку идеи, во вторую — против нее, в третье колонке записываются интересные аспекты, касающиеся данной идеи. В другой схеме наряду с плюсами и минусами формулируются возможные последствия применения идеи на практике. (b) Каждый участник получает листы со всеми идеями и заполняет их. Необязательно оценивать все идеи. Пример заполненного листа показан в Таблице 4. (c) Все листы собираются для составления интегральных оценок. 4. Студент и его научный руководитель подводят итоги рассмотрения всех идей и определяют наиболее перспективные идеи. Идея: Использование методов морфологического анализа для нахождения дефектов в ПО Плюсы
Минусы
Интересные моменты
Совсем новая
Необходим исходный код ПО
Может быть использована в комбинации с обычными методами статического анализа
Может быть Нужно прояснить понятие дефекта использована для нахождения очень тонких дефектов Если в качестве дефекта будет рассматриваться корректный код, нужно предпринимать сложные действия по исправлению такой ситуации
Стандарт POSIX предоставляет строгое описание функциональности операционной системы За Против Стандарт по определению является Формальные правила оформления строгим описанием. Он создается на документа не гарантируют строгости основе формальных правил, представленного в нем регламентирующих описания содержательного текста. отдельных функций. Поддержка: Если почитать POSIX, легко заметить, что его требования оформлены в соответствии с определенным набором правил. POSIX представляет выработанный POSIX является компромиссом между большой группой экспертов консенсус многими крупными поставщиками по поводу функциональности операционных систем (ОС), взгляды операционных систем. Он существует которых на их разработку могут значительно отличаться. более 20 лет, за это время все существенные дефекты были найдены и устранены. Поддержка: Двусмысленности неизбежны в стандарте, объединяющем несколько разных подходов к проектированию ОС. Множество операционных систем успешно используют POSIX как рекомендации по предоставляемым функциям. Возьмем, например, функцию создания потока (thread). POSIX говорит, что эта функция может взаимодействовать с подсистемой управления динамической памятью, но ничего не говорит о том, в чем именно может заключаться это взаимодействие. Таб. 5. Пример результата дебатов.
Таб. 4. Пример субъективной оценки идеи, полученной в результате мозгового штурма. Организация мозгового штурма должна помогать участникам генерировать и высказывать интересные идеи, какими бы фантастическими или безумными они не казались на первый взгляд. Также участники должны быть освобождены от давления авторитетных мнений, они не должны быть вынуждены защищать свои идеи — любые идеи должны приниматься к рассмотрению. 247
2.4. Дебаты Одним из важных навыков для разработки ПО является умение выслушать мнение, отличное от собственного, понять, на чем оно основывается, и принять это во внимание в дальнейшей работе. Дебаты [11] позволяют отработать данный навык. 248
В начале на доске записывается спорное утверждение, которое будет обсуждаться. Каждый участник по отдельности или каждая группа участников выдвигает аргументы, поддерживающие или опровергающие рассматриваемое утверждение. Каждый аргумент может быть в свою очередь поддержан другими утверждениями. Все аргументы и поддерживающие их утверждения записываются на доске. Целью дебатов является предоставление каждому участнику материала для формирования собственной точки зрения на обсуждаемую тему. Другой целью является тренировка навыков в отстаивании своей точки зрения и понимании других, отличных от нее. Студенты знают, что им могут возразить, они психологически готовы к этому, они тренируются концентрироваться на существенных деталях, анализировать и оценивать различные точки зрения на предмет обсуждения и относиться с уважением к противоположным и, может быть, непопулярным точкам зрения. Примеры записей на доске после дискуссии по поводу некоторого утверждения представлены в Таблице 5.
3. Заключение В статье предложена идея интегрированного обучения техническим, когнитивным и социальным навыкам, необходимым при использовании передовых методов разработки ПО, в частности формальных методов, на практике. Такое интегрированное обучение может быть организовано на основе методов активного обучения. В статье представлены несколько таких методов, помогающих вырабатывать необходимые навыки социального плана — умение слушать и принимать во внимание противоположные точки зрения, умение взаимодействовать эффективно при обсуждении профессиональных проблем, умение применять знания в реальных нестандартных ситуациях. В статье описаны четыре техники обучения — ролевая игра, кластер, мозговой штурм и дебаты. Авторы успешно применяли эти техники в обучении современным методам тестирования ПО, основанного на моделях [12,13], и уверены, что они могут использоваться для обучения любым формальным методам и особенно полезны при обучении их использованию на практике. Было проведено несколько тренингов с использованием описанных техник и некоторых других. Тренинги продемонстрировали, что при таком обучении студенты лучше усваивают знания и становятся более активным и самостоятельными в практической работе.
[3]. А. Файоль, Г. Эмерсон, Ф. Тейлор, Г. Форд. Управление — это наука и искусство. Республика, М. 1992. [4]. S. C. Brock. Practitioners’ views on teaching the large introductory college course. 12 pp. Kansas State University Center for Faculty Evaluation and Development. ERIC Document Reproduction Service No. ED 171 208, 1976. [5]. Labinowicz, Ed. The Piaget Primer: Thinking, Learning, Teaching. Menlo Park, CA: Addison-Wesley Publishing Co., 1980. [6]. Педагогические технологии. Под ред. В. С. Кукушкина. М., 2004. [7]. Dennis M. Adams. Simulation Games: An Approach to Learning. Worthington, Ohio, Charles A. Jones Publishing Company, 1973. [8]. John P. Hertel, and Barbara J. Mills. Using Simulations to Promote Learning in Higher Education: An Introduction. Stylus Publishing, Herndon, VA, 2002. [9]. Tony Buzan. Use Both Sides of Your Brain. New York: Dutton, 1974. [10]. James L. Marra. Advertising Creativity: Techniques For Generating Ideas. Englewood Cliffs, NJ: Prentice Hall, 1990. [11]. Ronald T. Hyman. Improving Discussion Leadership. New York: Columbia Univ., Teachers College Press, 1980. [12]. O. L. Petrenko, V. A. Omelchenko. Rapid Trainings on Specification Based Testing Tools. In Proc. of 1-st South-East European Workshop on Formal Methods, Thessaloniki, Greece, 2003. В. А. Омельченко, О. Л. Петренко. Обучение передовым [13]. В. В. Кулямин, технологиям разработки ПО: проблемы и методы их решения. Труды ИСП РАН, т. 5, 2004, стр. 101–120.
Литература [1]. Ф. Брукс. Мифический человеко-месяц или как создаются программные системы. Спб., Символ-Плюс, 2001. [2]. A Memorandum on Lifelong Learning: Commission StaffWorking Paper. European Commission. Directorate General for Education and Culture. European Commission, 2000. SEC (2000) 1832.
249
250