Составление приложения для использования в высокорадиоактивных средах


1456

Мы компилируем встроенное приложение C / C ++, которое развертывается в экранированном устройстве в среде, засыпанной ионизирующим излучением . Мы используем GCC и кросс-компиляцию для ARM. При развертывании наше приложение генерирует некоторые ошибочные данные и вылетает чаще, чем хотелось бы. Аппаратное обеспечение разработано для этой среды, и наше приложение работает на этой платформе в течение нескольких лет.

Есть ли какие-либо изменения, которые мы можем внести в наш код, или улучшения во время компиляции, которые могут быть сделаны для выявления / исправления программных ошибок и повреждения памяти, вызванного сбоями одного события ? Удалось ли другим разработчикам снизить вредное воздействие программных ошибок на долго работающее приложение?


186
Изменяются ли значения в памяти или значения в процессоре? Если оборудование предназначено для среды, программное обеспечение должно работать так, как будто оно работает в нерадиоактивной среде.
Томас Мэтьюз

3
Если возможно, вы должны настроить систему регистрации, которая хранит события в энергонезависимой памяти, устойчивой к излучению. Храните достаточно информации, чтобы вы могли отследить событие и легко найти основную причину.
Томас Мэтьюз

2
@Thomas Matthews Вся память имеет частоту ошибок FIT, и производители оборудования обещают много. Большинство проблем, вероятно, вызвано тем, что SEU изменяют оперативную память во время выполнения.
Ладья

9
Это комбинированное аппаратно-программное решение, но я знаю, что Texas Instruments (и, возможно, другие) делает встраиваемые микросхемы для критически важных приложений, которые состоят из двух дублирующих ядер, работающих в режиме ожидания, на пол такта не в фазе. Существуют специальные прерывания и действия по сбросу, которые выполняются, когда оборудование обнаруживает что-то другое между ядрами, поэтому вы можете восстанавливаться после ошибок. Я верю, что TI маркирует их как процессоры безопасности Hercules.
mbrig

5
Избыточные прочные моторы, некоторые шестерни, валы и трещотки! Заменяйте ежегодно или чаще, если требуется мощность дозы. Нет, на самом деле, мой первый вопрос с такими проблемами всегда был, действительно ли вам нужно столько программного обеспечения? Будьте настолько похожими, насколько это возможно.
Jwdonahue

Ответы:


814

Работая около 4-5 лет над разработкой программного обеспечения / прошивки и тестированием среды миниатюрных спутников *, я хотел бы поделиться своим опытом здесь.

* ( миниатюрные спутники намного более склонны к одиночным событиям, чем большие спутники из-за его относительно небольших, ограниченных размеров для его электронных компонентов )

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

Теперь эта ситуация обычно обрабатывается как на аппаратном, так и на программном уровне. Здесь, по вашей просьбе, я поделюсь тем, что мы можем сделать на уровне программного обеспечения.

  1. ... восстановление ... цель . Предоставьте возможность обновлять / перекомпилировать / перепрошивать ваше программное обеспечение / прошивку в реальных условиях. Это почти обязательная функция для любого программного обеспечения / прошивки в сильно ионизированной среде. Без этого вы могли бы иметь избыточное программное / аппаратное обеспечение столько, сколько захотите, но в один прекрасный момент все они взорвутся. Итак, подготовьте эту функцию!

  2. ... минимальная рабочая версия ... Имейте отзывчивые, множественные копии, минимальную версию программного обеспечения / прошивки в вашем коде. Это похоже на безопасный режим в Windows. Вместо того, чтобы иметь только одну полнофункциональную версию вашего программного обеспечения, имейте несколько копий минимальной версии вашего программного обеспечения / прошивки. Минимальная копия обычно имеет гораздо меньший размер, чем полная копия, и почти всегда имеет только следующие две или три функции:

    1. способен слушать команды из внешней системы,
    2. способен обновлять текущее программное обеспечение / прошивку,
    3. способный контролировать основные служебные данные операции.
  3. ... скопировать ... куда-нибудь ... иметь избыточное программное обеспечение / прошивку где-нибудь.

    1. Вы можете, с избыточным аппаратным обеспечением или без него, попытаться установить избыточное программное обеспечение / прошивку в вашем ARM uC. Обычно это делается с помощью двух или более идентичных программ / микропрограмм по разным адресам, которые посылают друг другу пульс, но одновременно будет активен только один. Если известно, что одно или несколько программ / микропрограмм не отвечают, переключитесь на другое программное обеспечение / микропрограммное обеспечение. Преимущество использования этого подхода заключается в том, что мы можем сразу заменить функциональную замену после возникновения ошибки - без какого-либо контакта с какой-либо внешней системой / стороной, ответственной за обнаружение и устранение ошибки (в случае спутника обычно это Центр управления полетом ( MCC)).

      Строго говоря, недостаток аппаратного обеспечения заключается в том, что вы фактически не можете устранить все отдельные точки сбоев. По крайней мере, у вас все еще будет одна единственная точка отказа, а именно сам коммутатор (или часто начало кода). Тем не менее, для устройства, ограниченного по размеру в сильно ионизованной среде (например, пико / фемтосателлиты), уменьшение единой точки отказа до одной точки без дополнительного оборудования все же стоит рассмотреть. Более того, кусок кода для переключения, безусловно, будет намного меньше, чем код для всей программы, что значительно снижает риск попадания в него одного события.

    2. Но если вы этого не делаете, у вас должна быть хотя бы одна копия во внешней системе, которая может войти в контакт с устройством и обновить программное обеспечение / прошивку (в случае спутника это снова центр управления полетами).

    3. Вы также можете иметь копию в вашей постоянной памяти на вашем устройстве, которая может быть запущена для восстановления программного обеспечения / прошивки работающей системы
  4. ... обнаруживаемая ошибочная ситуация. Ошибка должна быть обнаружена , обычно с помощью аппаратной схемы исправления ошибок / обнаружения или небольшого фрагмента кода для исправления ошибок / обнаружения. Лучше всего ставить такой код маленьким, множественным и независимым от основного программного обеспечения / прошивки. Его основная задача только для проверки / исправления. Если аппаратная схема / прошивка надежна(например, он более защищен от радиации, чем остальные - или имеет несколько схем / логических схем), тогда вы можете рассмотреть возможность исправления ошибок с его помощью. Но если это не так, лучше сделать это как обнаружение ошибок. Коррекция может осуществляться внешней системой / устройством. Для исправления ошибок вы могли бы рассмотреть возможность использования базового алгоритма исправления ошибок, такого как Hamming / Golay23, потому что они могут быть легче реализованы как в схеме / программном обеспечении. Но в конечном итоге это зависит от возможностей вашей команды. Для обнаружения ошибок обычно используется CRC.

  5. ... аппаратное обеспечение, поддерживающее восстановление. Теперь самое сложное в этом вопросе. В конечном счете, восстановление требует, чтобы оборудование, которое отвечает за восстановление, было как минимум функциональным. Если оборудование постоянно повреждено (обычно это происходит после того, как его общая ионизирующая доза достигает определенного уровня), то (к сожалению) у программного обеспечения нет возможности помочь в восстановлении. Таким образом, аппаратное обеспечение по праву является первостепенной задачей для устройства, подверженного высокому уровню излучения (такого как спутник).

В дополнение к предложению о вышеупомянутом ожидании ошибки прошивки из-за одного события, я также хотел бы предложить вам:

  1. Алгоритм обнаружения и / или исправления ошибок в межсистемном протоколе связи. Это еще одно, почти необходимо иметь, чтобы избежать неполных / неправильных сигналов, полученных от другой системы

  2. Фильтр в вашем чтении АЦП. Как не использовать АЦП для чтения непосредственно. Фильтруйте его по медианному фильтру, среднему фильтру или любым другим фильтрам - никогда не доверяйте единственному значению чтения. Образец больше, а не меньше - разумно.


401

