Согласно закону Мура, сложность компьютерных микросхем удваивается каждые 18 месяцев, а сложность программного обеспечения растет еще быстрее. Это побуждает разработчиков компьютерных систем к поиску технологий, способных самостоятельно адаптироваться к изменению окружающей среды. Одна из таких технологий, адаптивная декомпозиция ресурсов, представляющая собой расширение операционной системы реального времени на уровне ядра, позволяет создавать безопасные группы из нескольких приложений и потоков, максимально эффективно используя ресурсы процессора.
Как правило, множество подсистем, процессов и потоков, составляющих современную встраиваемую систему, разрабатываются параллельно друг другу. Проект распределяется между многочисленными группами разработки; каждая из них имеет свои собственные цели, схемы назначения приоритетов задач и подходы к оптимизации процесса выполнения. Когда эти подсистемы интегрируются в общую среду исполнения, все ее части должны обеспечивать требуемый ответ при любом сценарии работы. Однако при таком способе разработки неизбежно возникают вопросы, связанные с производительностью. Многие из этих вопросов появляются только в процессе интеграции и проверочного тестирования, когда стоимость перепроектирования и перекодирования программного обеспечения оказывается чрезвычайно высокой. Разработчикам приходится манипулировать приоритетами задач с возможным изменением поведения потоков в системе, а затем проводить повторное тестирование и уточнять собственные модификации. На это нередко требуется несколько рабочих недель, что приводит к увеличению затрат и задержке выпуска продукта. К сожалению, лишь немногие разработчики и проектировщики могут диагностировать и решать такие проблемы на системном уровне.
Усугубляет ситуацию то обстоятельство, что многие современные встраиваемые системы являются динамическими устройствами, работающими в сети, которые могут (или должны) поддерживать новые функциональные возможности программного обеспечения на протяжении всего срока службы. Подобная гибкость дает многочисленные преимущества, но и влечет за собой множество проблем в ходе проектирования. К примеру, каким образом устройство может загружать и запускать новые программные компоненты, не согласовываясь с режимом работы и выполнением в реальном времени существующих компонентов? И как устройство может безопасно выполнить эти обновления во время объединения в операционной системе, поддерживая постоянную доступность и высокий уровень надежности? В таких случаях редко удается осуществить добавление новых аппаратных средств или вычислительных мощностей, чтобы обеспечить работу новых компонентов. Следовательно, системные разработчики должны применять технологии, гарантирующие, что каждый программный компонент — как и старый, так и новый — всегда получить иметь доступ к требуемым вычислительным ресурсам.
Рис. 1. Приоритетное планирование гарантирует, что наиболее важные задачи обязательно получат доступ к ресурсам процессора, но также может быть причиной проблем в том случае, когда высокоприоритетная задача неумышленно или намеренно потребляет все доступные циклы процессора. Например, задача А препятствует всем другим задачам в получении доступа к процессору (4-я единица времени) |
До настоящего времени в операционных системах применялось многопоточное и приоритетное планирование для осуществления контроля за тем, какие задачи используют процессорные циклы (рис. 1). Системные разработчики могут назначить приоритет каждому потоку и затем планировать их выполнение, взяв на вооружение определенную стратегию, например циклический алгоритм (round-robin) или правило «первым прибыл — первым обслужен» (FIFO). Приоритеты определяют, какую очередь готовых потоков выполнить первой, а стратегия планирования предписывает, как потоки с равными приоритетами будут совместно использовать процессор.
Приоритетное планирование обеспечивает удобный метод определения приоритета планирования для каждой задачи, однако, создает и проблему — если приоритет какой-либо задачи хотя бы на один уровень выше, чем у другой, то задача с более высоким приоритетом может полностью лишить процессорного времени менее важную задачу. Если у процесса А (рис. 1) появляется чрезвычайно большое количество заданий или он становится объектом отказа в обслуживании, то он заблокирует доступ к ресурсам процессу B и любому другому процессу с более низким приоритетом.
Подобная проблема возникает во всех областях, где используется встраиваемое программное обеспечение. В автомобиле процесс А может, например, отражать работу навигационного дисплея, а процесс B — mp3-плейера; если система навигации потребляет слишком много процессорных циклов при вычислении маршрута, то она может лишить mp3-плейер ресурсов, заставив его «прыгать». При работе в сети процесс А может быть протоколом TCP/IP и маршрутизации, а процесс B — агентом протокола SNMP. В системе управления производством процесс А может быть контуром управления манипулятора робота, а процесс B — человеко-машинным интерфейсом.
Сервисы, обеспечиваемые потоками с более низким приоритетом, включая диагностические сервисы, которые защищают систему от программных ошибок или отказов в обслуживании, могут быть лишены процессорных циклов на неограниченные периоды времени, подвергая тем самым риску работоспособность системы. Независимо от того, для какого рынка предназначена встроенная система, недостаток ресурсов у задачи или процесса представляет серьезную проблему. Чтобы ее решить, некоторые операционные системы реального времени, например LynxOS, производят фиксированное выделение процессорных ресурсов группам потоков согласно стандарту ARINC-653*. Системный разработчик может делить задачи (потоки) на группы (разделы), и назначать процент процессорного времени для каждой группы (рис. 2). При таком подходе никакая задача в какой-либо группе не сможет потреблять больше статически определенного для этой группы процента процессорного времени. К примеру, пусть группе назначено 30% ресурсов процессора; тогда, если процесс в этой группе впоследствии станет объектом отказа в обслуживании, он гарантировано сможет использовать не более 30% процессорного времени.
Рис. 2. Фиксированное выделение процессорных ресурсов препятствует потреблению всех циклов процессора заданием с высоким приоритетом (например, заданием A), однако оно может также привести к снижению производительности, растрачивая неиспользованные циклы процессора в данной группе (например, в группе 3) |
Поскольку алгоритм планирования является фиксированным, группа ни при каких обстоятельствах не сможет использовать процессорные циклы, назначенные другим группам, даже если они не задействуют выделенные им ресурсы. В результате снижается общая производительность системы.
Подход, именуемый адаптивной декомпозицией (Adaptive Partitioning, AP), устраняет эти недостатки, предлагая более динамический алгоритм планирования. АР представляет собой расширение операционной системы реального времени на уровне ядра с целью создания безопасных групп из нескольких приложений и потоков и при этом максимально эффективного использования ресурсов процессора. Подобно статическому объединению, адаптивная декомпозиция дает возможность системному разработчику резервировать циклы процессора для процесса или группы процессов. Разработчик может, таким образом, гарантировать, что нагрузка на одну подсистему или группу не будет влиять на доступность других.
В отличие от статических методов, при неполной загрузке процессора планирование выполнения потоков на процессоре не отличается от обычного планирования выполнения потоков в операционной системе реального времени — на процессор ставится готовый к исполнению поток, имеющий максимальный приоритет. В результате потоки в одной группе могут иметь доступ к любым свободным циклам процессора, которые не используются потоками в любой другой группе (рис. 3).
Рис. 3. Адаптивная декомпозиция не допускает, чтобы высокоприоритетные задачи потребляли больше ресурсов процессора, чем им назначено, кроме тех случаев, когда неиспользуемые циклы процессора становятся доступными в системе. Например, задачи A и D могут выполняться во время, назначенное группе 3, поскольку задачам E и F не требуется оставшаяся часть назначенных им циклов процессора. При использовании фиксированного выделения ресурсов это свободное время было бы потеряно |
При полной загрузке процессора система адаптивной декомпозиции строго ограничивает выделение процессорного времени группам потоков на основе установленных бюджетов для каждой группы. Группе потоков выделяется гарантированное процессорное время в рамках бюджета, которое они могут использовать. Внутри каждой группы потоки конкурируют за процессорное время на основе установленных для каждого потока приоритетов, что позволяет разработчикам оптимизировать назначение приоритетов потокам не для всей системы в целом, а только в пределах группы. Применение технологии адаптивной декомпозиции не требует изменения кода приложений реального времени и изменения модели программирования или методов отладки, с которыми уже знакомы разработчики.
Адаптивная декомпозиция, которая была впервые применена в ОС QNX Neutrino, предоставляет разработчикам встраиваемых систем следующие возможности:
- гарантированное выделение процессорного времени, когда система сильно загружена;
- приоритетное планирование реального времени, когда система не сильно загружена, что позволяет работать в текущем режиме планирования;
- использование свободного процессорного времени, предназначенного группам, которые оказались не полностью загруженными; это позволяет предоставить другим группам дополнительное процессорное время, необходимое им для работы при максимальной загрузке, и тем самым использовать процессор на 100%;
- совмещение планировщика адаптивной декомпозиции с действующими системами без изменений кода, в результате чего приложения и системные службы можно просто запустить в группе; планировщик будет гарантировать, что группы получат назначенные им ресурсы;
- динамическое добавление и конфигурирование группы в процессе выполнения, что позволяет системе регулировать потребление ресурсов процессора в ответ на сбои;
- гарантированное выделение операции по восстановлению циклов процессора, требуемых для исправления системных ошибок; это позволяет сократить среднее время исправления, что особенно важно в системах с высокой доступностью;
- прерывание выполнения кода, имеющего целью захватить все процессорное время, путем отказа ему в обслуживании.
Адаптивная декомпозиция ресурсов позволяет создавать безопасные группы из нескольких приложений и потоков.
В том случае если не созданы группы из нескольких приложений и потоков, аварийные приложения могут лишить базовые приложения необходимых процессорных ресурсов. К примеру, дефекты кода приложения могут случайно стать причиной возникновения таких условий выполнения, которые приведут к останову всей системы. Распределенные DoS-атаки также могут нагрузить систему задачами сетевой обработки, лишив базовые приложения процессорных ресурсов. Адаптивная декомпозиция ресурсов позволяет ограничить данные угрозы и защитить базовые приложения и службы. Аварийные компоненты системы изолируются: они не смогут использовать больше процессорного времени, чем установлено бюджетом. Все это позволяет системе сохранить работоспособность при любых обстоятельствах.
Использовать механизм адаптивной декомпозиции достаточно просто. При старте системы автоматически создается группа System с бюджетом процессорного времени 100%, и в ней запускаются все процессы. В любой момент времени можно создавать другие группы и назначать им бюджеты.
Следующий пример иллюстрирует, как работает метод адаптивной декомпозиции ресурсов. Сначала запустим в системе три приложения без адаптивной декомпозиции ресурсов: APSMonitor — монитор системных ресурсов; Car — критичный процесс, вычисляющий скорость движения машины (если приложению не хватает системных ресурсов, то скорость вычислений падает, что отражается на скорости движения автомобиля); Go-Slow — некритичный процесс, требующий значительных системных ресурсов, используемый для создания нагрузки на систему. Как видно из рис. 4, при работе критичного приложения оказываются занятыми все процессорные ресурсы.
Рис. 4. Критичное приложение занимает 100% ресурсов, работая в одиночку |
Машина движется со скоростью 83 км/ч. Теперь увеличим нагрузку на систему, используя приложение Go-Slow. Все процессорные ресурсы заняты, и критичному приложению не хватает процессорных ресурсов, в результате чего скорость машины снизилась до 19 км/ч.
Теперь запустим те же приложения с адаптивной декомпозицией ресурсов. Создадим в системе три группы процессов: System с бюджетом 20% процессорного времени, Critical и Untrusted с бюджетом 40% процессорного времени каждый. Приложение Go-Slow запустим в группе Untrusted, критичное приложение Car запустим в группе Critical, а все остальные процессы и потоки будут работать в группе System. В результате приложение Go-Slow не использует процессорные ресурсы, а свободные ресурсы делятся между остальными двумя группами процессов, при этом процессор загружен на 100%. Если увеличить нагрузку на систему с помощью приложения Go-Slow, то, поскольку адаптивная декомпозиция гарантирует выделение процессорного времени группе приложений, приложению Go-Slow будут выделены ресурсы процессора в соответствии с установленным бюджетом. В связи с возросшей нагрузкой на систему и отсутствием свободных процессорных ресурсов, все группы приложений получают процессорные ресурсы согласно установленным бюджетам (рис. 5). Критичное приложение Car стало работать медленнее (скорость движения автомобиля упала), но все же оно работает и гарантированно получает выделенные ему ресурсы.
Рис. 5. При работе некритичному процессу Go-Slow выделяется установленное количество ресурсов |
Из примера видно, что адаптивная декомпозиция позволяет разработчикам встраиваемых систем создавать безопасные группы из нескольких приложений или потоков и гарантирует эффективное выделение процессорного времени тем группам, которым оно требуется. Если на этапе проектирования при назначении приоритетов потокам были допущены ошибки, то применение технологии адаптивной декомпозиции позволяет их исправить на этапе конфигурирования системы без необходимости перекомпиляции.
Адаптивная декомпозиция — первый пример подхода к декомпозиции ресурсов, совместимого с моделью планирования стандарта POSIX. Благодаря этому существующие системы на базе POSIX смогут воспользоваться адаптивной декомпозицией без внесения изменений в код и архитектуру приложения.
Роман Коньшин (r.konshin@swd.ru)— преподаватель учебного центра компании SWD Software (Санкт-Петербург).
* Стандарт ARINC-653 (Avionics Application Software Standard Interface) разработан компанией ARINC в 1997 году. Определяет универсальный программный интерфейс APEX (Application/Executive) между операционной системой авиационного компьютера и прикладным программным обеспечением. Требования к интерфейсу между приложениями и сервисами операционной системы определяются таким образом, чтобы разрешить приложениям контролировать диспетчеризацию, связь и состояние внутренних обрабатываемых элементов. В 2003 году принята новая редакция этого стандарта. ARINC-653 в качестве одного из основных требований для ОСРВ в авиации вводит архитектуру изолированных виртуальных машин.