it-swarm.com.de

Anwendung zur Verwendung in stark radioaktiven Umgebungen

Wir kompilieren eine eingebettete C/C++ - Anwendung, die in einer abgeschirmten Umgebung in einer Umgebung eingesetzt wird, die mit ionisierender Strahlung bombardiert wird . Wir verwenden GCC und Cross-Compiling für ARM. Bei der Bereitstellung generiert unsere Anwendung einige fehlerhafte Daten und stürzt häufiger ab, als wir möchten. Die Hardware ist für diese Umgebung ausgelegt, und unsere Anwendung läuft seit mehreren Jahren auf dieser Plattform.

Gibt es Änderungen, die wir an unserem Code vornehmen können, oder Verbesserungen bei der Kompilierung, die zum Erkennen/Korrigieren von soft-Fehlern und Speicherbeschädigung durch Einzelereignisstörungen vorgenommen werden können? Haben andere Entwickler die schädlichen Auswirkungen weicher Fehler auf eine langlebige Anwendung reduziert?

1345
rook

Ich arbeite seit ungefähr 4-5 Jahren mit Software-/Firmware-Entwicklung und Umgebungstests von miniaturisierten Satelliten *. Ich möchte meine Erfahrungen hier teilen.

* (miniaturisierte Satelliten sind aufgrund ihrer relativ kleinen, begrenzten Größen für ihre elektronischen Komponenten viel anfälliger für Einzelereignisse als größere Satelliten))

Um es kurz und direkt zu sagen: Es gibt keinen Mechanismus, um sich von erkennbar, fehlerhaft .__ zu erholen. Situation durch die Software/Firmware selbst ohne mindestens eine Kopie von Minimale Arbeitsversion der Software/Firmware irgendwo für Wiederherstellung - und mit Hardware, die die Wiederherstellung unterstützt (funktional).

Nun wird diese Situation normalerweise sowohl auf Hardware- als auch auf Softwareebene behandelt. Auf Ihren Wunsch werde ich Ihnen mitteilen, was wir auf Softwareebene tun können.

  1. ... Wiederherstellungszweck .... Bieten Sie die Möglichkeit, Ihre Software/Firmware in einer realen Umgebung zu aktualisieren, neu zu kompilieren oder erneut zu laden. Dies ist eine fast Muss-Funktion für jede Software/Firmware in stark ionisierter Umgebung. Andernfalls könnten Sie so viele redundante Software/Hardware haben, wie Sie möchten, aber irgendwann werden sie alle explodieren. Also, bereiten Sie diese Funktion vor!

  2. ... Mindestarbeitsversion ... Haben Sie mehrere Kopien, Mindestversion der Software/Firmware in Ihrem Code. Dies ist wie im abgesicherten Modus in Windows. Anstatt nur eine voll funktionsfähige Version Ihrer Software zu haben, müssen Sie mehrere Kopien der Mindestversion Ihrer Software/Firmware haben. Die minimale Kopie hat normalerweise eine viel geringere Größe als die vollständige Kopie und hat fast immer nur die folgenden zwei oder drei Funktionen: 

    1. in der Lage, auf Befehle von einem externen System zu hören, 
    2. fähig, die aktuelle Software/Firmware zu aktualisieren, 
    3. in der Lage, die Housekeeping-Daten des Grundbetriebs zu überwachen.
  3. ... kopieren ... irgendwo ... Haben Sie irgendwo redundante Software/Firmware. 

    1. Sie könnten mit oder ohne redundante Hardware versuchen, redundante Software/Firmware in Ihrem ARM uC zu haben. Dies geschieht normalerweise, indem zwei oder mehr identische Software/Firmware in separaten Adressen vorhanden sind, die den Herzschlag aneinander senden - aber jeweils nur eine aktiv ist. Wenn bekannt ist, dass eine oder mehrere Software/Firmware nicht reagiert, wechseln Sie zur anderen Software/Firmware. Die Verwendung dieses Ansatzes hat den Vorteil, dass der Funktionsaustausch sofort nach Auftreten eines Fehlers erfolgen kann - ohne Kontakt mit dem externen System/der Partei, die dafür verantwortlich ist, den Fehler zu erkennen und zu beheben (im Fall eines Satelliten handelt es sich normalerweise um das Mission Control Center ( MCC)). 

      Streng genommen, ohne redundante Hardware, besteht der Nachteil darin, dass Sie tatsächlich nicht beseitigen können alle Single-Point-of-Failures. Zumindest haben Sie noch one Single Point of Failure, dh der Switch selbst (oder oft der Anfang des Codes). Für ein Gerät, das in einer stark ionisierten Umgebung (z. B. Pico/Femto-Satelliten) nur in begrenztem Umfang verfügbar ist (z. B. Pico/Femtosatelliten), ist die Reduzierung des einzelnen Fehlerpunkts auf einen Punkt ohne zusätzliche Hardware immer noch eine Überlegung wert. Irgendwann wäre der Code für das Wechseln sicherlich viel weniger als der Code für das gesamte Programm - wodurch das Risiko eines Single-Events erheblich verringert wird.

    2. Wenn Sie dies nicht tun, sollten Sie mindestens eine Kopie in Ihrem externen System haben, die mit dem Gerät in Kontakt treten und die Software/Firmware aktualisieren kann (im Fall der Satelliten ist dies wieder die Missionszentrale). 

    3. Sie könnten auch eine Kopie in Ihrem permanenten Speicher auf Ihrem Gerät haben, die zum Wiederherstellen der Software/Firmware des laufenden Systems ausgelöst werden kann
  4. ... fehlerhafte Situation erkennbar. Der Fehler muss erkennbar sein, in der Regel durch die Hardware Fehlerkorrektur/Erkennungsschaltung oder durch einen kleinen Code zur Fehlerkorrektur/Erkennung. Es ist am besten, diesen Code klein, mehrfach und unabhängig von der Hauptsoftware/Firmware zu setzen. Seine Hauptaufgabe ist _ = only zum Überprüfen/Korrigieren. Wenn die Hardwareschaltung/Firmware zuverlässig ist (z. B. strahlungsgehärteter als die Pausen - oder wenn mehrere Schaltungen/Logiken vorhanden sind), sollten Sie möglicherweise eine Fehlerkorrektur in Betracht ziehen. Wenn dies nicht der Fall ist, ist es besser, es als Fehlererkennung zu machen. Die Korrektur kann durch ein externes System/Gerät erfolgen. Für die Fehlerkorrektur können Sie die Verwendung eines grundlegenden Fehlerkorrekturalgorithmus wie Hamming/Golay23 in Betracht ziehen, da sie sowohl in der Schaltung als auch in der Software einfacher implementiert werden können. Dies hängt jedoch letztlich von der Leistungsfähigkeit Ihres Teams ab. Zur Fehlererkennung wird normalerweise CRC verwendet.... Hardware, die die Wiederherstellung unterstützt Nun kommt der schwierigste Aspekt in dieser Angelegenheit. Letztendlich erfordert die Wiederherstellung, dass die Hardware, die für die Wiederherstellung verantwortlich ist, mindestens funktionsfähig ist. Wenn die Hardware dauerhaft beschädigt ist (normalerweise, nachdem ihre Gesamtionisierungsdosis ein bestimmtes Niveau erreicht hat), gibt es (leider) keine Möglichkeit, dass die Software bei der Wiederherstellung hilft. Daher ist Hardware zu Recht die größte Bedeutung für ein Gerät, das einem hohen Strahlungspegel ausgesetzt ist (z. B. Satellit).

  5.  

  1. Filtern Sie in Ihrem ADC-Messwert. Verwenden Sie not das ADC-Lesen direkt. Filtern Sie nach Medianfilter, Mittelwertfilter oder anderen Filtern - never vertrauen auf den einzelnen Lesewert. Probiere mehr, nicht weniger - vernünftig.

  2. Filter in your ADC reading. Do not use the ADC reading directly. Filter it by median filter, mean filter, or any other filters - never trust single reading value. Sample more, not less - reasonably.

759
Ian