У НАСА есть документ о радиационно-стойком программном обеспечении. Он описывает три основные задачи:

  1. Регулярный мониторинг памяти на наличие ошибок, а затем их устранение,
  2. надежные механизмы восстановления после ошибок и
  3. возможность перенастроить, если что-то больше не работает.

Обратите внимание, что частота сканирования памяти должна быть достаточно частой, чтобы редко возникали многобитовые ошибки, поскольку большая часть памяти ECC может восстанавливаться после однобитовых, а не многобитовых ошибок.

Надежное восстановление после ошибок включает передачу потока управления (как правило, перезапуск процесса в точке до возникновения ошибки), освобождение ресурса и восстановление данных.

Их основная рекомендация по восстановлению данных состоит в том, чтобы избежать необходимости в этом, поскольку промежуточные данные рассматриваются как временные, так что перезапуск до того, как ошибка также откатит данные до надежного состояния. Это звучит аналогично понятию «транзакции» в базах данных.

Они обсуждают методы, особенно подходящие для объектно-ориентированных языков, таких как C ++. Например

  1. Программные ECC для смежных объектов памяти
  2. Программирование по контракту : проверка предварительных условий и постусловий, затем проверка объекта, чтобы убедиться, что он все еще находится в действительном состоянии.

И так уж вышло, НАСА использовало C ++ для крупных проектов, таких как Mars Rover .

Абстракция и инкапсуляция класса C ++ обеспечили быструю разработку и тестирование среди множества проектов и разработчиков.

Они избегали определенных функций C ++, которые могут создавать проблемы:

  1. Исключения
  2. Шаблоны
  3. Iostream (без консоли)
  4. Множественное наследование
  5. Перегрузка оператора (кроме newи delete)
  6. Динамическое выделение (используется выделенный пул памяти и размещение, newчтобы избежать возможности повреждения кучи системы).

28
Это на самом деле звучит как то, что чистый язык был бы хорош в. Так как значения никогда не меняются, если они повреждены, вы можете просто вернуться к исходному определению (что и должно быть), и вы не будете случайно делать одно и то же дважды (из-за отсутствия побочных эффектов).
PyRulez

20
RAII - плохая идея, потому что вы не можете полагаться на то, что он работает правильно или вообще не работает. Это может привести к случайному повреждению ваших данных и т. Д. Вы действительно хотите получить как можно больше неизменности, а также механизмы исправления ошибок. Гораздо проще просто выбросить сломанные вещи, чем попытаться как-то их починить (как именно вы знаете достаточно, чтобы вернуться к правильному старому состоянию?). Возможно, вы захотите использовать довольно глупый язык для этого - оптимизация может повредить больше, чем помочь.
Луаан

67
@PyRulez: Чистые языки - это абстракция, аппаратные средства - не чистые. Компиляторы довольно хорошо скрывают разницу. Если ваша программа имеет значение, которое по логике больше не должно использоваться после шага X, компилятор может перезаписать его значением, которое рассчитывается на шаге X + 1. Но это значит, что ты не можешь вернуться. Более формально, возможные состояния программы на чистом языке образуют ациклический граф, что означает, что два состояния эквивалентны и могут быть объединены, когда состояния, достижимые из обоих, эквивалентны. Это слияние уничтожает разницу в путях, ведущих к этим состояниям.
MSalters

2
@Vorac - Согласно презентации, проблема с шаблонами C ++ связана с раздуванием кода.
jww

3
@DeerSpotter Точная проблема намного больше, чем это. Ионизация может повредить биты вашей работающей программы-наблюдателя. Тогда вам понадобится наблюдатель наблюдателя, затем - наблюдатель наблюдателя наблюдателя и так далее ...
Агниус Василяускас

116

Вот некоторые мысли и идеи:

Используйте ROM более творчески.

Храните все, что вы можете в ROM. Вместо того, чтобы вычислять вещи, храните таблицы поиска в ПЗУ. (Убедитесь, что ваш компилятор выводит таблицы поиска в раздел только для чтения! Распечатайте адреса памяти во время выполнения, чтобы проверить!) Сохраните таблицу векторов прерываний в ПЗУ. Конечно, запустите несколько тестов, чтобы увидеть, насколько надежна ваша ПЗУ по сравнению с вашей ОЗУ.

Используйте вашу лучшую оперативную память для стека.

SEU в стеке, вероятно, являются наиболее вероятным источником сбоев, потому что именно там обычно живут такие вещи, как индексные переменные, переменные состояния, адреса возврата и указатели различных типов.

Реализуйте процедуры таймера-тика и сторожевого таймера.

Вы можете запускать процедуру проверки работоспособности каждый тик таймера, а также подпрограмму сторожевого таймера для обработки блокировки системы. Ваш основной код также может периодически увеличивать счетчик, чтобы указывать прогресс, и процедура проверки работоспособности может гарантировать, что это произошло.

Реализуйте коды исправления ошибок в программном обеспечении.

Вы можете добавить избыточность к своим данным, чтобы иметь возможность обнаруживать и / или исправлять ошибки. Это добавит время обработки, потенциально оставляя процессор подверженным облучению в течение более длительного времени, увеличивая тем самым вероятность ошибок, поэтому вы должны учитывать компромисс.

Помните тайники.

Проверьте размеры кэшей вашего процессора. Данные, к которым вы недавно обращались или изменяли, вероятно, будут в кеше. Я полагаю, что вы можете отключить по крайней мере некоторые из кэшей (с большой производительностью); Вы должны попробовать это, чтобы увидеть, насколько кеши восприимчивы к SEU. Если кеши более устойчивы, чем ОЗУ, то вы можете регулярно читать и перезаписывать критически важные данные, чтобы убедиться, что они остаются в кеше и вернуть ОЗУ в рабочее состояние.

Умно используйте обработчики ошибок страниц.

Если вы отметите страницу памяти как отсутствующую, ЦП выдаст ошибку страницы при попытке доступа к ней. Вы можете создать обработчик ошибок страницы, который выполняет некоторую проверку перед обслуживанием запроса на чтение. (Операционные системы ПК используют это для прозрачной загрузки страниц, которые были выгружены на диск.)

Используйте язык ассемблера для критических вещей (которые могут быть всем).

С языком ассемблера вы знаете, что находится в регистрах, а что в оперативной памяти; Вы знаете, какие специальные таблицы ОЗУ использует ЦП, и можете разрабатывать обходные пути, чтобы снизить риск.

Используйте, objdumpчтобы реально посмотреть на сгенерированный ассемблер и выяснить, сколько кода занимает каждая ваша подпрограмма.

Если вы используете большую ОС, такую ​​как Linux, вы напрашиваетесь на неприятности; просто так много сложности и так много вещей, которые могут пойти не так.

Помните, что это игра вероятностей.

Комментатор сказал

Каждая подпрограмма, которую вы пишете для обнаружения ошибок, будет сама по себе приводить к отказу по той же причине.

Хотя это действительно так, вероятность ошибок в (скажем) 100 байтах кода и данных, необходимых для правильной работы процедуры проверки, намного меньше, чем вероятность ошибок в других местах. Если ваш ПЗУ достаточно надежен и почти весь код / ​​данные фактически находятся в ПЗУ, ваши шансы еще выше.

Используйте избыточное оборудование.

Используйте 2 или более идентичных аппаратных настроек с идентичным кодом. Если результаты отличаются, необходимо выполнить сброс. С 3 или более устройствами вы можете использовать систему «голосования», чтобы попытаться определить, какое из них было взломано.


14
В настоящее время есть ECC, доступный через аппаратное обеспечение, которое экономит время обработки. Первый шаг - выбрать микроконтроллер со встроенным ECC.
Лундин

23
Где-то в глубине моего сознания есть отсылка к аппаратному обеспечению авионики (возможно, космического челнока?), Где избыточная архитектура была явно разработана, чтобы не быть идентичной (и разными командами). Это уменьшает вероятность системной ошибки в конструкции аппаратного / программного обеспечения, уменьшая вероятность одновременного сбоя всех систем голосования при столкновении с одними и теми же входами.
Питер М

