Compilación de una aplicación para su uso en entornos altamente radiactivos.
Estamos compilando una aplicación C++ integrada que se implementa en un dispositivo blindado en un entorno bombardeado con radiación ionizante . Estamos usando GCC y compilación cruzada para ARM. Cuando se implementa, nuestra aplicación genera algunos datos erróneos y falla con más frecuencia de lo que nos gustaría. El hardware está diseñado para este entorno y nuestra aplicación se ha ejecutado en esta plataforma durante varios años.
¿Hay cambios que podamos realizar en nuestro código o mejoras en tiempo de compilación que se puedan realizar para identificar/corregir errores de software y corrupción de memoria causados por alteraciones de un solo evento ? ¿Algún otro desarrollador ha logrado reducir los efectos nocivos de los errores leves en una aplicación de larga duración?
Habiendo trabajado durante aproximadamente 4-5 años en el desarrollo de software/firmware y pruebas ambientales de satélites miniaturizados *, me gustaría compartir mi experiencia aquí.
*( Los satélites miniaturizados son mucho más propensos a sufrir perturbaciones por eventos únicos que los satélites más grandes debido a sus tamaños relativamente pequeños y limitados para sus componentes electrónicos )
Para ser muy conciso y directo: no existe ningún mecanismo para recuperarse de una situación errónea detectable por el propio software/firmware sin , al menos, una copia de la versión mínima funcional del software/firmware en algún lugar para fines de recuperación , y con el hardware compatible. la recuperación (funcional).
Ahora bien, esta situación normalmente se maneja tanto a nivel de hardware como de software. Aquí, según lo solicite, compartiré lo que podemos hacer a nivel de software.
...propósito de recuperación... . Proporciona la capacidad de actualizar/recompilar/reactualizar tu software/firmware en un entorno real. Esta es una característica casi imprescindible para cualquier software/firmware en un entorno altamente ionizado. Sin esto, podría tener tanto software/hardware redundante como desee, pero en algún momento todos explotarán. Entonces, ¡prepara esta función!
...versión mínima de trabajo... Tenga copias múltiples y receptivas de la versión mínima del software/firmware en su código. Esto es como el modo seguro en Windows. En lugar de tener solo una versión completamente funcional de su software, tenga varias copias de la versión mínima de su software/firmware. La copia mínima suele tener un tamaño mucho menor que la copia completa y casi siempre tiene sólo las dos o tres características siguientes:
- capaz de escuchar comandos desde un sistema externo,
- capaz de actualizar el software/firmware actual,
- capaz de monitorear los datos de mantenimiento de la operación básica.
...copiar... en alguna parte... Tener software/firmware redundante en alguna parte.
Podría, con o sin hardware redundante, intentar tener software/firmware redundante en su ARM uC. Esto normalmente se hace teniendo dos o más software/firmware idénticos en direcciones separadas que se envían latidos entre sí, pero solo uno estará activo a la vez. Si se sabe que uno o más software/firmware no responden, cambie al otro software/firmware. El beneficio de utilizar este enfoque es que podemos tener un reemplazo funcional inmediatamente después de que ocurre un error, sin ningún contacto con cualquier sistema/parte externa responsable de detectar y reparar el error (en el caso de un satélite, generalmente es el Centro de Control de Misión ( MCC)).
Estrictamente hablando, sin hardware redundante, la desventaja de hacer esto es que en realidad no se pueden eliminar todos los puntos únicos de falla. Como mínimo, todavía tendrá un único punto de falla, que es el interruptor en sí (o, a menudo, el comienzo del código). Sin embargo, para un dispositivo limitado por el tamaño en un entorno altamente ionizado (como los satélites pico/femto), aún valdrá la pena considerar la reducción del punto único de falla a un punto sin hardware adicional. Además, el fragmento de código para el cambio ciertamente sería mucho menor que el código para todo el programa, lo que reduciría significativamente el riesgo de que se produzca un evento único.
Pero si no estás haciendo esto, deberías tener al menos una copia en tu sistema externo que pueda entrar en contacto con el dispositivo y actualizar el software/firmware (en el caso del satélite, es nuevamente el centro de control de la misión).
- También puede tener la copia en la memoria permanente de su dispositivo, que puede activarse para restaurar el software/firmware del sistema en ejecución.
...situación errónea detectable. El error debe ser detectable , generalmente mediante el circuito de detección/corrección de errores del hardware o mediante un pequeño fragmento de código para la corrección/detección de errores. Es mejor colocar dicho código en un formato pequeño, múltiple e independiente del software/firmware principal. Su tarea principal es únicamente comprobar/corregir. Si el circuito/firmware del hardware es confiable (por ejemplo, está más endurecido por radiación que el resto, o tiene múltiples circuitos/lógicas), entonces podría considerar realizar una corrección de errores con él. Pero si no es así, es mejor hacerlo como detección de errores. La corrección puede realizarse mediante un sistema/dispositivo externo. Para la corrección de errores, podría considerar hacer uso de un algoritmo básico de corrección de errores como Hamming/Golay23, porque se pueden implementar más fácilmente tanto en el circuito como en el software. Pero en última instancia depende de la capacidad de su equipo. Para la detección de errores, normalmente se utiliza CRC.
...hardware que soporta la recuperación Ahora, llega el aspecto más difícil de este tema. En última instancia, la recuperación requiere que el hardware responsable de la recuperación sea al menos funcional. Si el hardware está permanentemente roto (lo que normalmente ocurre después de que su dosis ionizante total alcanza cierto nivel), entonces (lamentablemente) no hay forma de que el software ayude en la recuperación. Por lo tanto, el hardware es, con razón, la preocupación de mayor importancia para un dispositivo expuesto a un alto nivel de radiación (como un satélite).
Además de la sugerencia anterior para anticipar el error del firmware debido a un evento único, también me gustaría sugerirle que tenga:
Algoritmo de detección y/o corrección de errores en el protocolo de comunicación entre subsistemas. Este es otro elemento casi imprescindible para evitar recibir señales incompletas o incorrectas de otros sistemas.
Filtre su lectura de ADC. No utilice la lectura del ADC directamente . Filtrelo por filtro de mediana, filtro de media o cualquier otro filtro; nunca confíe en un solo valor de lectura. Pruebe más, no menos, de forma razonable.
La NASA tiene un artículo sobre software reforzado contra la radiación. Describe tres tareas principales:
- Monitoreo regular de la memoria en busca de errores y luego eliminarlos,
- mecanismos robustos de recuperación de errores, y
- la capacidad de reconfigurarse si algo ya no funciona.
Tenga en cuenta que la velocidad de exploración de la memoria debe ser lo suficientemente frecuente como para que rara vez se produzcan errores de varios bits, ya que la mayoría de la memoria ECC puede recuperarse de errores de un solo bit, no de errores de varios bits.
La recuperación sólida de errores incluye la transferencia del flujo de control (normalmente reiniciar un proceso en un punto anterior al error), la liberación de recursos y la restauración de datos.
Su principal recomendación para la restauración de datos es evitar la necesidad de hacerlo, haciendo que los datos intermedios se traten como temporales, de modo que reiniciar antes del error también revierta los datos a un estado confiable. Esto suena similar al concepto de "transacciones" en las bases de datos.
Discuten técnicas particularmente adecuadas para lenguajes orientados a objetos como C++. Por ejemplo
- ECC basados en software para objetos de memoria contiguos
- Programación por contrato : verificar las condiciones previas y posteriores, luego verificar el objeto para verificar que todavía se encuentra en un estado válido.
Y da la casualidad de que la NASA ha utilizado C++ para proyectos importantes como el Mars Rover .
La abstracción y encapsulación de clases de C++ permitieron un desarrollo y pruebas rápidos entre múltiples proyectos y desarrolladores.
Evitaron ciertas características de C++ que podrían crear problemas:
- Excepciones
- Plantillas
- Iostream (sin consola)
- herencia múltiple
- Sobrecarga del operador (aparte de
new
ydelete
) - Asignación dinámica (se utiliza un grupo de memoria dedicado y una ubicación
new
para evitar la posibilidad de corrupción del montón del sistema).
Aquí hay algunos pensamientos e ideas:
Utilice ROM de forma más creativa.
Guarda todo lo que puedas en ROM. En lugar de calcular cosas, almacene tablas de búsqueda en ROM. (¡Asegúrese de que su compilador envíe sus tablas de búsqueda a la sección de solo lectura! ¡Imprima las direcciones de memoria en tiempo de ejecución para verificar!) Guarde su tabla de vectores de interrupción en la ROM. Por supuesto, realiza algunas pruebas para ver qué tan confiable es tu ROM en comparación con tu RAM.
Utilice su mejor RAM para la pila.
Las SEU en la pila son probablemente la fuente más probable de fallas, porque es donde normalmente se encuentran cosas como variables de índice, variables de estado, direcciones de retorno y punteros de varios tipos.
Implemente rutinas de cronómetro y temporizador de vigilancia.
Puede ejecutar una rutina de "verificación de cordura" cada vez que marca el cronómetro, así como una rutina de vigilancia para manejar el bloqueo del sistema. Su código principal también podría incrementar periódicamente un contador para indicar el progreso, y la rutina de verificación de cordura podría garantizar que esto haya ocurrido.
Implementar códigos de corrección de errores en el software.
Puedes agregar redundancia a tus datos para poder detectar y/o corregir errores. Esto agregará tiempo de procesamiento, lo que potencialmente dejará al procesador expuesto a la radiación durante más tiempo, aumentando así la posibilidad de errores, por lo que debe considerar la compensación.
Recuerda los cachés.
Verifique los tamaños de los cachés de su CPU. Los datos a los que ha accedido o modificado recientemente probablemente estarán en un caché. Creo que puedes desactivar al menos algunos de los cachés (con un gran costo de rendimiento); deberías probar esto para ver qué tan susceptibles son los cachés a los SEU. Si los cachés son más resistentes que la RAM, entonces puede leer y reescribir periódicamente datos críticos para asegurarse de que permanezcan en el caché y volver a poner la RAM en línea.
Utilice hábilmente controladores de errores de página.
Si marca una página de memoria como no presente, la CPU emitirá un error de página cuando intente acceder a ella. Puede crear un controlador de errores de página que realice algunas comprobaciones antes de atender la solicitud de lectura. (Los sistemas operativos de PC utilizan esto para cargar de forma transparente páginas que se han intercambiado en el disco).
Utilice lenguaje ensamblador para cosas críticas (que podrían ser todo).
Con el lenguaje ensamblador, sabes qué hay en los registros y qué hay en la RAM; usted sabe qué tablas de RAM especiales utiliza la CPU y puede diseñar cosas de manera indirecta para mantener bajo el riesgo.
Úselo objdump
para observar realmente el lenguaje ensamblador generado y calcular cuánto código ocupa cada una de sus rutinas.
Si está utilizando un sistema operativo grande como Linux, entonces se está metiendo en problemas; hay tanta complejidad y tantas cosas que pueden salir mal.
Recuerda que es un juego de probabilidades.
Un comentarista dijo
Cada rutina que escriba para detectar errores estará sujeta a fallar por la misma causa.
Si bien esto es cierto, las posibilidades de errores en (digamos) 100 bytes de código y datos necesarios para que una rutina de verificación funcione correctamente son mucho menores que las posibilidades de errores en otros lugares. Si su ROM es bastante confiable y casi todo el código/datos está realmente en la ROM, entonces sus probabilidades son aún mejores.
Utilice hardware redundante.
Utilice 2 o más configuraciones de hardware idénticas con código idéntico. Si los resultados difieren, se debe activar un reinicio. Con 3 o más dispositivos puedes utilizar un sistema de "votación" para intentar identificar cuál ha sido comprometido.
Quizás también le interese la rica literatura sobre el tema de la tolerancia a fallos algorítmicos. Esto incluye la tarea anterior: escribir una clasificación que ordene correctamente su entrada cuando un número constante de comparaciones falle (o, la versión un poco más malvada, cuando el número asintótico de comparaciones fallidas aumente como log(n)
para n
las comparaciones).
Un lugar para comenzar a leer es el artículo de 1984 de Huang y Abraham " Tolerancia a fallos basada en algoritmos para operaciones matriciales ". Su idea es vagamente similar al cálculo cifrado homomórfico (pero en realidad no es lo mismo, ya que están intentando la detección/corrección de errores a nivel de operación).
Un descendiente más reciente de ese artículo es " Tolerancia a fallas basada en algoritmos aplicada a la computación de alto rendimiento " de Bosilca, Delmas, Dongarra y Langou .