Die NASA hat einen Vortrag über strahlungsgehärtete Software. Es beschreibt drei Hauptaufgaben:

  1. Regelmäßiges Überwachen des Speichers auf Fehler, dann Beseitigung dieser Fehler
  2. robuste Fehlerbehebungsmechanismen und
  3. die Fähigkeit, sich neu zu konfigurieren, wenn etwas nicht mehr funktioniert.

Beachten Sie, dass die Speichersuchrate so häufig sein sollte, dass Mehrbitfehler selten auftreten, da die meisten ECC Speicher nach Einzelbitfehlern und nicht nach Multibitfehlern wiederhergestellt werden können.

Die robuste Fehlerbehebung umfasst die Steuerungsflussübertragung (in der Regel einen Neustart eines Prozesses vor dem Fehler), die Ressourcenfreigabe und die Datenwiederherstellung.

Ihre Hauptempfehlung für die Wiederherstellung von Daten besteht darin, die Notwendigkeit zu vermeiden, dass Zwischendaten als temporär behandelt werden, sodass ein Neustart vor dem Fehler auch die Daten in einen zuverlässigen Zustand zurückführt. Dies klingt ähnlich wie das Konzept von "Transaktionen" in Datenbanken.

Sie diskutieren Techniken, die sich besonders für objektorientierte Sprachen wie C++ eignen. Zum Beispiel

  1. Softwarebasierte ECCs für zusammenhängende Speicherobjekte
  2. Programmieren nach Vertrag : Überprüfen von Vorbedingungen und Nachbedingungen, dann Prüfen des Objekts, um zu überprüfen, ob es sich noch in einem gültigen Zustand befindet.

Und es ist einfach so, dass die NASA C++ für Großprojekte wie den Mars Rover verwendet hat.

Die Abstraktion und Einkapselung von C++ - Klassen ermöglichte eine schnelle Entwicklung und Prüfung zwischen mehreren Projekten und Entwicklern.

Sie vermieden bestimmte C++ - Funktionen, die Probleme verursachen könnten:

  1. Ausnahmen
  2. Vorlagen
  3. Iostream (keine Konsole)
  4. Mehrfachvererbung
  5. Überladen des Operators (außer new und delete)
  6. Dynamische Zuordnung (verwendet einen dedizierten Speicherpool und Platzierung new, um die Möglichkeit einer Beschädigung des Systemheap zu vermeiden).
381
rsjaffe

Hier sind einige Gedanken und Ideen:

Verwenden Sie ROM kreativer.

Speichern Sie alles, was Sie können, im ROM. Speichern Sie die Nachschlagetabellen im ROM, anstatt sie zu berechnen. (Stellen Sie sicher, dass Ihr Compiler Ihre Nachschlagetabellen in den Nur-Lese-Bereich ausgibt. Drucken Sie die Speicheradressen zur Laufzeit aus, um dies zu überprüfen.) Speichern Sie Ihre Interrupt-Vektortabelle im ROM. Führen Sie natürlich einige Tests durch, um festzustellen, wie zuverlässig Ihr ROM mit Ihrem RAM verglichen wird.

Verwenden Sie Ihr Bestes RAM für den Stapel.

SEUs im Stack sind wahrscheinlich die wahrscheinlichste Absturzquelle, da dort normalerweise Indexvariablen, Statusvariablen, Rückgabeadressen und Zeiger verschiedener Art vorkommen.

Implementieren Sie Timer-Tick- und Watchdog-Timer-Routinen.

Sie können bei jedem Zeitgeber-Tick eine Routine zur Überprüfung der Systemintegrität sowie eine Watchdog-Routine ausführen, um die Systemblockierung zu handhaben. Ihr Hauptcode könnte auch einen Zähler in regelmäßigen Abständen erhöhen, um den Fortschritt anzuzeigen, und die Routine zur Überprüfung der Gesundheit könnte sicherstellen, dass dies geschehen ist.

Implementiere Fehlerkorrektur-Codes in Software.

Sie können Ihren Daten Redundanz hinzufügen, um Fehler zu erkennen und/oder zu korrigieren. Dadurch wird die Verarbeitungszeit verlängert und der Prozessor möglicherweise für längere Zeit der Strahlung ausgesetzt, wodurch sich die Wahrscheinlichkeit von Fehlern erhöht. Daher müssen Sie den Kompromiss in Betracht ziehen.

Erinnere dich an die Caches.

Überprüfen Sie die Größe Ihrer CPU-Caches. Daten, auf die Sie in letzter Zeit zugegriffen oder die Sie geändert haben, befinden sich wahrscheinlich in einem Cache. Ich glaube, Sie können zumindest einige der Caches deaktivieren (mit einem hohen Leistungsaufwand). Sie sollten dies versuchen, um zu sehen, wie anfällig die Caches für SEUs sind. Wenn die Caches härter als RAM sind, können Sie regelmäßig wichtige Daten lesen und neu schreiben, um sicherzustellen, dass sie im Cache bleiben, und RAM wieder in Einklang bringen.

Verwenden Sie Seitenfehlerbehandlungsroutinen geschickt.

Wenn Sie eine Speicherseite als nicht vorhanden markieren, gibt die CPU einen Seitenfehler aus, wenn Sie versuchen, darauf zuzugreifen. Sie können einen Seitenfehlerhandler erstellen, der einige Überprüfungen durchführt, bevor die Leseanforderung bearbeitet wird. (PC-Betriebssysteme verwenden dies, um Seiten, die auf die Festplatte ausgelagert wurden, transparent zu laden.)

Verwenden Sie die Assembler-Sprache für wichtige Dinge (die alles sein können).

Mit der Assemblersprache können Sie wissen was in Registern und was im RAM ist; Sie wissen welche speziellen RAM -Tabellen die CPU verwendet, und Sie können Dinge auf Umwegen entwerfen, um Ihr Risiko gering zu halten.

Verwenden Sie objdump, um sich die generierte Assembler-Sprache anzusehen und herauszufinden, wie viel Code jede Ihrer Routinen in Anspruch nimmt.

Wenn Sie ein großes Betriebssystem wie Linux verwenden, fragen Sie nach Problemen. Es gibt einfach so viel Komplexität und so viele Dinge, die schief gehen.

Denken Sie daran, es ist ein Spiel der Wahrscheinlichkeiten.

Ein Kommentator sagte

Jede Routine, die Sie zum Abfangen von Fehlern schreiben, kann aus derselben Ursache fehlschlagen.

Während dies zutrifft, ist die Wahrscheinlichkeit von Fehlern in den (sagen wir) 100 Byte Code und Daten, die erforderlich sind, damit eine Prüfroutine richtig funktioniert, viel geringer als die Wahrscheinlichkeit von Fehlern an anderer Stelle. Wenn Ihr ROM ist ziemlich zuverlässig und fast der gesamte Code/die gesamten Daten sind tatsächlich in ROM dann sind Ihre Chancen noch besser.

Verwenden Sie redundante Hardware.

Verwenden Sie mindestens zwei identische Hardware-Setups mit identischem Code. Bei abweichenden Ergebnissen sollte ein Reset ausgelöst werden. Bei 3 oder mehr Geräten können Sie mithilfe eines "Abstimmungssystems" versuchen, zu identifizieren, welches Gerät kompromittiert wurde.

115
Artelius

Möglicherweise interessieren Sie sich auch für die umfangreiche Literatur zum Thema algorithmische Fehlertoleranz. Dazu gehört die alte Zuweisung: Schreiben Sie eine Sortierung, die ihre Eingabe korrekt sortiert, wenn eine konstante Anzahl von Vergleichen fehlschlägt (oder die etwas schlechtere Version, wenn die asymptotische Anzahl von fehlgeschlagenen Vergleichen als log(n) für n Vergleiche skaliert).

Ein Ort, an dem man mit dem Lesen beginnen kann, ist die Arbeit von Huang und Abraham von 1984 " Algorithmusbasierte Fehlertoleranz für Matrixoperationen ". Ihre Idee ist der homomorphen, verschlüsselten Berechnung ein wenig ähnlich (aber sie ist nicht wirklich die gleiche, da sie versuchen, eine Fehlererkennung korrektur auf Betriebsebene durchzuführen).