8
@PeterM: AFAIK, который также востребован для летного программного обеспечения для Boeing 777: три версии от трех команд на трех языках программирования.
Восстановить Монику - М. Шредер

7
@DanEsparza RAM обычно имеет конденсатор (DRAM) или несколько транзисторов с обратной связью (SRAM) для хранения данных. Событие излучения может спонтанно заряжать / разряжать конденсатор или изменять сигнал в контуре обратной связи. ПЗУ, как правило, не требует возможности записи (по крайней мере, без особых обстоятельств и / или более высоких напряжений) и, следовательно, может быть по своей природе более стабильным на физическом уровне.
нанофарад

7
@DanEsparza: существует несколько типов памяти ROM. Если «ПЗУ» эмулируется, например, eeprom или флэш-памятью «только для чтения при 5 В, но программируется при 10 В», то действительно, «ПЗУ» все еще подвержено ионизации. Может быть, просто меньше, чем другие. Тем не менее, есть хорошие старые хардкорные вещи, такие как Mask ROM или PROM на основе предохранителей, которые, я думаю, нуждаются в действительно серьезном количестве радиации, чтобы начать выходить из строя. Я не знаю, однако, если они все еще производятся.
Кецалькоатль

105

Вас также может заинтересовать обширная литература по теме алгоритмической отказоустойчивости. Это включает в себя старое назначение: написать сортировку, которая правильно сортирует свои входные данные, когда постоянное число сравнений не удастся (или, что более опасная версия, когда асимптотическое число неудачных сравнений масштабируется какlog(n) для nсравнений).

Место, где можно начать читать, - статья Хуанга и Авраама 1984 года " Отказоустойчивость на основе алгоритмов для матричных операций ». Их идея в некоторой степени похожа на гомоморфные зашифрованные вычисления (но на самом деле это не то же самое, поскольку они пытаются обнаружить / исправить ошибки на уровне операций).

Более поздний потомок этого документа - Босилька, Дельмас, Донгарра и Лангу, «Отказоустойчивость на основе алгоритмов, применяемая для высокопроизводительных вычислений ».


5
Мне очень нравится ваш ответ. Это более общий программный подход к целостности данных, и в нашем конечном продукте будет использовано решение по отказоустойчивости на основе алгоритмов. Спасибо!
Ладья

41

Написание кода для радиоактивных сред на самом деле ничем не отличается от написания кода для любого критически важного приложения.

В дополнение к тому, что уже упоминалось, вот несколько разных советов:

  • Используйте каждодневные меры безопасности "хлеб с маслом", которые должны присутствовать в любой полупрофессиональной встроенной системе: внутренний сторожевой таймер, внутренний детектор низкого напряжения, внутренний монитор часов. Эти вещи даже не нужно упоминать в 2016 году, и они стандартны практически для каждого современного микроконтроллера.
  • Если у вас есть безопасный и / или ориентированный на автомобили MCU, он будет иметь определенные функции сторожевого таймера, такие как заданное временное окно, внутри которого вам необходимо обновить сторожевой таймер. Это предпочтительно, если у вас есть критически важная система реального времени.
  • В общем, используйте MCU, подходящий для систем такого типа, а не какой-нибудь общий основной поток, который вы получили в пакете кукурузных хлопьев. В настоящее время почти каждый производитель MCU имеет специализированные MCU, разработанные для приложений безопасности (TI, Freescale, Renesas, ST, Infineon и т. Д.). Они имеют множество встроенных функций безопасности, в том числе ядра блокировки: это означает, что 2 ядра процессора выполняют один и тот же код, и они должны соглашаться друг с другом.
  • ВАЖНО: Вы должны обеспечить целостность внутренних регистров MCU. Все регистры управления и состояния аппаратных периферийных устройств, которые доступны для записи, могут находиться в оперативной памяти и поэтому уязвимы.

    Чтобы защитить себя от повреждений реестра, желательно выбрать микроконтроллер со встроенными функциями «однократной записи» регистров. Кроме того, вам нужно хранить значения по умолчанию всех аппаратных регистров в NVM и регулярно копировать эти значения в свои регистры. Вы можете обеспечить целостность важных переменных таким же образом.

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

  • Существуют всевозможные методы проверки ошибок в ОЗУ или NVM: контрольные суммы, «шаблоны ходьбы», программный ECC и т. Д. И т. Д. На сегодняшний день лучшим решением является не использование какого-либо из них, а использование MCU со встроенным ECC и аналогичные проверки. Поскольку делать это в программном обеспечении сложно, и проверка ошибок сама по себе может привести к ошибкам и неожиданным проблемам.

  • Используйте избыточность. Вы можете хранить как энергозависимую, так и энергонезависимую память в двух одинаковых «зеркальных» сегментах, которые всегда должны быть эквивалентными. К каждому сегменту может быть прикреплена контрольная сумма CRC.
  • Избегайте использования внешней памяти вне MCU.
  • Реализуйте стандартную процедуру обработки прерываний / обработчик исключений по умолчанию для всех возможных прерываний / исключений. Даже те, которые вы не используете. Процедура по умолчанию не должна делать ничего, кроме отключения собственного источника прерывания.
  • Понять и принять концепцию защитного программирования. Это означает, что ваша программа должна обрабатывать все возможные случаи, даже те, которые не могут возникнуть в теории. Примеры .

    Высококачественная критически важная прошивка обнаруживает как можно больше ошибок, а затем безопасно их игнорирует.

  • Никогда не пишите программы, которые полагаются на плохо определенное поведение. Вполне вероятно, что такое поведение может резко измениться с неожиданными аппаратными изменениями, вызванными излучением или электромагнитными помехами. Лучший способ гарантировать, что ваша программа свободна от такого дерьма, - это использовать стандарт кодирования, такой как MISRA, вместе с инструментом статического анализатора. Это также поможет с защитным программированием и устранением ошибок (почему бы вам не захотеть обнаруживать ошибки в каком-либо приложении?).
  • ВАЖНО: не используйте значения по умолчанию для статических переменных продолжительности хранения. То есть не доверяйте содержимому по умолчанию .dataили .bss. Между моментом инициализации и моментом, когда переменная фактически используется, может быть сколько угодно времени, могло быть достаточно времени для повреждения ОЗУ. Вместо этого напишите программу так, чтобы все такие переменные устанавливались из NVM во время выполнения, незадолго до того времени, когда такая переменная используется в первый раз.

    На практике это означает, что если переменная объявлена ​​в области видимости файла или как static, вы никогда не должны использовать ее =для инициализации (или вы могли бы, но это бессмысленно, потому что вы все равно не можете полагаться на значение). Всегда устанавливайте его во время выполнения, перед использованием. Если есть возможность многократно обновлять такие переменные из NVM, то сделайте это.

    Точно так же в C ++ не полагайтесь на конструкторы для статических переменных продолжительности хранения. Пусть конструктор (ы) вызовет общедоступную подпрограмму «set-up», которую вы также можете вызвать позже во время выполнения, прямо из приложения вызывающей стороны.

    Если возможно, удалите код запуска «copy-down», который полностью инициализирует .dataи .bss(и вызывает конструкторы C ++), чтобы вы могли получить ошибки компоновщика, если вы пишете код, полагаясь на него. Многие компиляторы имеют возможность пропустить это, обычно называемое «минимальный / быстрый запуск» или подобное.

    Это означает, что любые внешние библиотеки должны быть проверены, чтобы они не содержали такой зависимости.

  • Реализуйте и определите безопасное состояние для программы, куда вы будете возвращаться в случае критических ошибок.

  • Внедрение системы отчетов об ошибках / журнала ошибок всегда полезно.

Один из способов справиться с повреждением логических значений (как в вашем примере ссылки) - сделать TRUEравным, а 0xffffffffзатем использовать POPCNTс порогом.
wizzwizz4

@ wizzwizz4 Учитывая, что значение 0xff является значением по умолчанию для непрограммированной флэш-ячейки, это звучит как плохая идея.
Лундин

%01010101010101010101010101010101, XOR, тогда, POPCNT?
wizzwizz4

