Тысячи людей работали над проектированием, сборкой и тестированием оборудования для миссии НАСА Curiosity, причем речь идет не только о самом марсоходе и его научных инструментах, но и о маршевой ступени, которая привела Curiosity на Марс, а также о сложнейшей спускаемой ступени, аккуратно посадившей аппарат на поверхность планеты 5 августа 2012 года. Все это оборудование, кропотливо разрабатывавшееся и многократно протестированное, управляется программным обеспечением, написанным командой из 35 человек в Лаборатории реактивного движения НАСА. Понятно, что управляющее ПО критически важно для успеха миссии — любой сбой способен привести к потере космического аппарата и к разгромным заголовкам в СМИ всего мира.

Управляющее бортовое ПО марсохода состоит примерно из 3 млн строк кода (Million Lines Of Code, MLOC). Основная его часть написана на языке Си, а небольшая доля (преимущественно код, отвечающий за навигацию на поверхности) — на C++. Код исполняется на защищенном от радиации микропроцессоре RAD750, представляющем собой чип IBM PowerPC 750, доработанный для применения в космосе. Процессор работает с тактовой частотой 133 МГц. Компьютер имеет 4 Гбайт флэш-памяти и 128 Мбайт оперативной. Примерно на 75% код сгенерирован автоматически системами, получающими на входе описания работы конечных автоматов, и из XML-файлов. Остальное писалось вручную, во многом на основе кода, разработанного для предыдущих миссий на Марс.

Curiosity — уже седьмой космический аппарат, который в НАСА посадили на Марс. А до этого были два посадочных модуля Viking (1976 год); малый марсоход Pathfinder (1996 год); два исследовательских марсохода Opportunity и Spirit (2004 год); посадочный модуль Phoenix, стартовавший в 2007 году и созданный на базе конструкции модуля Mars Surveyor 2001 года, миссия которого провалилась. Каждая новая миссия усложнялась и требовала больше управляющего ПО, чем предыдущая. При этом, как и во многих других отраслях, объем кода здесь растет экспоненциально — в каждой новой миссии на Марс применяется больше управляющего ПО, чем во всех предыдущих вместе взятых:

  • код бортового ПО посадочных модулей Viking занимал около 5 тыс. строк;
  • для Pathfinder — 150 тыс. строк;
  • Phoenix — 300 тыс. строк;
  • Opportunity и Spirit — по 650 тыс. строк;
  • Mars Science Laboratory — 3 MLOC.

 

Среднегодовой темп роста объема кода ПО для марсианских миссий

Комплексный годовой коэффициент роста объема ПО для космических аппаратов за последние 36 лет составлял примерно 1,2, что близко к среднему значению для критически важных программных систем, составляющему 1,16. В числе таких систем железнодорожная система Токио, система управления полетом от компании Honeywell и бортовое ПО Airbus. Но отличие Mars Science Laboratory в том, что код должен надежно работать на расстоянии в миллионы километров от Земли — его невозможно исправлять и сопровождать обычным образом.

 

Рис. А. Объем кода, управляющего посадкой космических аппаратов на Марс
Рис. А. Объем кода, управляющего посадкой космических аппаратов на Марс

 

 

Очевидно, что не существует какого-то одного «волшебного» инструмента или метода, позволяющего обеспечить надежность любого крупного и сложного приложения, — для создания такого ПО требуются качественные инструменты, высокая квалификация программистов и тщательно контролируемый процесс разработки. Три ключевых момента процесса создания надежного ПО: предотвращение, распознавание и сдерживание.

Предотвращение

Лучший способ создать надежное ПО — раннее предотвращение появления дефектов. Авторы марсианской системы попытались сделать это несколькими способами.

Во-первых, для миссии был взят на вооружение новый строгий стандарт кодирования, позднее принятый в качестве стандарта разработки всего ПО в Лаборатории реактивного движения НАСА Калифорнийского института технологий (Jet Propulsion Laboratory, JPL). Многие проекты разработки ПО опираются на подобные стандарты, но данный не совсем обычен — его правила были сформулированы на основе анализа всех промахов и ошибок предыдущих космических миссий. При создании стандарта были классифицированы проблемы, которые можно было отнести на счет ПО, и составлен сжатый набор правил, строгое следование которым позволит предотвратить появление ошибок такого класса. Затем были выбраны правила, выполнение которых можно проверить механически, например с помощью статического анализатора. Они и вошли в стандарт кодирования. Таким образом, предписания стандарта нельзя проигнорировать (как нередко поступают с другими стандартами) — для каждой очередной сборки ПО соответствие стандарту проверялось автоматически, все отклонения регистрировались и становились исходными данными для последующего процесса ревизии кода.

Во-вторых, для разработчиков был подготовлен курс сертификации, в числе прочего делавший акцент на программных рисках и методах защитного (defensive) программирования. Чтобы получить право участвовать в создании полетного ПО, каждый разработчик должен был пройти этот курс и сдать экзамен. В рамках курса разъяснялись принятый стандарт кодирования, а также общие принципы программирования и базовая структура управляющего ПО космического аппарата. Частично тот же материал преподавался старшему руководству JPL (но без экзамена), чтобы создать общую базу знаний по проблемам разработки критически важного ПО.

Распознавание

Следующая важнейшая тактика предотвращения дефектов — их распознавание на как можно более раннем этапе цикла разработки. Для этого в JPL воспользовались группой самых современных статических анализаторов кода и проводили ревизии кода с помощью автоматических инструментов.