Ein neuerer Nachkomme dieses Papiers ist Bosilca, Delmas, Dongarra und Langou's "/ - Algorithmus-basierte Fehlertoleranz für das Hochleistungs-Computing ".

96
Eric Towers

Das Schreiben von Code für radioaktive Umgebungen unterscheidet sich nicht wirklich vom Schreiben von Code für geschäftskritische Anwendungen. 

Hier finden Sie neben den bereits erwähnten Tipps einige weitere Tipps:

  • Verwenden Sie die alltäglichen Sicherheitsvorkehrungen "Brot und Butter", die bei jedem semiprofessionellen Embedded-System vorhanden sein sollten: interner Watchdog, interner Unterspannungsdetektor, interner Uhrmonitor. Diese Dinge sollten im Jahr 2016 nicht einmal erwähnt werden und sind bei fast jedem modernen Mikrocontroller Standard.
  • Wenn Sie über eine sicherheits- und/oder automobilorientierte MCU verfügen, verfügt diese über bestimmte Watchdog-Funktionen, z. B. ein bestimmtes Zeitfenster, in dem Sie den Watchdog aktualisieren müssen. Dies wird bevorzugt, wenn Sie ein geschäftskritisches Echtzeitsystem haben.
  • Verwenden Sie im Allgemeinen eine MCU, die für diese Art von Systemen geeignet ist, und nicht einige allgemeine Flusen, die Sie in einer Packung Cornflakes erhalten haben. Nahezu jeder Hersteller von MCUs verfügt heute über spezielle MCUs für Sicherheitsanwendungen (TI, Freescale, Renesas, ST, Infineon usw.). Diese verfügen über zahlreiche integrierte Sicherheitsfunktionen, einschließlich Lock-Step-Cores: Dies bedeutet, dass zwei CPU-Cores denselben Code ausführen und miteinander übereinstimmen müssen.
  • WICHTIG: Sie müssen die Integrität der internen MCU-Register sicherstellen. Alle Steuer- und Statusregister von Hardware-Peripheriegeräten, die beschreibbar sind, können sich im RAM Speicher befinden und sind daher anfällig. 

    Um sich vor Registerverfälschungen zu schützen, sollten Sie sich vorzugsweise einen Mikrocontroller mit integrierten "einmal beschreibbaren" Registereigenschaften aussuchen. Außerdem müssen Sie die Standardwerte aller Hardwareregister in NVM speichern und diese Werte in regelmäßigen Abständen in Ihre Register kopieren. Sie können die Integrität wichtiger Variablen auf dieselbe Weise sicherstellen.

    Hinweis: Verwenden Sie immer eine defensive Programmierung. Dies bedeutet, dass Sie all -Register in der MCU einrichten müssen und nicht nur die, die von der Anwendung verwendet werden. Sie möchten nicht, dass ein beliebiges Hardware-Peripheriegerät plötzlich aufwacht.

  • Es gibt alle möglichen Methoden, um Fehler in RAM oder NVM zu überprüfen: Prüfsummen, "Laufmuster", Software-ECC usw. Die beste Lösung heutzutage ist, keine dieser Methoden zu verwenden, sondern eine MCU zu verwenden mit eingebautem ECC und ähnlichen Prüfungen. Da dies in Software sehr komplex ist, könnte die Fehlerprüfung an sich Fehler und unerwartete Probleme verursachen.

  • Verwenden Sie Redundanz. Sie können sowohl flüchtigen als auch nichtflüchtigen Speicher in zwei identischen "Spiegel" -Segmenten speichern, die immer gleichwertig sein müssen. Jedes Segment könnte eine CRC-Prüfsumme enthalten.
  • Vermeiden Sie die Verwendung externer Speicher außerhalb der MCU.
  • Implementieren Sie eine Standard-Interrupt-Serviceroutine/einen Standard-Ausnahmehandler für alle möglichen Interrupts/Ausnahmen. Sogar die, die Sie nicht verwenden. Die Standardroutine sollte nichts anderes tun, als ihre eigene Interruptquelle abzuschalten.
  • Das Konzept der defensiven Programmierung verstehen und annehmen. Das bedeutet, dass Ihr Programm alle möglichen Fälle behandeln muss, auch solche, die theoretisch nicht möglich sind. Beispiele

    Die unternehmenskritische Firmware von hoher Qualität erkennt so viele Fehler wie möglich und ignoriert sie auf sichere Weise.

  • Schreiben Sie niemals Programme, die auf schlecht angegebenes Verhalten angewiesen sind. Es ist wahrscheinlich, dass sich dieses Verhalten bei unerwarteten Hardwareänderungen aufgrund von Strahlung oder EMI drastisch ändern kann. Der beste Weg, um sicherzustellen, dass Ihr Programm keinen solchen Mist enthält, ist die Verwendung eines Kodierungsstandards wie MISRA zusammen mit einem statischen Analysegerät. Dies hilft auch bei der defensiven Programmierung und bei der Beseitigung von Fehlern (warum sollten Sie keine Fehler in irgendeiner Art von Anwendung entdecken wollen?).
  • WICHTIG: Implementieren Sie keine Abhängigkeit von den Standardwerten der Variablen für die statische Speicherdauer. Das heißt, vertrauen Sie nicht dem Standardinhalt von .data oder .bss. Zwischen dem Zeitpunkt der Initialisierung und dem Zeitpunkt, an dem die Variable tatsächlich verwendet wird, kann eine gewisse Zeit vergehen, und es könnte ausreichend Zeit für das RAM gewesen sein, um beschädigt zu werden. Schreiben Sie das Programm stattdessen so, dass alle derartigen Variablen zur Laufzeit von NVM festgelegt werden, unmittelbar vor dem Zeitpunkt, zu dem eine solche Variable zum ersten Mal verwendet wird. 

    In der Praxis bedeutet dies, dass, wenn eine Variable im Dateibereich oder als static deklariert ist, niemals = zum Initialisieren verwendet werden sollte (oder Sie könnten, aber es ist sinnlos, da Sie sich ohnehin nicht auf den Wert verlassen können). Stellen Sie es immer zur Laufzeit ein, kurz vor der Verwendung. Wenn es möglich ist, solche Variablen wiederholt von NVM zu aktualisieren, tun Sie dies.

    Verlassen Sie sich in C++ ebenfalls nicht auf Konstruktoren für Variablen mit statischer Speicherdauer. Lassen Sie den Konstruktor bzw. die Konstruktoren eine öffentliche "Setup-Routine" aufrufen, die Sie später auch zur Laufzeit direkt von der Aufruferanwendung aus aufrufen können.Entfernen Sie nach Möglichkeit den Startcode "copy-down", der .data und .bss (und C++ - Konstruktoren) vollständig initialisiert, sodass Linker-Fehler auftreten, wenn Sie Code schreiben, der auf solchen Code basiert. Viele Compiler haben die Möglichkeit, dies zu überspringen, normalerweise als "minimaler/schneller Start" oder ähnliches.

    Dies bedeutet, dass alle externen Bibliotheken überprüft werden müssen, damit sie nicht so zuverlässig sind.

    .

  • Die Implementierung eines Fehlerbericht-/Fehlerprotokollsystems ist immer hilfreich. 

  • Implementing an error report/error log system is always helpful.
38
Lundin

Es ist möglicherweise möglich, C zu verwenden, um Programme zu schreiben, die sich in solchen Umgebungen robust verhalten, jedoch nur, wenn die meisten Formen der Compileroptimierung deaktiviert sind. Optimierende Compiler ersetzen viele scheinbar redundante Codierungsmuster durch "effizientere" Codierungsmuster und haben möglicherweise keine Ahnung, dass der Programmierer x==42 testet, wenn der Compiler weiß, dass x keine andere Möglichkeit hat, weil der Programmierer dies will Die Ausführung eines bestimmten Codes mit x zu verhindern, der einen anderen Wert enthält - selbst in Fällen, in denen er diesen Wert nur halten könnte, wenn das System eine Art elektrischen Störimpuls erhält.