1
@ wizzwizz4 Или просто значение 0x1, как того требует стандарт C.
Лундин

1
@ wizzwizz4 Почему вы используете некоторые или все вышеупомянутые методы (ECC, CRC и т. д.). В противном случае космический луч может также перевернуть один бит в вашем .textразделе, изменив код операции или подобный.
Лундин

34

Может быть возможно использовать C для написания программ, которые ведут себя надежно в таких средах, но только если большинство форм оптимизации компилятора отключены. Оптимизирующие компиляторы предназначены для замены многих, казалось бы, избыточных шаблонов кодирования на «более эффективные», и могут не иметь ни малейшего представления о том, что причина, по которой программист тестирует, x==42когда компилятор знает, что нет другого способа xудержать что-либо еще, заключается в том, что программист хочет предотвратить выполнение определенного кода с сохранением xнекоторого другого значения - даже в тех случаях, когда единственным способом удержать это значение было бы, если бы система получала какой-то электрический сбой.

Объявление переменных, как volatileэто часто бывает полезно, но не может быть панацеей. Особо важно отметить, что безопасное кодирование часто требует, чтобы опасные операции имели аппаратные блокировки, для активации которых требуется несколько шагов, и чтобы код был написан с использованием шаблона:

... code that checks system state
if (system_state_favors_activation)
{
  prepare_for_activation();
  ... code that checks system state again
  if (system_state_is_valid)
  {
    if (system_state_favors_activation)
      trigger_activation();
  }
  else
    perform_safety_shutdown_and_restart();
}
cancel_preparations();

