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

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

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

23 ответов


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


НАСА бумага о радиационном отверждении программного обеспечения. Он описывает три основные задачи:

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

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

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

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

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

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

и, так уж получилось, NASA использовало C++ для крупных проектов, таких как Марс.

абстракция и инкапсуляция класса C++ позволили быстро разработать и протестировать несколько проектов и разработчиков.

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

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

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

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

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

использовать ваш лучший RAM для стека.

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

реализовать таймер-ТИК и сторожевой таймер подпрограммы.

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

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

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

помните о тайниках.

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

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

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

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

с ассемблером, вы знаю что в регистрах и что в ОЗУ; вы знаю какие специальные таблицы ОЗУ использует процессор, и вы можете проектировать вещи окольным путем, чтобы снизить риск.

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

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

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

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

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

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

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

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


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

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

алгоритм на основе отказоустойчивости применяется для высокопроизводительных вычислений".

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

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

  • используйте ежедневные меры безопасности "хлеба & масла" которые должны присутствовать на любой полупрофессиональной врезанной системе: внутренний сторожевой пес, внутреннее низшее напряжение обнаруживает, внутренний монитор часов. Эти вещи даже не должны упоминаться в год 2016, и они стандартны практически на каждом современном микроконтроллере.
  • если у вас есть безопасность и/или автомобильный MCU, он будет иметь определенные функции сторожевого пса, такие как заданное окно времени, внутри которого вам нужно обновить сторожевого пса. Это предпочтительнее, если у вас есть критически важная система реального времени.
  • в общем, используйте MCU, подходящий для таких систем, а не какой-то общий основной пух, который вы получили в пакете кукурузных хлопьев. Почти каждое изготовление MCU в наше время специализировало MCUs конструированное для применений безопасности (TI, Freescale, Renesas, ST, Infineon etc etc). Они имеют множество встроенных функций безопасности, включая ядра lock-step: это означает, что есть 2 ядра CPU, выполняющие один и тот же код, и они должны соглашаться друг с другом.
  • важно: вы должны обеспечить целостность внутренних регистров MCU. Все регистры управления и состояния аппаратных периферийных устройств, которые можно записать, могут быть расположены в ОЗУ память, и поэтому уязвимы.

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

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

  • есть все виды методов для проверки ошибок в ОЗУ или NVM: контрольные суммы, "Ходячие шаблоны", программное обеспечение ECC и т. д. Лучшее решение в настоящее время-не использовать ни один из них, а использовать MCU со встроенным ECC и аналогичными проверками. Потому что делать это в программном обеспечении сложно, и проверка ошибок сама по себе поэтому могут возникнуть ошибки и неожиданные проблемы.

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

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

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

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

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

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

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

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

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

можно использовать 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();

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

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


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

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

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

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

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


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

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

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

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

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

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


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

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

вот некоторые идеи:

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

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

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

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

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

  • используйте оборудование для поддержки, но делайте это осторожно. Вы можете получить ECC RAM, например, и регулярно читать / писать через него, чтобы исправить ошибки ECC (и паниковать, если ошибка неисправима). Однако (из памяти) статическая оперативная память намного более толерантна к ионизирующему излучению, чем DRAM, поэтому она мая лучше использовать статический DRAM вместо этого. См. первый пункт в разделе "вещи, которые я бы не сделал".

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

Я не do:

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

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

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

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


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

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

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

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


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

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

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

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

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

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

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

  • устойчивых алгоритмов структуры интро Джузеппе Ф. Италиано, Universita di Roma "Tor Vergata"

  • Кристиано, П., Demaine, Д. Е. & Кишор, С. (2011). Отказоустойчивые структуры данных без потерь с аддитивными накладными расходами. В алгоритмах и структурах данных (стр. 243-254). Springer Berlin Heidelberg.

  • Ферраро-Петрилло, США, Grandoni, Ф., & Итальяно, Г. Ф. (2013). Структуры данных, устойчивые к сбоям памяти: экспериментальное исследование словарей. Журнал экспериментальной Алгоритмики (JEA), 18, 1-6.

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

Если вам интересно узнать больше о области устойчивых структур данных, вы можете проверить работы Джузеппе Ф. Итальяно (и работать свой путь через refs) и неисправная модель ОЗУ (введена в Finocchi et al. 2005; Finocchi and Italiano 2008).

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

идея заключается в том, что вы просто сделать 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 gates). Это часто реализуется в самолетах и критически важных устройствах (см. мажорирование). Таким образом, у вас не будет никаких вычислительных накладных расходов (так как дополнительные вычисления будут выполняться параллельно), и у вас есть еще один уровень защиты от мягких ошибок (поскольку дублирование вычислений и большинство голосов будут управляться непосредственно аппаратным обеспечением, а не программным обеспечением, которое может быть более легко повреждено, поскольку программа просто бит, хранящийся в памяти...).


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

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

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


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

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

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

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


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


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

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

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


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


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

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

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

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

просто что-то рассмотреть ...


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

Enter image description here

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


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

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

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

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


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

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

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


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


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

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

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

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

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

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

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

и если вам удастся полностью свести к минимуму ваш код до" hello world "типа приложения - и он все еще не работает случайным образом - то аппаратные проблемы ожидаются - и должно быть "обновление оборудования" - то есть изобрести такой cpu / ram / ... - аппаратная комбинация, которая лучше переносит радиацию.

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

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


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

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

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