Das Deklarieren von Variablen als volatile ist häufig hilfreich, stellt jedoch möglicherweise kein Allheilmittel dar. Beachten Sie, dass für die sichere Codierung gefährliche .__-Vorgänge häufig Hardware-Interlocks erfordern, die zum Aktivieren von Und diesem Code mehrere Schritte erfordern mit dem Muster geschrieben werden:

... 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();

Wenn ein Compiler den Code relativ wörtlich übersetzt, und wenn alle Die Systemstatusprüfungen nach der prepare_for_activation(), Wiederholt werden, ist das System möglicherweise gegen nahezu alle plausiblen einzelnen Störimpulsereignisse robust würde den Programmzähler und -stapel willkürlich beschädigen. Wenn Nach dem Aufruf von prepare_for_activation() ein Störimpuls auftritt, würde dies bedeuten, dass die Aktivierung angemessen gewesen wäre (da es keinen anderen Grund gibt, vor dem der Störungsfaktor prepare_for_activation() aufgerufen wurde). Wenn durch den Glitch prepare_for_activation() unangemessener Code erreicht wird, jedoch ___ keine nachfolgenden Glitch-Ereignisse vorhanden sind, besteht keine Möglichkeit, dass Code anschließend trigger_activation() erreicht werden kann, ohne die Validierungsprüfung durchlaufen zu haben. Wenn der Stack Probleme bereitet, kann die Ausführung an einen Punkt unmittelbar vor trigger_activation() übergehen, nachdem der Kontext, in dem prepare_for_activation() aufgerufen wurde, wieder aufgerufen wird. Der Aufruf von cancel_preparations() wäre jedoch zwischen den Aufrufen von prepare_for_activation() und trigger_activation() aufgetreten, wodurch der letztere Aufruf harmlos wird.

Ein solcher Code kann in herkömmlichen C-Codes sicher sein, nicht jedoch in modernen C-Compilern. Solche Compiler können in einer solchen Umgebung sehr gefährlich sein, da sie aggressiv nur Code einschließen möchten, der in Situationen relevant ist, die über einen genau definierten Mechanismus zustande kommen könnten und deren Folgen ebenfalls gut definiert wären. Code, dessen Zweck darin besteht, nach Fehlern zu erkennen und zu bereinigen, kann in einigen Fällen die Situation verschlimmern. Wenn der Compiler feststellt, dass der versuchte Wiederherstellungsvorgang in einigen Fällen undefiniertes Verhalten hervorrufen würde, kann daraus geschlossen werden, dass die Bedingungen, die eine solche Wiederherstellung in solchen Fällen erforderlich machen würden, möglicherweise nicht auftreten können, wodurch der Code eliminiert wird, der für sie geprüft worden wäre.

31
supercat

Was Ihnen helfen könnte, ist ein Watchdog . In den 80er Jahren wurden Wachhunde häufig im industriellen Computing eingesetzt. Hardwarefehler waren dann viel häufiger - eine andere Antwort bezieht sich auch auf diesen Zeitraum.

Ein Watchdog ist eine kombinierte Hardware-/Software-Funktion. Die Hardware ist ein einfacher Zähler, der von einer Zahl (z. B. 1023) auf Null herunterzählt. TTL oder eine andere Logik könnte verwendet werden.

Die Software wurde so konzipiert, dass eine Routine den korrekten Betrieb aller wichtigen Systeme überwacht. Wenn diese Routine korrekt ausgeführt wird = den Computer fehlerfrei ausführt, wird der Zähler auf 1023 zurückgesetzt.

Der Gesamtaufbau ist so, dass die Software unter normalen Umständen verhindert, dass der Hardwarezähler den Wert Null erreicht. Wenn der Zähler Null erreicht, führt die Hardware des Zählers seine einzige Aufgabe aus und setzt das gesamte System zurück. Aus Sicht des Zählers ist Null gleich 1024 und der Zähler zählt weiter abwärts.

Dieser Watchdog stellt sicher, dass der angeschlossene Computer in vielen, vielen Fällen eines Fehlers neu gestartet wird. Ich muss zugeben, dass ich nicht mit Hardware vertraut bin, die eine solche Funktion auf heutigen Computern ausführen kann. Schnittstellen zu externer Hardware sind jetzt viel komplexer als früher.

Ein inhärenter Nachteil des Watchdog ist, dass das System nicht verfügbar ist, wenn es ausfällt, bis der Watchdog-Zähler den Wert 0 und die Neustartzeit erreicht. Während diese Zeit im Allgemeinen viel kürzer ist als bei einem Eingriff von außen oder von Menschen, müssen die unterstützten Geräte in der Lage sein, für diesen Zeitraum ohne Computersteuerung vorzugehen.

27
OldFrank

Dies ist ein extrem breites Thema. Grundsätzlich können Sie sich nicht wirklich von Speicherbeschädigungen erholen, aber Sie können zumindest versuchen, prompt auszulösen . Hier sind ein paar Techniken, die Sie verwenden könnten:

  • Prüfsummenkonstante Daten . Wenn Sie Konfigurationsdaten haben, die lange Zeit konstant bleiben (einschließlich der von Ihnen konfigurierten Hardware-Register), berechnen Sie die Prüfsumme bei der Initialisierung und überprüfen Sie diese regelmäßig. Wenn Sie eine Nichtübereinstimmung sehen, ist es Zeit, die Daten neu zu initialisieren oder zurückzusetzen.

  • Variablen mit Redundanz speichern . Wenn Sie eine wichtige Variable x haben, schreiben Sie ihren Wert in x1, x2 und x3 und lesen Sie ihn als (x1 == x2) ? x2 : x3.

  • implementieren Programmablaufüberwachung . XOR ein globales Flag mit einem eindeutigen Wert in wichtigen Funktionen/Zweigen, das von der Hauptschleife aus aufgerufen wird. Wenn Sie das Programm in einer strahlungsfreien Umgebung mit einer Testabdeckung von nahezu 100% ausführen, sollten Sie am Ende des Zyklus eine Liste der akzeptablen Werte der Flagge erhalten. Zurücksetzen, wenn Sie Abweichungen sehen.

  • den Stapelzeiger überwachen . Vergleichen Sie zu Beginn der Hauptschleife den Stapelzeiger mit dem erwarteten Wert. Bei Abweichung zurücksetzen.

27

In dieser Antwort wird davon ausgegangen, dass Sie ein System benötigen, das ordnungsgemäß funktioniert, und darüber hinaus ein System, das nur minimale Kosten verursacht oder schnell ist. Die meisten Leute, die mit radioaktiven Dingen spielen, legen Wert auf Korrektheit/Sicherheit gegenüber Geschwindigkeit/Kosten

Einige Leute haben Hardware-Änderungen vorgeschlagen, die Sie vornehmen können (in Ordnung - es gibt bereits viele gute Antworten, und ich habe nicht die Absicht, alles zu wiederholen), und andere haben Redundanz vorgeschlagen (im Prinzip großartig), aber ich glaube nicht Jeder hat vorgeschlagen, wie diese Redundanz in der Praxis funktionieren könnte. Wie scheitern Sie? Woher weißt du, wenn etwas schief gelaufen ist? Viele Technologien arbeiten auf der Basis, dass alles funktionieren wird, und ein Misserfolg ist daher eine schwierige Sache. Einige verteilte Computertechnologien, die auf Skalierung ausgelegt sind , erwarten jedoch einen Ausfall (schließlich ist bei ausreichender Skalierung der Ausfall eines Knotens von vielen bei jedem MTBF für einen einzelnen Knoten); Sie können dies für Ihre Umgebung nutzen.