Если компилятор переводит код относительно буквально, и если после проверки повторяются все проверки состояния системы prepare_for_activation(), система может быть устойчивой практически к любому правдоподобному событию с одним единственным затруднением, даже к тем, которые могут произвольно повредить счетчик программ и стек. Если сбой происходит сразу после вызова prepare_for_activation(), это будет означать, что активация была бы уместной (так как prepare_for_activation()до сбоя не было вызвано никакой другой причины ). Если сбой приводит к prepare_for_activation()неправильному доступу к коду , но при этом нет последующих событий сбоя, у кода не будет возможности достичь его, trigger_activation()не пройдя проверку проверки или сначала не вызвав cancel_preparations [если стек выпадает, выполнение может продолжаться как раз передtrigger_activation()после того, как контекст, который вызвал, prepare_for_activation()возвращается, но вызов к cancel_preparations()произошел бы между вызовами к , таким образом делая последний вызов безопасным.prepare_for_activation() иtrigger_activation()

Такой код может быть безопасным в традиционном Си, но не с современными компиляторами Си. Такие компиляторы могут быть очень опасными в такой среде, потому что агрессивно они стремятся включать только код, который будет уместен в ситуациях, которые могут возникнуть через какой-то четко определенный механизм, и чьи последствия будут также хорошо определены. Код, целью которого будет обнаружение и очистка после сбоев, в некоторых случаях может ухудшить ситуацию. Если компилятор определяет, что попытка восстановления в некоторых случаях вызовет неопределенное поведение, это может означать, что условия, которые могут потребовать такого восстановления в таких случаях, не могут возникнуть, таким образом устраняя код, который бы проверял их.


6
Реально говоря, сколько современных компиляторов, которые не предлагают -O0или эквивалентный переключатель? GCC будет делать много странных вещей, если вы дадите ему разрешение , но если вы попросите его не делать этого, он, как правило, тоже может быть довольно буквальным.
Леушенко

24
Извините, но эта идея принципиально опасна. Отключение оптимизации приводит к более медленной программе. Или, другими словами, вам нужен более быстрый процессор. Как оказалось, более быстрые процессоры быстрее, потому что заряды на их затворах меньше. Это делает их гораздо более восприимчивыми к радиации. Лучшая стратегия состоит в том, чтобы использовать медленный, большой чип, где один фотон с гораздо меньшей вероятностью может опрокинуться немного и вернуть скорость с помощью -O2.
MSalters

27
Вторичная причина -O0плохой идеи заключается в том, что она издает гораздо более бесполезные инструкции. Пример: не встроенный вызов содержит инструкции по сохранению регистров, выполнению вызова, восстановлению регистров. Все это может потерпеть неудачу. Инструкция, которой нет, не может потерпеть неудачу.
MSalters

15
Еще одна причина, почему -O0это плохая идея: она склонна хранить переменные в памяти, а не в регистре. Теперь нет уверенности, что память более восприимчива к SEU, но данные в полете более восприимчивы, чем данные в покое. Бесполезного перемещения данных следует избегать, и это -O2помогает.
MSalters

9
@MSalters: Важно не то, чтобы данные были защищены от сбоев, а то, чтобы система могла обрабатывать сбои в соответствии с требованиями. На многих компиляторах отключение всех оптимизаций приводит к коду, который выполняет чрезмерное количество перемещений между регистрами, что является плохим, но хранение переменных в памяти безопаснее с точки зрения восстановления, чем хранение их в регистрах. Если в памяти есть две переменные, которые должны подчиняться какому-либо условию (например, v1=v2+0xCAFEBABEи все обновления двух переменных сделаны ...
суперкат

29

Это чрезвычайно широкий предмет. По сути, вы не можете действительно восстановиться после повреждения памяти, но вы можете, по крайней мере, попытаться быстро потерпеть неудачу . Вот несколько методов, которые вы могли бы использовать:

  • постоянные данные контрольной суммы . Если у вас есть какие-либо данные конфигурации, которые остаются постоянными в течение длительного времени (включая настроенные вами аппаратные регистры), вычислите его контрольную сумму при инициализации и проверяйте ее периодически. Когда вы видите несоответствие, пришло время для повторной инициализации или сброса.

  • хранить переменные с избыточностью . Если у вас есть важная переменная x, написать свое значение в x1, x2и x3и читать его как (x1 == x2) ? x2 : x3.

  • реализовать мониторинг потока программ . XOR - глобальный флаг с уникальным значением в важных функциях / ветвях, вызываемых из основного цикла. Запуск программы в среде без излучения с почти 100% тестовым покрытием должен дать вам список допустимых значений флага в конце цикла. Сброс, если вы видите отклонения.

  • контролировать указатель стека . В начале основного цикла сравните указатель стека с его ожидаемым значением. Сброс на отклонение.


27

Что может вам помочь, так это сторожевой пес . В 1980-х годах сторожевые устройства широко использовались в промышленных вычислениях. Аппаратные сбои были гораздо более распространенными, чем другой - другой ответ также относится к этому периоду.

Сторожевой таймер - это комбинированная аппаратная / программная функция. Аппаратное обеспечение представляет собой простой счетчик, который отсчитывает от числа (скажем, 1023) до нуля. TTL или другая логика может быть использована.

Программное обеспечение было разработано таким образом, чтобы одна программа контролировала правильную работу всех основных систем. Если эта процедура завершается правильно = обнаруживает, что компьютер работает нормально, для счетчика возвращается значение 1023.

Общая конструкция такова, что в нормальных условиях программное обеспечение предотвращает достижение аппаратным счетчиком нуля. Если счетчик достигает нуля, аппаратная часть счетчика выполняет свою единственную задачу и сбрасывает всю систему. С точки зрения счетчика ноль равен 1024, и счетчик продолжает обратный отсчет.

Этот сторожевой таймер обеспечивает перезагрузку подключенного компьютера во многих случаях сбоя. Должен признать, что я не знаком с оборудованием, способным выполнять такую ​​функцию на современных компьютерах. Интерфейсы к внешнему оборудованию теперь намного сложнее, чем раньше.

Недостатком сторожевого таймера является то, что система недоступна с момента сбоя, пока счетчик сторожевого таймера не достигнет нуля + время перезагрузки. Хотя это время обычно намного короче, чем любое внешнее или человеческое вмешательство, поддерживаемое оборудование должно быть в состоянии работать без компьютерного контроля в течение этого периода.


9
Бинарные счетчики со стандартными микросхемами TTL - это действительно решение 1980-х годов. Не делай этого. Сегодня на рынке не существует ни одного MCU без встроенной схемы сторожевого таймера. Все, что вам нужно проверить, - это если встроенный сторожевой таймер имеет отдельный источник синхронизации (хорошо, скорее всего, так) или он наследует свои часы от системных часов (плохо).
Лундин

1
nos

2
Кстати, до сих пор широко используется во встроенных процессорах.
Грэхем

5
@Peter Mortensen Пожалуйста, прекратите редактировать каждый ответ на этот вопрос. Это не Википедия, и эти ссылки бесполезны (и я уверен, что все знают, как найти Википедию в любом случае ...). Многие из ваших правок неверны, потому что вы не знаете тему. Я делаю откаты на ваши неправильные правки, когда сталкиваюсь с ними. Вы не поворачиваете эту нить лучше, но хуже. Прекратите редактирование.
Лундин

У Джека Гансле есть хорошая статья о сторожевых собаках
Игорь Скочинский,

23

В этом ответе предполагается, что вы заинтересованы в том, чтобы система работала корректно, помимо системы с минимальной стоимостью или высокой скоростью; большинство людей, играющих с радиоактивными вещами, ценят правильность / безопасность, а не скорость / стоимость.

Несколько человек предложили внести изменения в аппаратные средства, которые вы можете внести (хорошо - здесь уже есть много полезного в ответах, и я не собираюсь повторять все это), а другие предложили избыточность (в принципе здорово), но я не думаю, что кто-нибудь предположил, как эта избыточность может работать на практике. Как вы терпите неудачу? Как вы знаете, когда что-то «пошло не так»? Многие технологии работают на основе того, что все будет работать, и поэтому неудача - это сложная задача. Тем не менее, некоторые распределенные вычислительные технологии , предназначенные для масштабирования ожидать сбоя (в конце концов, при достаточном масштабе сбой одного узла из множества неизбежен при любой MTBF для одного узла); Вы можете использовать это для своего окружения.

Вот несколько идей:

  • Убедитесь, что все ваше оборудование реплицировано nраз (где nбольше 2, и предпочтительно нечетное), и что каждый аппаратный элемент может связываться друг с другом аппаратным элементом. Ethernet является одним из очевидных способов сделать это, но есть много других гораздо более простых маршрутов, которые обеспечат лучшую защиту (например, CAN). Минимизируйте общие компоненты (даже источники питания). Это может означать, например, выборку входов АЦП в нескольких местах.

  • Убедитесь, что состояние вашего приложения находится в одном месте, например, в конечном автомате. Это может быть полностью основано на оперативной памяти, хотя не исключает стабильного хранения. Таким образом, он будет храниться в нескольких местах.

  • Принять протокол кворума для изменений состояния. Смотрите РАФТ для примера. Поскольку вы работаете в C ++, для этого есть хорошо известные библиотеки. Изменения в FSM будут сделаны только тогда, когда большинство узлов согласится. Используйте известную хорошую библиотеку для стека протоколов и протокола кворума вместо того, чтобы самим ее свернуть, иначе вся ваша хорошая работа по резервированию будет потрачена впустую, когда протокол кворума зависнет.

  • Убедитесь, что вы проверяли контрольную сумму (например, CRC / SHA) своего FSM и сохраняли CRC / SHA в самом FSM (а также передавали в сообщении и проверяли контрольные суммы самих сообщений). Получите, чтобы узлы регулярно проверяли свой FSM на соответствие этой контрольной сумме, проверяли контрольную сумму входящих сообщений и проверяли, чтобы их контрольная сумма соответствовала контрольной сумме кворума.

  • Встраивайте в свою систему как можно больше других внутренних проверок, заставляя узлы, которые обнаруживают свои собственные ошибки, перезагружаться (это лучше, чем выполнять половину работы, если у вас достаточно узлов). Попытайтесь позволить им полностью удалить себя из кворума во время перезагрузки на случай, если они больше не появятся. При перезагрузке попросите их проверить контрольную сумму образа программного обеспечения (и всего остального, что они загружают) и выполнить полный тест ОЗУ, прежде чем снова ввести себя в кворум.

  • Используйте оборудование, чтобы поддержать вас, но делайте это осторожно. Например, вы можете получить оперативную память ECC и регулярно читать и записывать ее для исправления ошибок ECC (и паники, если ошибка не исправима). Однако (из памяти) статическое ОЗУ гораздо более терпимо к ионизирующему излучению, чем ДРАМ, во-первых, поэтому вместо него может быть лучше использовать статический ДРАМ. Смотрите также первый пункт в разделе «что бы я не делал».

Допустим, у вас есть 1% шанс отказа любого узла в течение одного дня, и давайте представим, что вы можете сделать отказы полностью независимыми. С 5 узлами вам понадобится три для отказа в течение одного дня, что составляет вероятность 0,0000%. С большим, ну, вы поняли.

Что бы я не делал:

  • Недооценивайте ценность отсутствия проблемы, с которой нужно начинать. Если вес не является проблемой, большой кусок металла вокруг вашего устройства будет гораздо более дешевым и надежным решением, чем команда программистов. Опто-оптическая связь входов электромагнитных помех является проблемой и т. Д. Как бы то ни было, попытайтесь при поиске ваших компонентов найти те компоненты, которые наилучшим образом защищены от ионизирующего излучения.

  • Бросайте свои собственные алгоритмы . Люди делали это раньше. Используйте их работу. Отказоустойчивость и распределенные алгоритмы сложны. Используйте работу других людей, где это возможно.

  • Используйте сложные настройки компилятора, надеясь, что вы обнаружите больше сбоев. Если вам повезет, вы можете обнаружить больше сбоев. Скорее всего, вы будете использовать путь кода в компиляторе, который был менее протестирован, особенно если вы сами его свернули.

  • Используйте методы, которые не были протестированы в вашей среде. Большинству людей, пишущих программное обеспечение высокой доступности, приходится имитировать режимы сбоев, чтобы проверить правильность их работы, и в результате пропустить множество режимов сбоев. Вы находитесь в «счастливом» положении с частыми неудачами по требованию. Поэтому протестируйте каждую технику и убедитесь, что ее применение действительно улучшает MTBF на величину, которая превышает сложность ее внедрения (со сложностью возникают ошибки). Особенно примените это к моим советам по алгоритмам кворума и т. Д.


2
Ethernet, вероятно, не очень хорошая идея для использования в критически важных приложениях. Как и I2C, за пределами самой платы. Что-то прочное, как CAN, было бы гораздо более подходящим.
Лундин

1
@ Lundin Справедливо, хотя все оптически подключенное (включая Ethernet) должно быть в порядке.
abligh

1
Физическая среда является не столько причиной непригодности Ethernet, сколько отсутствием детерминированного поведения в реальном времени. Хотя я полагаю, что в настоящее время есть способы обеспечить несколько более надежный Ethernet, я просто сгруппировал его вместе с коммерческой / игрушечной электроникой по старой привычке.
Лундин

1
@Lundin, это справедливо, но, поскольку я предлагаю использовать его для запуска RAFT, в алгоритме будет (теоретически) недетерминированное поведение в реальном времени в любом случае (например, одновременные выборы лидера, приводящие к повторным выборам, аналогичным CSMA / КОМПАКТ ДИСК). Если необходимо строгое поведение в реальном времени, возможно, мой ответ имеет больше проблем, чем ethernet (и обратите внимание, что в начале моего ответа я сказал, что «правильный», скорее всего, будет за счет «быстрого» часто). Я включил вашу точку зрения относительно CAN, хотя.
раньше

1
@Lundin: Ни одна система, включающая асинхронные аспекты, не может быть полностью недетерминированной. Я думаю, что наихудшее поведение Ethernet может быть ограничено при отсутствии сбоев аппаратного обеспечения, если программные протоколы настроены подходящим образом, а устройства имеют уникальные идентификаторы, и существует известное ограничение на количество устройств (чем больше устройств, тем больше количество повторных попыток в худшем случае).
Суперкат

23

Поскольку вы специально запрашиваете программные решения и используете C ++, почему бы не использовать перегрузку операторов для создания собственных, безопасных типов данных? Например:

Вместо использования uint32_tdouble, и int64_tт.д.), сделать свой собственный , SAFE_uint32_tкоторый содержит несколько (минимум 3) uint32_t. Перегрузите все операции, которые вы хотите (* + - / << >> = ==! = И т. Д.), И заставьте перегруженные операции выполнять независимо для каждого внутреннего значения, т.е. не делайте этого один раз и скопируйте результат. Как до, так и после убедитесь, что все внутренние значения совпадают. Если значения не совпадают, вы можете обновить неправильное значение до наиболее распространенного. Если наиболее распространенное значение отсутствует, вы можете смело уведомлять об ошибке.

Таким образом, не имеет значения, произойдет ли повреждение в ALU, регистрах, ОЗУ или на шине, у вас все равно будет несколько попыток и очень хороший шанс на обнаружение ошибок. Однако обратите внимание, что это работает только для переменных, которые вы можете заменить - например, ваш указатель стека все еще будет восприимчивым.

Дополнительная история: я столкнулся с аналогичной проблемой, также на старом чипе ARM. Это оказался набор инструментов, который использовал старую версию GCC, которая вместе с конкретным чипом, который мы использовали, вызывала ошибку в определенных крайних случаях, которая (иногда) повреждала значения, передаваемые в функции. Убедитесь, что у вашего устройства нет проблем, прежде чем обвинять его в радиоактивности, и да, иногда это ошибка компилятора =)