Коллегиальная ревизия кода, состоящего из миллионов строк, сопряжена с определенными сложностями. Поэтому в JPL решили перенести значительную часть рутинных проверок (например, на соответствие стандарту, распространенные виды ошибок кодирования и рискованные приемы) на автоматизированные инструменты. Полная сборка полетного ПО Mars Science Laboratory с параллельным выполнением всех проверок выполнялась каждую ночь. Совместно с четырьмя разными статистическими анализаторами применялось около сотни вспомогательных скриптов, проверявших выполнение требований, которые сложно запрограммировать в анализаторах (например, запрет использования табуляции для форматирования кода и соблюдение правил выбора заголовков файлов).

В работе использовались статические анализаторы Coverity, Codenosar, Uno, а ближе к концу разработки появился Semmle. У каждого из них есть свои сильные стороны, и каждый находит разные недостатки кода, причем результаты их работы на удивление почти не перекрываются. Результаты еженощного анализа сводились в единый отчет с помощью инструмента Scrub, который добавлял в отчет все комментарии, полученные для каждого модуля в процессе ревизии кода. Отличительной чертой процесса ревизии было то, что участники проверяли код независимо друг от друга, а не на совещаниях. От владельца модуля требовалось ответить на все отчеты (созданные автоматически или людьми) простым «согласен», «не согласен» или «обсудить». Первое означало, что владелец признает обнаруженную ошибку и согласен на изменение кода. Второе — он убежден, что код верный и менять его не нужно. Третье — отчет неоднозначен и нужна дополнительная информация, чтобы решить, требуются ли исправления.

После независимых проверок для каждого модуля проводилось единственное очное совещание с участием всех проверявших, владельца модуля и руководителя проекта для обсуждения разногласий. Всего для миссии Mars Science Laboratory было проведено около 200 сеансов ревизии кода, и примерно 80% всех комментариев и автоматически созданных отчетов получили согласие от владельца модуля. По остальным 20% проводились обсуждения, после которых принималось окончательное решение о внесении изменений (в некоторых случаях вопреки несогласию владельца модуля) или сохранении кода в прежнем виде (см. рис.). В целом таким образом было проработано около 10 тыс. комментариев и примерно 25 тыс. автоматически сгенерированных отчетов. Как можно видеть, подавляющее большинство комментариев и отчетов привели к изменению кода.

 

Доля комментариев, которые привели к исправлениям после ревизий кода Mars Science Laboratory, проводившихся в период с 2008 по 2012 год. По приоритетности исправлений можно видеть, что все комментарии рассматривались одинаково серьезно. Результатом большинства комментариев стали модификации кода
Доля комментариев, которые привели к исправлениям после ревизий кода Mars Science Laboratory, проводившихся в период с 2008 по 2012 год. По приоритетности исправлений можно видеть, что все комментарии рассматривались одинаково серьезно. Результатом большинства комментариев стали модификации кода

 

Был добавлен еще один уровень проверки — с помощью системы верификации корректности программной модели (spinroot.com) исследовались ключевые элементы многопоточного кода на появление возможных состояний «гонки» и взаимоблокировки. Таким способом были проанализированы пять важнейших подсистем проекта. В одном из случаев на основании результатов пришлось полностью переработать структуру подсистемы.

Помимо статического анализа, коллективной ревизии кода и верификации модели, каждый программный модуль проходил тщательное модульное и интеграционное тестирование на настольном компьютере с программной имитацией контролируемого оборудования и на испытательном стенде с реальной аппаратурой. Требование к модульным тестам было обычным для приложений такого рода — обеспечить полное покрытие кода. Выполнить это было не всегда просто, особенно учитывая использование методов безопасного программирования, требующих предусматривать все возможные ситуации (штатные и нештатные) для защиты от последствий непредвиденных ошибок. Однако может оказаться, что защитный код при обычном тестировании никогда не будет выполняться, что означает нарушение правила запрета сохранения в системе такого кода. Решение — разработка специальных тестов-«демонов», способных вызвать запуск защитного кода для выявления условий, при которых он выполнится.

Сдерживание

Последний уровень защиты программной системы более структурирован по своей природе — это механизм, ограждающий от дефектов, которые не были обнаружены при проверках. Он предотвращает распространение их влияния за пределы модуля-источника и исключает сбой системы в целом. Один из способов достичь этого — дублирование. Принцип дублирования оборудования общеизвестен и относительно прост в реализации — например, на космический аппарат можно установить дополнительный набор двигателей или второй приемопередатчик. Этот метод опирается на предположение, что аппаратные сбои в дубликатах оборудования чаще всего не будут происходить одновременно. Однако в случае программного обеспечения этому принципу следовать труднее — выполнение одного и того же кода на нескольких экземплярах процессора не защитит от программных сбоев.

Принцип сдерживания особенно широко применялся в программах управления посадкой, которые в НАСА называют «семью минутами ужаса». Большинство критически важных узлов космического аппарата было для надежности продублировано, в том числе центральный процессор и подсистема памяти. Резервный процессор должен брать на себя управление космическим аппаратом в случае сбоя основного. Но если сбой вызван программным обеспечением, запуск на исполнение точно такого же кода на другом процессоре не поможет. Поэтому в процессе посадки резервный процессор исполняет упрощенную версию посадочного ПО, называемую «второй шанс» (или «последний шанс»). Как теперь известно, основной процессор безупречно справился с задачей посадки на Марс и «второй шанс» не понадобился, а в целом существенных аномалий в полетном программном обеспечении Mars Science Laboratory выявлено не было.

Джерард Хольцманн (gholzmann@acm.org) — старший научный сотрудник Лаборатории реактивного движения НАСА.

Gerard J. Holzmann, Landing a Spacecraft on Mars, IEEE Software, March/April 2013, IEEE Computer Society. All rights reserved. Reprinted with permission.