Hier sind ein paar Ideen:

  • Stellen Sie sicher, dass Ihre gesamte Hardware n Mal repliziert wird (wobei n größer als 2 und vorzugsweise ungerade ist) und dass jedes Hardwareelement mit jedem anderen Hardwareelement kommunizieren kann. Ethernet ist ein offensichtlicher Weg, dies zu tun, aber es gibt viele andere weitaus einfachere Routen, die einen besseren Schutz bieten (z. B. CAN). Minimieren Sie gemeinsame Komponenten (auch Netzteile). Dies kann beispielsweise das Abtasten von ADC-Eingängen an mehreren Stellen bedeuten.

  • Stellen Sie sicher, dass sich Ihr Anwendungsstatus an einem einzigen Ort befindet, z. in einer endlichen Zustandsmaschine. Dies kann vollständig auf RAM basieren, schließt jedoch eine stabile Speicherung nicht aus. Es wird also an mehreren Orten aufbewahrt.

  • Verabschiedung eines Quorum-Protokolls für Zustandsänderungen. Siehe zum Beispiel RAFT . Da Sie in C++ arbeiten, gibt es dafür bekannte Bibliotheken. Änderungen am FSM würden nur vorgenommen, wenn die Mehrheit der Knoten zustimmt. Verwenden Sie eine als funktionierend bekannte Bibliothek für den Protokollstapel und das Quorumprotokoll, anstatt selbst eine zu erstellen. Andernfalls wird Ihre gesamte Arbeit an der Redundanz verschwendet, wenn das Quorumprotokoll auflegt.

  • Stellen Sie sicher, dass Sie Ihre FSM mit einer Prüfsumme (z. B. CRC/SHA) versehen und die CRC/SHA in der FSM selbst speichern (sowie in der Nachricht übertragen und die Nachrichten selbst mit einer Prüfsumme versehen). Fordern Sie die Knoten auf, ihren FSM regelmäßig anhand dieser Prüfsumme zu überprüfen, eingehende Nachrichten zu prüfen und zu überprüfen, ob ihre Prüfsumme mit der Prüfsumme des Quorums übereinstimmt.

  • Bauen Sie so viele interne Überprüfungen wie möglich in Ihr System ein, sodass Knoten, die ihren eigenen Fehler feststellen, neu gestartet werden (dies ist besser, als die Hälfte der Arbeit fortzusetzen, vorausgesetzt, Sie haben genügend Knoten). Versuchen Sie, sie beim Neustart sauber aus dem Quorum entfernen zu lassen, falls sie nicht wieder auftauchen. Lassen Sie sie beim Neustart das Software-Image (und alles andere, was sie laden) prüfen und einen vollständigen RAM Test durchführen, bevor sie sich wieder dem Quorum unterziehen.

  • Verwenden Sie Hardware, um Sie zu unterstützen, aber tun Sie dies vorsichtig. Sie können beispielsweise ECC-RAM abrufen und regelmäßig lesen/schreiben, um ECC-Fehler zu korrigieren (und in Panik zu geraten, wenn der Fehler nicht korrigierbar ist). Jedoch (aus dem Speicher) ist statisch RAM gegenüber ionisierender Strahlung weitaus toleranter als DRAM an erster Stelle, so dass es sein kann Verwenden Sie stattdessen lieber statischen DRAM. Siehe auch den ersten Punkt unter "Dinge, die ich nicht tun würde".

Angenommen, Sie haben eine 1% ige Ausfallwahrscheinlichkeit für einen bestimmten Knoten innerhalb eines Tages und tun so, als könnten Sie Fehler völlig unabhängig machen. Bei 5 Knoten müssen drei innerhalb eines Tages ausfallen, was einer Wahrscheinlichkeit von 0,00001% entspricht. Mit more kommt man auf die Idee.

Dinge, die ich nicht tun würde :

  • Unterschätzen Sie den Wert, dass Sie nicht das Problem haben, mit dem Sie beginnen sollen. Wenn das Gewicht keine Rolle spielt, wird ein großer Metallblock um Ihr Gerät herum ein Eine weitaus billigere und zuverlässigere Lösung als ein Team von Programmierern. Das Gleiche gilt für die optische Kopplung von EMI-Eingängen usw. Versuchen Sie auf jeden Fall, bei der Beschaffung Ihrer Komponenten die Komponenten zu verwenden, die gegen ionisierende Strahlung am besten geeignet sind.

  • Rollen Sie Ihre eigenen Algorithmen . Leute haben das schon mal gemacht. Nutzen Sie ihre Arbeit. Fehlertoleranz und verteilte Algorithmen sind schwierig. Verwenden Sie die Arbeit anderer Leute, wo immer dies möglich ist.

  • Verwenden Sie komplizierte Compilereinstellungen in der naiven Hoffnung, dass Sie mehr Fehler entdecken. Wenn Sie Glück haben, können Sie mehr Fehler entdecken. Wahrscheinlicher ist, dass Sie einen Codepfad innerhalb des Compilers verwenden, der weniger getestet wurde, insbesondere wenn Sie ihn selbst gerollt haben.

  • Verwenden Sie Techniken, die in Ihrer Umgebung nicht getestet wurden. Die meisten Leute, die Hochverfügbarkeitssoftware schreiben, müssen Fehlermodi simulieren, um zu überprüfen, ob ihre HA korrekt funktioniert, und viele Fehlermodi verpassen als Ergebnis. Sie sind in der glücklichen Lage, häufige Ausfälle auf Abruf zu haben. Testen Sie also jede Technik und stellen Sie sicher, dass ihre Anwendung die MTBF tatsächlich um einen Betrag verbessert, der die Komplexität übersteigt, um sie einzuführen (mit der Komplexität kommen Fehler). Wenden Sie dies insbesondere auf meine Ratschläge zu Quorum-Algorithmen usw. an.

23
abligh

Da Sie speziell nach Softwarelösungen fragen und C++ verwenden, sollten Sie die Operator-Überladung verwenden, um eigene sichere Datentypen zu erstellen. Zum Beispiel:

Erstellen Sie statt uint32_t (und double, int64_t etc) Ihren eigenen SAFE_uint32_t, der ein Vielfaches (mindestens 3) von uint32_t enthält. Überladen Sie alle Operationen, die Sie ausführen möchten (* + -/<< >> = ==! = Etc), und lassen Sie die überladenen Operationen für jeden internen Wert unabhängig ausführen, dh führen Sie das Ergebnis nicht einmal aus und kopieren Sie das Ergebnis. Überprüfen Sie vor und nach, ob alle internen Werte übereinstimmen. Wenn die Werte nicht übereinstimmen, können Sie den falschen Wert auf den Wert mit dem häufigsten Wert aktualisieren. Wenn kein allgemeiner Wert vorhanden ist, können Sie sicher benachrichtigen, dass ein Fehler vorliegt.

Auf diese Weise ist es egal, ob in der ALU, in Registern, im RAM oder in einem Bus eine Beschädigung auftritt. Sie haben immer noch mehrere Versuche und eine sehr gute Chance, Fehler zu erkennen. Beachten Sie jedoch, dass dies nur für die Variablen funktioniert, die Sie ersetzen können. Beispielsweise ist Ihr Stapelzeiger noch anfällig.

Eine Nebengeschichte: Ich bin auf eine ähnliche Ausgabe gestoßen, auch auf einem alten ARM -Chip. Es stellte sich heraus, dass es sich um eine Toolchain handelte, die eine alte Version von GCC verwendete, die zusammen mit dem von uns verwendeten Chip in bestimmten Edge-Fällen einen Fehler auslöste, der (manchmal) beschädigte Werte an Funktionen übergeben würde. Stellen Sie sicher, dass Ihr Gerät keine Probleme hat, bevor Sie es auf Radioaktivität hinweisen, und ja, manchmal handelt es sich um einen Compiler-Fehler =)

22
jkflying

Haftungsausschluss: Ich bin kein Experte für Radioaktivität und arbeite auch nicht für diese Art von Anwendung. Aber ich habe an weichen Fehlern und Redundanz für die Langzeitarchivierung kritischer Daten gearbeitet, die in gewissem Zusammenhang stehen (dasselbe Problem, unterschiedliche Ziele).

Das Hauptproblem bei der Radioaktivität ist meiner Meinung nach, dass Radioaktivität Bits wechseln kann, sodass Radioaktivität jeden digitalen Speicher manipulieren kann/wird . Diese Fehler werden normalerweise als weiche Fehler , Bit Rot usw. bezeichnet.