1
У некоторых из этих предложений есть что-то похожее на мышление «многоразрядной проверки работоспособности» для обнаружения коррупции, мне очень нравится это предложение с предложением критических для безопасности пользовательских типов данных, хотя
WearyWanderer

2
В мире существуют системы, в которых каждый резервный узел проектировался и разрабатывался разными группами, причем арбитр следил за тем, чтобы они случайно не остановились на одних и тех же решениях. Таким образом, у вас не будет их всех из-за одной и той же ошибки, и похожие переходные процессы не будут проявлять схожих режимов отказа.
Jwdonahue

16

Отказ от ответственности: я не профессионал радиоактивности, и не работал на такого рода приложения. Но я работал над мягкими ошибками и избыточностью для долгосрочного архивирования критических данных, которые несколько связаны (одна и та же проблема, разные цели).

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

Тогда возникает вопрос: как надежно вычислить, когда ваша память ненадежна?

Чтобы значительно снизить частоту мягких ошибок (за счет вычислительных затрат, поскольку это будут в основном программные решения), вы можете:

  • полагаться на старую старую схему избыточности и, в частности, на более эффективные коды с исправлением ошибок (те же цели, но более умные алгоритмы, чтобы вы могли восстановить больше битов с меньшей избыточностью). Это иногда (ошибочно) также называется контрольной суммой. При таком решении вы должны будете в любой момент сохранить полное состояние вашей программы в главной переменной / классе (или структуре?), Вычислить ECC и проверить правильность ECC, прежде чем что-либо делать, и если нет, починить поля. Это решение, однако, не гарантирует, что ваше программное обеспечение может работать (просто, что оно будет работать правильно, когда оно может, или перестает работать, если нет, потому что ECC может сказать вам, если что-то не так, и в этом случае вы можете остановить свое программное обеспечение, чтобы вы могли не получить поддельные результаты).

  • или вы можете использовать устойчивые алгоритмические структуры данныхЭто гарантирует, до некоторой степени, что ваша программа будет по-прежнему давать правильные результаты даже при наличии мягких ошибок. Эти алгоритмы можно рассматривать как смесь общих алгоритмических структур со схемами ECC, изначально встроенными в него, но это гораздо более гибко, чем это, потому что схема отказоустойчивости тесно связана со структурой, так что вам не нужно кодировать дополнительные процедуры. проверить ECC, и обычно они намного быстрее. Эти структуры обеспечивают способ гарантировать, что ваша программа будет работать при любых условиях, вплоть до теоретической границы мягких ошибок. Вы также можете смешать эти отказоустойчивые структуры со схемой избыточности / ECC для дополнительной безопасности (или закодировать ваши наиболее важные структуры данных как отказоустойчивые, а остальные - расходуемые данные, которые вы можете пересчитать из основных структур данных,

Если вы заинтересованы в устойчивых структурах данных (что является недавним, но интересным, новым направлением в алгоритмике и разработке избыточности), я советую вам прочитать следующие документы:

  • Интеллектуальные алгоритмы структуры данных, введение Джузеппе Ф.Итальяно, Университет Ромы "Tor Vergata"

  • Christiano, P., Demaine, ED, & Kishore, S. (2011). Безотказные отказоустойчивые структуры данных с аддитивными издержками. В алгоритмах и структурах данных (стр. 243-254). Springer Berlin Heidelberg.

  • Ferraro-Petrillo, U., Grandoni, F. & Italiano, GF (2013). Структуры данных, устойчивые к сбоям памяти: экспериментальное изучение словарей. Журнал экспериментальной алгоритмики (JEA), 18, 1-6.

  • Итальяно, GF (2010). Эластичные алгоритмы и структуры данных. В алгоритмах и сложности (стр. 13-24). Springer Berlin Heidelberg.

Если вам интересно узнать больше о области упругих структур данных, вы можете ознакомиться с работами Джузеппе Ф. Итальяно (и пройтись по ссылкам) и моделью Faulty-RAM (представленной в Finocchi et al. 2005; Finocchi). и итальяно 2008).

/ РЕДАКТИРОВАТЬ: я проиллюстрировал предотвращение / восстановление от программных ошибок в основном для оперативной памяти и хранения данных, но я не говорил об ошибках вычислений (ЦП) . Другие ответы уже указывали на использование атомарных транзакций, как в базах данных, поэтому я предложу другую, более простую схему: избыточность и большинство голосов .

Идея состоит в том, что вы просто делаете x раз одно и то же вычисление для каждого вычисления, которое вам нужно сделать, и сохраняете результат в x разных переменных (с x> = 3). Затем вы можете сравнить ваши переменные x :

  • если они все согласны, то нет никакой ошибки в вычислениях.
  • если они не согласны, то вы можете использовать большинство голосов, чтобы получить правильное значение, и, поскольку это означает, что вычисления были частично повреждены, вы также можете запустить сканирование состояния системы / программы, чтобы проверить, все ли в порядке.
  • если большинство голосов не может определить победителя (все значения x различны), то это идеальный сигнал для вас, чтобы запустить безотказную процедуру (перезагрузить компьютер, выдать предупреждение пользователю и т. д.).

Эта схема резервирования очень быстрая по сравнению с ECC (практически O (1)) и дает вам четкий сигнал, когда вам необходимо обеспечить отказоустойчивость . Кроме того, гарантируется, что большинство голосов (почти) никогда не произведут искаженный вывод, а также восстановятся после незначительных ошибок вычислений , потому что вероятность того, что вычисления x дадут тот же результат, бесконечно мала (поскольку существует огромное количество возможных выходных данных, почти невозможно случайным образом получить 3 раза то же самое, еще меньше шансов, если x> 3).

Таким образом, большинством голосов вы защищены от искаженного вывода, а с избыточностью x == 3 вы можете восстановить 1 ошибку (при x == 4 это будет 2 ошибки, которые можно исправить, и т. Д. - точное уравнение - это nb_error_recoverable == (x-2)где x - это число повторений расчетов, потому что вам нужно, по крайней мере, 2 согласованных расчета для восстановления с использованием большинства голосов).

Недостаток заключается в том, что вам нужно вычислять x раз вместо одного, поэтому у вас есть дополнительные вычислительные затраты, но при этом линейная сложность, так что асимптотически вы не теряете много из-за преимуществ, которые вы получаете. Быстрый способ сделать большинство голосов - это вычислить режим для массива, но вы также можете использовать медианный фильтр.