Die Frage ist dann: Wie kann man zuverlässig rechnen, wenn der Speicher unzuverlässig ist?

Um die Häufigkeit von Softwarefehlern erheblich zu reduzieren (auf Kosten des Rechenaufwands, da es sich meist um softwarebasierte Lösungen handelt), können Sie entweder:

  • verlassen Sie sich auf das gute alte Redundanzschema und genauer gesagt auf das effizientere - Fehlerkorrekturcodes (gleicher Zweck, aber cleverere Algorithmen, damit Sie mehr Bits mit weniger Redundanz wiederherstellen können). Dies wird manchmal (fälschlicherweise) auch als Prüfsumme bezeichnet. Bei dieser Art von Lösung müssen Sie den vollständigen Status Ihres Programms jederzeit in einer Hauptvariablen/-klasse (oder einer Struktur?) Speichern, einen ECC berechnen und prüfen, ob der ECC korrekt ist, bevor Sie etwas unternehmen nicht reparieren Sie die Felder. Diese Lösung garantiert jedoch nicht, dass Ihre Software funktioniert (einfach, dass sie ordnungsgemäß funktioniert, wenn dies möglich ist, oder wenn dies nicht möglich ist, funktioniert sie nicht mehr, da ECC Ihnen mitteilen kann, ob ein Fehler vorliegt. In diesem Fall können Sie Ihre Software anhalten, damit Sie dies tun können keine falschen Ergebnisse erhalten).

  • oder Sie können ausfallsichere algorithmische Datenstrukturen verwenden, die bis zu einem gewissen Grad garantieren, dass Ihr Programm auch in Gegenwart von soft noch korrekte Ergebnisse liefert fehler. Diese Algorithmen können als Mischung gängiger algorithmischer Strukturen mit eingebauten ECC-Schemata betrachtet werden. Dies ist jedoch weitaus widerstandsfähiger, da das Ausfallsicherheitsschema eng an die Struktur gebunden ist, sodass Sie keine zusätzlichen Prozeduren codieren müssen ECC zu überprüfen, und in der Regel sind sie viel schneller. Diese Strukturen bieten eine Möglichkeit, um sicherzustellen, dass Ihr Programm unter allen Bedingungen bis zur theoretischen Grenze von weichen Fehlern funktioniert. Sie können diese ausfallsicheren Strukturen auch mit dem Redundanz-/ECC-Schema für zusätzliche Sicherheit mischen (oder Ihre wichtigsten Datenstrukturen als ausfallsichere Daten codieren, und den Rest der aus den Hauptdatenstrukturen neu zu berechnenden Daten als normale Datenstrukturen mit a Bit von ECC oder eine Paritätsprüfung, die sehr schnell zu berechnen ist).

Wenn Sie an stabilen Datenstrukturen interessiert sind (ein neues, aber aufregendes Feld in der Algorithmus- und Redundanztechnik), empfehle ich Ihnen, die folgenden Dokumente zu lesen:

  • Resilient algorithms data structures intro von Giuseppe F. Italiano, Universität Rom "Tor Vergata"

  • Christiano, P., Demaine, E. D. & Kishore, S. (2011). Verlustfreie fehlertolerante Datenstrukturen mit additivem Overhead. In Algorithmen und Datenstrukturen (S. 243-254). Springer Berlin Heidelberg.

  • Ferraro-Petrillo, U., Grandoni, F. & amp; Italiano, G. F. (2013). Gegen Speicherfehler resistente Datenstrukturen: eine experimentelle Untersuchung von Wörterbüchern. Journal of Experimental Algorithmics (JEA), 18, 1-6.

  • Italiano, G. F. (2010). Ausfallsichere Algorithmen und Datenstrukturen. In Algorithmen und Komplexität (S. 13-24). Springer Berlin Heidelberg.

Wenn Sie mehr über das Gebiet der belastbaren Datenstrukturen erfahren möchten, können Sie die Werke von Giuseppe F. Italiano (und sich durch die Referenzen arbeiten) und Fehlerhaftes RAM-Modell (eingeführt in Finocchi et al. 2005; Finocchi und Italiano 2008).

/ EDIT: Ich habe das Verhindern/Wiederherstellen von Softwarefehlern hauptsächlich für RAM Speicher und Datenspeicher) illustriert, aber ich habe nicht über Berechnung (CPU) gesprochen. Fehler . Andere Antworten wiesen bereits auf die Verwendung atomarer Transaktionen wie in Datenbanken hin, daher werde ich ein anderes, einfacheres Schema vorschlagen: Redundanz und Mehrheitsabstimmung .

Die Idee ist, dass Sie einfach x-mal die gleiche Berechnung für jede Berechnung durchführen, die Sie durchführen müssen, und das Ergebnis in x verschiedenen Variablen speichern (mit x>) = 3). Sie können dann Ihre x Variablen vergleichen :

  • wenn alle übereinstimmen, liegt überhaupt kein Rechenfehler vor.
  • wenn sie nicht übereinstimmen, können Sie mit der Mehrheit abstimmen, um den korrekten Wert zu erhalten. Da dies bedeutet, dass die Berechnung teilweise fehlerhaft war, können Sie auch einen System-/Programmstatus-Scan auslösen, um zu überprüfen, ob der Rest in Ordnung ist.
  • wenn die Mehrheitsentscheidung keinen Gewinner ermitteln kann (alle x-Werte sind unterschiedlich), ist dies ein perfektes Signal für Sie, um die Ausfallsicherungsprozedur auszulösen (Neustart, Alarmierung des Benutzers usw.).

Dieses Redundanzschema ist sehr schnell im Vergleich zu ECC (praktisch O(1)) und bietet Ihnen eine Klares Signal , wenn Sie ausfallsicher sein müssen ) garantiert keine fehlerhafte Ausgabe zu erzeugen und auch kleinere Rechenfehler zu beheben , da die Wahrscheinlichkeit, dass x-Berechnungen die gleiche Ausgabe ergeben, unendlich klein ist (da es eine große Menge möglicher Ausgaben gibt, ist es fast unmöglich, zufällig das Dreifache derselben zu erhalten, noch weniger Chancen, wenn x> 3 ist).

Mit der Mehrheitswahl sind Sie also vor fehlerhafter Ausgabe geschützt, und mit Redundanz x == 3 können Sie 1 Fehler beheben (mit x == 4 können 2 Fehler behoben werden usw. - die genaue Gleichung lautet nb_error_recoverable == (x-2) wobei x die Anzahl der Berechnungswiederholungen ist, da Sie mindestens 2 übereinstimmende Berechnungen benötigen, um mit der Mehrheit der abgegebenen Stimmen wiederherzustellen).

Der Nachteil ist, dass Sie x-mal statt einmal berechnen müssen, sodass Sie zusätzliche Berechnungskosten haben, die lineare Komplexität jedoch asymptotisch ist und Sie nicht viel für die Vorteile verlieren, die Sie gewinnen. Eine schnelle Möglichkeit, eine Mehrheitsabstimmung durchzuführen, besteht darin, den Modus in einem Array zu berechnen. Sie können jedoch auch einen Medianfilter verwenden.

Wenn Sie außerdem sicherstellen möchten, dass die Berechnungen korrekt durchgeführt werden, und wenn Sie Ihre eigene Hardware herstellen können, können Sie Ihr Gerät mit x CPUs aufbauen und das System so verkabeln, dass die Berechnungen automatisch mit der Mehrheit der abgegebenen Stimmen auf den x CPUs dupliziert werden mechanisch am Ende (zum Beispiel mit UND/ODER-Toren). Dies wird häufig in Flugzeugen und unternehmenskritischen Geräten implementiert (siehe dreifache modulare Redundanz ). Auf diese Weise haben Sie keinen Rechenaufwand (da die zusätzlichen Berechnungen parallel ausgeführt werden), und Sie haben eine weitere Schutzschicht vor weichen Fehlern (da die Berechnungsduplizierung und die Mehrheitsabstimmung direkt von der Hardware und nicht von verwaltet werden Software - die leichter beschädigt werden kann, da ein Programm einfach aus Bits besteht, die im Speicher gespeichert sind ...).

15
gaborous

Sie möchten 3+ Slave-Maschinen mit einem Master außerhalb der Strahlungsumgebung. Alle E/A durchlaufen den Master, der einen Abstimmungs- und/oder Wiederholungsmechanismus enthält. Die Slaves müssen jeweils über einen Hardware-Watchdog verfügen, und der Aufruf zum Anstoßen sollte von CRCs oder dergleichen umgeben sein, um die Wahrscheinlichkeit eines unfreiwilligen Stoßens zu verringern. Das Bumping sollte vom Master gesteuert werden, sodass ein Verbindungsabbruch mit Master innerhalb weniger Sekunden einem Neustart gleichkommt.

Ein Vorteil dieser Lösung ist, dass Sie für den Master dieselbe API wie für die Slaves verwenden können, sodass Redundanz zu einer transparenten Funktion wird.

Edit: Aus den Kommentaren möchte ich die "CRC-Idee" klären. Die Möglichkeit, dass der Slave seinen eigenen Watchdog stößt, ist nahe null, wenn Sie den Bump mit CRC umgeben oder Verdauungsprüfungen von zufälligen Daten vom Master durchführen. Diese zufälligen Daten werden nur vom Master gesendet, wenn der untersuchte Slave mit den anderen übereinstimmt. Die Zufallsdaten und der CRC/Digest werden sofort nach jedem Stoß gelöscht. Die Master-Slave-Bump-Frequenz sollte mehr als doppelt das Watchdog-Timeout sein. Die vom Master gesendeten Daten werden jedes Mal eindeutig generiert.

9
Jonas Byström

Ein Punkt scheint niemand erwähnt zu haben. Sie sagen, Sie entwickeln in der GCC und werden auf ARM cross-compiliert. Woher wissen Sie, dass Sie keinen Code haben, der Annahmen über den freien Arbeitsspeicher, die Ganzzahlgröße, die Zeigergröße zulässt, wie lange es dauert, um eine bestimmte Operation auszuführen, wie lange das System ununterbrochen läuft oder verschiedene andere Dinge? Dies ist ein sehr häufiges Problem.

Die Antwort ist in der Regel automatisierte Unit-Tests. Schreiben Sie Test-Kabelsätze, die den Code auf dem Entwicklungssystem ausführen, und führen Sie dann dieselben Test-Kabelsätze auf dem Zielsystem aus. Achten Sie auf Unterschiede!

Suchen Sie auch nach Errata auf Ihrem eingebetteten Gerät. Möglicherweise gibt es etwas über "nicht dies tun, weil es abstürzt, also aktivieren Sie diese Compiler-Option und der Compiler wird es umgehen".

Kurz gesagt, die wahrscheinlichste Ursache für Abstürze sind Fehler in Ihrem Code. Solange Sie nicht sicher sind, dass dies nicht der Fall ist, machen Sie sich (noch) keine Sorgen über weitere esoterische Versagensmodi.

8
Graham

Wie wäre es mit der Ausführung vieler Instanzen Ihrer Anwendung? Wenn Abstürze auf zufällige Speicherbitänderungen zurückzuführen sind, besteht die Chance, dass einige Ihrer App-Instanzen es durchstehen und genaue Ergebnisse liefern. Es ist wahrscheinlich ziemlich einfach (für jemanden mit statistischem Hintergrund) zu berechnen, wie viele Instanzen bei gegebener Bit-Flop-Wahrscheinlichkeit erforderlich sind, um einen so kleinen Gesamtfehler wie gewünscht zu erzielen.

7
ren

Wenn Ihre Hardware ausfällt, können Sie sie mit mechanischem Speicher wiederherstellen. Wenn Ihre Codebasis klein ist und etwas physischen Speicherplatz bietet, können Sie einen mechanischen Datenspeicher verwenden.

 Enter image description here

Es wird eine Materialoberfläche geben, die nicht durch Strahlung beeinträchtigt wird. Mehrere Gänge werden da sein. Ein mechanisches Lesegerät läuft auf allen Gängen und kann flexibel auf und ab bewegt werden. Down bedeutet 0 und Up bedeutet 1. Aus 0 und 1 können Sie Ihre Codebasis generieren.

7
Hitul

Vielleicht hilft es zu wissen, bedeutet es, dass die Hardware "für diese Umgebung ausgelegt" ist. Wie wird es korrigiert und/oder zeigt das Vorhandensein von SEU-Fehlern an?

Bei einem Weltraum-Explorationsprojekt hatten wir eine benutzerdefinierte MCU, die eine Ausnahme/Unterbrechung bei SEU-Fehlern auslösen würde, jedoch mit einiger Verzögerung, d. H., Einige Zyklen können durchlaufen werden/Anweisungen werden nach demjenigen ausgeführt, der die SEU-Ausnahme verursacht hat.

Besonders anfällig war der Datencache, so dass ein Handler die anstößige Cachezeile ungültig machen und das Programm neu starten würde. Nur aufgrund der Ungenauigkeit der Ausnahme kann die Sequenz der durch die Ausnahmebedingung inn geführten Anweisungen nicht erneut gestartet werden.

Wir haben die gefährlichen (nicht wiederanlauffähigen) Sequenzen identifiziert (wie lw $3, 0x0($2), gefolgt von einem inn, der $2 modifiziert und nicht datenabhängig von $3 ist), und ich habe Änderungen an GCC vorgenommen, sodass solche Sequenzen nicht auftreten (z. B. als letzter Ausweg.) , trennt die beiden insns durch eine nop).

Nur etwas zu bedenken ...

7
chill

Jemand erwähnte die Verwendung langsamerer Chips, um zu verhindern, dass Ionen Bits so leicht umdrehen. In ähnlicher Weise verwenden Sie möglicherweise eine spezielle CPU/RAM, die tatsächlich mehrere Bits zum Speichern eines einzelnen Bits verwendet. Dadurch wird eine Hardwarefehlertoleranz bereitgestellt, da es sehr unwahrscheinlich ist, dass alle Bits umgedreht werden. Also 1 = 1111, müsste aber 4 Mal getroffen werden, um tatsächlich umgedreht zu werden. (4 könnte eine schlechte Zahl sein, da, wenn 2 Bits umgedreht werden, dies bereits mehrdeutig ist). Wenn Sie also mit 8 arbeiten, erhalten Sie 8-mal weniger RAM und einen Bruchteil langsamerer Zugriffszeiten, aber eine wesentlich zuverlässigere Datendarstellung. Sie können dies wahrscheinlich sowohl auf Softwareebene mit einem spezialisierten Compiler (x-Menge mehr Speicherplatz für alles) als auch mit der Sprachimplementierung (Write-Wrapper für Datenstrukturen, die Dinge auf diese Weise zuordnen) tun. Oder spezialisierte Hardware, die dieselbe logische Struktur hat, dies aber in der Firmware tut.

7
Alex C

Was Sie fragen, ist ein recht komplexes Thema - nicht leicht zu beantworten. Andere Antworten sind in Ordnung, aber sie haben nur einen kleinen Teil der Dinge abgedeckt, die Sie tun müssen.

Wie in den Kommentaren zu sehen, ist es nicht möglich, Hardwareprobleme zu 100% zu beheben, jedoch ist es mit hoher Wahrscheinlichkeit möglich, sie mithilfe verschiedener Techniken zu reduzieren oder aufzufangen.

Wenn ich Sie wäre, würde ich die Software mit der höchsten Stufe Sicherheitsintegritätsstufe (SIL-4) erstellen. Holen Sie sich das IEC 61513-Dokument (für die Nuklearindustrie) und befolgen Sie es.

7
BЈовић

Verwenden Sie einen zyklischen Scheduler . Auf diese Weise können Sie regelmäßige Wartungszeiten hinzufügen, um die Richtigkeit kritischer Daten zu überprüfen. Das am häufigsten auftretende Problem ist die Beschädigung des Stapels. Wenn Ihre Software zyklisch ist, können Sie den Stack zwischen den Zyklen neu initialisieren. Verwenden Sie die Stapel nicht erneut für Interrupt-Aufrufe. Legen Sie für jeden wichtigen Interrupt-Aufruf einen separaten Stack an.