Кроме того, если вы хотите убедиться, что вычисления выполняются правильно, если вы можете сделать свое собственное оборудование, вы можете собрать свое устройство с x процессорами и подключить систему так, чтобы вычисления автоматически дублировались на x процессорах с большинством голосов. механически в конце (например, с использованием вентилей AND / OR). Это часто реализуется в самолетах и ​​критически важных устройствах (см. Тройное модульное резервирование ). Таким образом, у вас не будет никаких вычислительных накладных расходов (поскольку дополнительные вычисления будут выполняться параллельно), и у вас будет еще один уровень защиты от мягких ошибок (поскольку дублирование вычислений и большинство голосов будут управляться непосредственно аппаратным обеспечением, а не программное обеспечение - которое может быть легко повреждено, поскольку программа - это просто биты, хранящиеся в памяти ...).


9

Один момент никто, кажется, не упомянул. Вы говорите, что разрабатываете в GCC и кросс-компилируете в ARM. Откуда вы знаете, что у вас нет кода, который делает предположения о свободной оперативной памяти, целочисленном размере, размере указателя, сколько времени требуется для выполнения определенной операции, сколько времени система будет работать непрерывно или что-то в этом роде? Это очень распространенная проблема.

Ответом обычно является автоматическое юнит-тестирование. Напишите тестовые наборы, которые осуществляют код в системе разработки, затем запустите те же тестовые наборы в целевой системе. Ищите различия!

Также проверьте наличие ошибок на встроенном устройстве. Вы можете обнаружить, что есть что-то вроде «не делайте этого, потому что это даст сбой, поэтому включите эту опцию компилятора, и компилятор будет обходить ее».

Короче говоря, ваш наиболее вероятный источник сбоев - это ошибки в вашем коде. Пока вы не уверены, что это не так, не беспокойтесь (пока) о более эзотерических режимах сбоев.


1
Действительно, нигде в тесте вопроса автор не упоминает, что было обнаружено, что приложение отлично работает вне радиоактивной среды.
23 марта

9

Вы хотите 3+ подчиненных машин с хозяином вне радиационной среды. Все операции ввода / вывода проходят через мастер, который содержит механизм голосования и / или повторных попыток. У ведомых устройств должен быть аппаратный сторожевой таймер, и призыв к их усилению должен быть окружен CRC или чем-то подобным, чтобы уменьшить вероятность непроизвольного столкновения. Удар должен контролироваться ведущим, поэтому потерянное соединение с главным равняется перезагрузке в течение нескольких секунд.

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

Изменить: Из комментариев я чувствую необходимость прояснить "идею CRC". Вероятность того, что ведомое устройство ударит свой собственный сторожевой таймер, близка к нулю, если вы окружите удар с помощью CRC или дайджест-проверок случайных данных от мастера. Эти случайные данные отправляются только от ведущего, когда подчиненное устройство находится под контролем других. Случайные данные и CRC / дайджест немедленно очищаются после каждого удара. Частота удара ведущий-ведомый должна быть более чем в два раза больше времени ожидания сторожевого таймера. Данные, отправленные мастером, генерируются уникальным образом каждый раз.


7
Я пытаюсь понять сценарий, в котором вы можете иметь хозяина вне радиационной среды, способного надежно общаться с рабами в радиационной среде, когда вы не можете просто поместить рабов вне радиационной среды.
fostandy

1
@fostandy: ведомые устройства измеряют или контролируют, используя оборудование, для которого требуется контроллер. Скажи счетчик Гейгера. Ведущий не нуждается в надежной связи из-за избыточности подчиненного устройства.
Йонас Быстрем

4
Введение мастера не будет автоматически означать повышение безопасности. Если ведомый x сошел с ума из-за повреждения памяти, так что он постоянно говорит себе: «Мастер здесь, мастер счастлив», то никакое количество CRC или лающих заказов мастера не спасет его. Вы должны дать хозяину возможность отключить власть этого раба. И если у вас есть ошибка по общей причине, добавление дополнительных ведомых не повысит безопасность. Также имейте в виду, что количество программных ошибок и количество вещей, которые могут сломаться, увеличиваются со сложностью.
Лундин

5
При этом, конечно, было бы неплохо «перенести» как можно большую часть программы куда-нибудь в менее уязвимое место, при этом сохраняя электронику внутри радиоактивной среды настолько простой, насколько это возможно, если у вас есть такая возможность.
Лундин

7

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


2
Конечно, встроенная система предпочла бы критические сбои безопасности в одном экземпляре надежного приложения, чем просто запускать несколько экземпляров, повышая требования к оборудованию и в некоторой степени надеясь на слепую удачу, что хотя бы один экземпляр справится, ладно? Я понял идею, и она верна, но больше склоняюсь к предложениям, которые не основаны на грубой силе
WearyWanderer

7

То, что вы спрашиваете, является довольно сложной темой - не так легко ответить. Другие ответы в порядке, но они охватывают лишь небольшую часть всего, что вам нужно сделать.

Как видно из комментариев , невозможно решить проблемы с оборудованием на 100%, однако возможно с высокой вероятностью уменьшить или отловить их, используя различные методы.

Если бы я был вами, я бы создал программное обеспечение самого высокого уровня безопасности (SIL-4). Получите документ МЭК 61513 (для атомной промышленности) и следуйте ему.


11
Или, скорее, прочитайте технические требования и реализуйте те, которые имеют смысл. Большая часть стандартов SIL - это нонсенс, если вы будете следовать им догматически, вы получите небезопасные и опасные продукты. Сегодня сертификация SIL в основном сводится к производству тонны документации и подкупу испытательного дома. Уровень SIL ничего не говорит о фактической безопасности системы. Вместо этого вы захотите сосредоточиться на реальных технических мерах безопасности. В документах SIL есть несколько очень хороших, и есть несколько полных бессмысленных.
Лундин

7

Кто-то упомянул об использовании более медленных чипов, чтобы ионы не могли легко перевернуть биты. Аналогичным образом возможно использовать специализированный процессор / оперативную память, который на самом деле использует несколько битов для хранения одного бита. Таким образом, обеспечивая аппаратную отказоустойчивость, так как маловероятно, что все биты будут перевернуты. Так что 1 = 1111, но нужно было бы попасть 4 раза, чтобы на самом деле перевернуться. (4 может быть плохим числом, так как если 2 бита перевернуты, это уже неоднозначно). Таким образом, если вы выберете 8, вы получите в 8 раз меньше оперативной памяти и на некоторое время меньше времени доступа, но гораздо более надежное представление данных. Вероятно, вы могли бы сделать это как на уровне программного обеспечения с помощью специализированного компилятора (выделите на x больше места для всего), так и на языке реализации (напишите обертки для структур данных, которые размещают объекты таким образом).


7

Возможно, было бы полезно узнать, означает ли это, что аппаратное обеспечение «предназначено для этой среды». Как это исправить и / или указывает на наличие ошибок SEU?

В одном проекте, связанном с исследованием космоса, у нас был собственный MCU, который вызывал бы исключение / прерывание при ошибках SEU, но с некоторой задержкой, то есть некоторые циклы могут проходить / выполнять инструкции после одного insn, который вызвал исключение SEU.

Особенно уязвим был кэш данных, поэтому обработчик лишил законной силы строку кэша и перезапустил программу. Только то, что из-за неточного характера исключения последовательность insns во главе с повышением исключения может не быть перезапускаемой.

Мы определили опасные (не перезапускаемые) последовательности (например lw $3, 0x0($2), за которым следует insn, который изменяет $2и не зависит от данных $3), и я внес изменения в GCC, поэтому такие последовательности не возникают (например, в качестве крайней меры, разделяя два insns на а nop).

Просто кое-что рассмотреть ...


7

Если ваше оборудование выходит из строя, вы можете использовать механическое хранилище для его восстановления. Если ваша кодовая база мала и имеет некоторое физическое пространство, вы можете использовать механическое хранилище данных.

Введите описание изображения здесь

Там будет поверхность материала, которая не будет подвергаться воздействию радиации. Несколько передач будет там. Механический считыватель будет работать на всех передачах и будет гибким, чтобы двигаться вверх и вниз. Вниз означает, что это 0, а вверх означает, что это 1. Из 0 и 1 вы можете сгенерировать свою кодовую базу.