Ähnlich wie beim Watchdog-Konzept gibt es Deadline-Timer. Starten Sie einen Hardware-Timer, bevor Sie eine Funktion aufrufen. Wenn die Funktion nicht zurückkehrt, bevor der Termin-Timer unterbrochen wird, laden Sie den Stapel erneut und versuchen Sie es erneut. Wenn es nach 3/5 Versuchen immer noch fehlschlägt, müssen Sie das ROM neu laden.

Teilen Sie Ihre Software in Teile auf und isolieren Sie diese Teile, um separate Speicherbereiche und Ausführungszeiten zu verwenden (insbesondere in einer Steuerungsumgebung). Beispiel: Signalerfassung, Datenübernahme, Hauptalgorithmus und Ergebnisimplementierung/-übertragung. Dies bedeutet, dass ein Fehler in einem Teil keine Fehler durch den Rest des Programms verursacht. Während wir die Signalerfassung reparieren, wird der Rest der Aufgaben mit veralteten Daten fortgesetzt. 

Alles benötigt CRCs. Wenn Sie RAM ausführen, benötigt auch Ihr .text einen CRC. Überprüfen Sie die CRCs regelmäßig, wenn Sie einen zyklischen Scheduler verwenden. Einige Compiler (nicht GCC) können CRCs für jeden Abschnitt erstellen, und einige Prozessoren verfügen über dedizierte Hardware für CRC-Berechnungen, aber ich denke, das würde den Rahmen Ihrer Frage sprengen. Durch die Überprüfung von CRCs wird der ECC-Controller im Speicher auch aufgefordert, Einzelbitfehler zu beheben, bevor er zu einem Problem wird.

6
Gerhard

Erstens Entwerfen Sie Ihre Anwendung um Fehler herum. Stellen Sie sicher, dass im Rahmen des normalen Durchflussbetriebs ein Zurücksetzen erwartet wird (abhängig von Ihrer Anwendung und der Art des Ausfalls, weich oder hart). Dies ist schwer zu erreichen: Kritische Vorgänge, die ein gewisses Maß an Transaktionalität erfordern, müssen möglicherweise auf Assembly-Ebene überprüft und optimiert werden, damit eine Unterbrechung an einem wichtigen Punkt nicht zu inkonsistenten externen Befehlen führt. Fail fast sobald eine nicht behebbare Speicherbeschädigung oder Regelflussabweichung erkannt wird. Wenn möglich, Fehler protokollieren.

Zweitens, wo möglich, Korruption korrigieren und fortfahren. Dies bedeutet, dass konstante Tabellen (und, wenn möglich, Programmcode) häufig überprüft und korrigiert werden müssen. Möglicherweise vor jeder Hauptoperation oder bei einem zeitgesteuerten Interrupt und Speichern von Variablen in Strukturen, die automatisch korrigiert werden (erneut vor jeder Hauptoperation oder bei einem zeitgesteuerten Interrupt stimmen die Mehrheit mit 3 ab und korrigieren, ob es sich um eine einzelne Abweichung handelt). Nach Möglichkeit Korrekturen protokollieren.

Drittens Testfehler. Richten Sie eine wiederholbare Testumgebung ein, die Bits im Speicher pseudozufällig spiegelt. Auf diese Weise können Sie Korruptionssituationen replizieren und Ihre Anwendung entsprechend gestalten.

4
MrBigglesworth

Angesichts der Kommentare von Supercat, der Tendenzen moderner Compiler und anderer Dinge wäre ich versucht, in die alten Zeiten zurückzukehren und den gesamten Code in Assembly und statische Speicherzuweisungen überall zu schreiben. Ich glaube, für diese Art äußerster Zuverlässigkeit verursacht Assembly keine großen prozentualen Kostenunterschiede.

3
Joshua

Hier sind sehr viele Antworten, aber ich werde versuchen, meine Ideen dazu zusammenzufassen.

Etwas stürzt ab oder funktioniert nicht richtig. Dies könnte auf Ihre eigenen Fehler zurückzuführen sein. Wenn Sie das Problem finden, ist es leicht zu beheben. Es besteht jedoch auch die Möglichkeit von Hardwarefehlern - und das lässt sich insgesamt schwer beheben.

Ich würde zuerst empfehlen, die problematische Situation durch Protokollierung (Stack, Register, Funktionsaufrufe) zu erfassen - entweder indem Sie sie irgendwo in einer Datei protokollieren oder sie irgendwie direkt übertragen ("oh nein - ich stürze ab").

Das Wiederherstellen einer solchen Fehlersituation ist entweder ein Neustart (wenn die Software noch am Leben ist und Kick tritt) oder ein Hardware-Reset (z. B. hw-Watchdogs). Einfacher von Anfang an zu beginnen.

Wenn das Problem hardwarebezogen ist, sollte die Protokollierung Ihnen helfen zu erkennen, in welchem ​​Funktionsaufruf-Problem ein Problem auftritt und dass Sie wissen können, was wo nicht funktioniert.

Auch wenn der Code relativ komplex ist - es ist sinnvoll, ihn zu "teilen und zu erobern" - was bedeutet, dass Sie Funktionsaufrufe entfernen oder deaktivieren, bei denen Sie ein Problem vermuten - normalerweise die Hälfte des Codes deaktivieren und eine andere Hälfte aktivieren - können Sie "funktioniert"/"funktioniert nicht" Art der Entscheidung, nach der Sie sich auf eine andere Hälfte des Codes konzentrieren können. (Wo Problem ist)

Wenn das Problem nach einiger Zeit auftritt - dann besteht der Verdacht, dass ein Stapelüberlauf vorliegt -, sollten die Stack-Point-Register besser überwacht werden - wenn sie ständig wachsen.

Und wenn es Ihnen gelingt, Ihren Code vollständig zu minimieren, bis die Anwendung "Hallo Welt" läuft - und es immer noch willkürlich fehlschlägt -, dann werden Hardwareprobleme erwartet - und es muss ein "Hardware-Upgrade" geben, das heißt, eine solche CPU/RAM/... Hardware-Kombination, die Strahlung besser vertragen würde.

Am wichtigsten ist wahrscheinlich, wie Sie Ihre Protokolle zurückbekommen, wenn die Maschine vollständig gestoppt/zurückgesetzt wird/nicht funktioniert. Möglicherweise sollte bootstap das erste Mal tun, wenn Sie eine problematische Situation haben.

Wenn es in Ihrer Umgebung auch möglich ist, ein Signal zu senden und eine Antwort zu empfangen, können Sie versuchen, eine Art Online-Debugging-Umgebung für Remote-Umgebungen zu erstellen. Sie müssen jedoch mindestens über Kommunikationsmedien verfügen und einen Prozessor oder einen RAM im Arbeitszustand haben. Unter Remote-Debugging verstehe ich entweder GDB/gdb-Stub-Ansatz oder Ihre eigene Implementierung dessen, was Sie benötigen, um von Ihrer Anwendung zurück zu gelangen (z. B. Protokolldateien herunterladen, Aufrufstack herunterladen, RAM herunterladen, Neustart durchführen)

1
TarmoPikaro

Ich habe wirklich viele tolle Antworten gelesen!

Hier ist mein 2 Cent: Erstellen Sie ein statistisches Modell der Speicher-/Registeranomalie, indem Sie eine Software schreiben, um den Speicher zu überprüfen oder häufige Registervergleiche durchzuführen. Erstellen Sie außerdem einen Emulator im Stil einer virtuellen Maschine, in dem Sie mit dem Problem experimentieren können. Ich denke, wenn Sie die Größe der Verbindung, die Taktfrequenz, den Hersteller, das Gehäuse usw. variieren, wird ein anderes Verhalten beobachtet.

Selbst unser Desktop-PC-Speicher weist eine bestimmte Ausfallrate auf, die jedoch die tägliche Arbeit nicht beeinträchtigt.

0
user9016329