2
Возможно, оптический носитель, такой как CD-ROM, будет соответствовать этому определению. Это будет иметь дополнительный бонус большой емкости.
Wossname

2
Да, это будет похоже, но CD-ROM будет использовать меньше, но это будет полностью механическая система.
Хитул

7
Интересно, есть ли причина, почему они не используют устройства чтения перфокарт в космосе?
Сорен

3
@ Сорен Скорость и физическое пространство могут быть причиной.
Хитул

5

Используйте циклический планировщик . Это дает вам возможность добавлять регулярное время обслуживания для проверки правильности критических данных. Чаще всего встречается проблема с повреждением стека. Если ваше программное обеспечение циклично, вы можете переинициализировать стек между циклами. Не используйте повторно стеки для вызовов прерывания, установите отдельный стек для каждого важного вызова прерывания.

Похожий на Watchdog концепт является таймерами крайних сроков. Запустите аппаратный таймер перед вызовом функции. Если функция не возвращается до того, как таймер крайнего срока прерывается, перезагрузите стек и попробуйте снова. Если после 3/5 попыток это не помогло, необходимо перезагрузить ПЗУ.

Разделите ваше программное обеспечение на части и изолируйте эти части, чтобы использовать отдельные области памяти и время выполнения (особенно в среде управления). Пример: получение сигнала, предварительная обработка данных, основной алгоритм и реализация / передача результата. Это означает, что сбой в одной части не приведет к сбоям в остальной части программы. Поэтому, пока мы восстанавливаем получение сигнала, остальные задачи продолжаются на устаревших данных.

Все нуждается в CRC. Если вы выполняете из ОЗУ, даже ваш .text нуждается в CRC. Регулярно проверяйте CRC, если вы используете циклический планировщик. Некоторые компиляторы (не GCC) могут генерировать CRC для каждого раздела, а некоторые процессоры имеют выделенное оборудование для выполнения вычислений CRC, но я думаю, что это выходит за рамки вашего вопроса. Проверка CRC также предлагает контроллеру ECC в памяти исправить однобитовые ошибки, прежде чем это станет проблемой.


4

Во-первых, разработайте свое приложение на случай отказа . Убедитесь, что как часть нормальной работы потока он ожидает сброса (в зависимости от вашего приложения и типа сбоя: мягкий или жесткий). Этого трудно достичь идеальным: критические операции, требующие некоторой степени транзакционности, могут нуждаться в проверке и настройке на уровне сборки, чтобы прерывание в ключевой точке не могло привести к несовместимым внешним командам. Сбой быстро, как только обнаруживается любое неисправимое повреждение памяти или отклонение потока управления. Журнал сбоев, если это возможно.

Во-вторых, где это возможно, исправьте коррупцию и продолжайте . Это означает, что контрольные суммы и исправление постоянных таблиц (и программного кода, если вы можете) часто; возможно, перед каждой основной операцией или по временному прерыванию, и сохраняя переменные в структурах, которые автозаменяются (снова перед каждой основной операцией или по временному прерыванию берут большинство голосов от 3 и исправляют, если это одно отклонение). Зарегистрируйте исправления, если это возможно.

В-третьих, провал теста . Установите воспроизводимую тестовую среду, которая перебрасывает биты в памяти псевдослучайно. Это позволит вам воспроизвести коррупционные ситуации и помочь разработать приложение вокруг них.


3

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


Я большой поклонник ассемблера (как вы можете видеть из моих ответов на другие вопросы), но я не думаю, что это хороший ответ. Вполне возможно узнать, чего ожидать от компилятора для большей части кода C (с точки зрения значений, находящихся в регистрах или в памяти), и вы всегда можете проверить, что это то, что вы ожидали. Написание большого проекта в asm - это просто тонна дополнительной работы, даже если у вас есть разработчики, которым очень удобно писать ARM asm. Может быть, если вы хотите сделать что-то вроде вычисления одного и того же результата 3 раза, написание некоторых функций в asm имеет смысл. (компиляторы откажутся от него)
Питер Кордес

Более высокий риск, который должен быть сбалансирован с обновлением компилятора, может привести к неожиданным изменениям.
Джошуа

1

Здесь огромное количество ответов, но я постараюсь обобщить свои идеи по этому поводу.

Что-то выходит из строя или работает неправильно, может быть результатом ваших собственных ошибок - тогда это должно быть легко исправить, когда вы обнаружите проблему. Но существует также возможность аппаратных сбоев - и это сложно, если не невозможно, исправить в целом.

Я бы порекомендовал сначала попытаться поймать проблемную ситуацию, ведя журнал (стек, регистры, вызовы функций) - либо записывая их где-то в файл, либо передавая их каким-либо образом напрямую («о нет, я сбой»).

Восстановление из такой ситуации ошибки - это либо перезагрузка (если программное обеспечение все еще живо и работает), либо аппаратный сброс (например, hw watchdogs). Проще начать с первого.

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

Также, если код относительно сложен - имеет смысл «разделить и завоевать» его - то есть вы удаляете / отключаете некоторые вызовы функций там, где вы подозреваете проблему - как правило, отключая половину кода и включая другую половину - вы можете получить «работает» / решение типа «не работает», после которого вы можете сосредоточиться на другой половине кода. (Где проблема)

Если через какое-то время возникает проблема - тогда можно ожидать переполнения стека - тогда лучше отслеживать регистры точек стека - если они постоянно растут.

И если вам удастся полностью свести к минимуму свой код до тех пор, пока приложение типа «здравствуй, мир» - и оно все равно будет случайным образом терпеть неудачу - тогда возникнут проблемы с оборудованием - и потребуется «обновление оборудования» - то есть изобрести такой процессор / ram / ... - комбинация аппаратных средств, которая лучше переносит излучение.

Вероятно, наиболее важным является то, как вы возвращаете свои журналы, если машина полностью остановлена ​​/ перезагружена / не работает - вероятно, первое, что должен сделать загрузчик, - это вернитесь домой, если возникнет проблемная ситуация.

Если в вашей среде возможно также передавать сигнал и получать ответ - вы можете попытаться создать какую-то среду удаленной отладки в режиме онлайн, но тогда у вас должен быть хотя бы работающий коммуникационный носитель и какой-нибудь процессор / некоторое количество оперативной памяти в рабочем состоянии. И под удаленной отладкой я подразумеваю либо подход типа GDB / gdb-заглушки, либо вашу собственную реализацию того, что вам нужно вернуть из приложения (например, загрузка файлов журнала, загрузка стека вызовов, загрузка оперативной памяти, перезапуск)


Извините, но речь идет о радиоактивной среде, в которой произойдет сбой оборудования. Ваш ответ об общей оптимизации программного обеспечения и о том, как найти ошибки. Но в этой ситуации ошибки не
вызваны

Да, вы можете обвинить также гравитацию, оптимизацию компилятора, стороннюю библиотеку, радиоактивную среду и так далее. Но вы уверены, что это не ваши собственные ошибки? :-) Если не доказано - я не верю в это. Однажды я запускал некоторое обновление прошивки и тестировал ситуацию отключения питания - мое программное обеспечение переживало все ситуации отключения питания только после того, как я исправил все свои собственные ошибки. (Более 4000 отключений в ночное время) Но трудно поверить, что в некоторых случаях была ошибка. Особенно, когда мы говорим о повреждении памяти.
TarmoPikaro

0

Я действительно прочитал много хороших ответов!

Вот мои 2 цента: построить статистическую модель аномалий памяти / регистра, написав программное обеспечение для проверки памяти или частых сравнений регистров. Кроме того, создайте эмулятор в стиле виртуальной машины, где вы сможете поэкспериментировать с этой проблемой. Я предполагаю, что если вы измените размер перехода, тактовую частоту, производителя, корпус и т. Д., То наблюдаете другое поведение.

Даже память нашего настольного ПК имеет определенную частоту отказов, которая, однако, не мешает повседневной работе.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.