Kompilieren einer Anwendung zur Verwendung in hochradioaktiven Umgebungen

1456

Wir kompilieren eine eingebettete C / C ++ - Anwendung, die in einem abgeschirmten Gerät in einer mit ionisierender Strahlung bombardierten Umgebung bereitgestellt 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 wurde für diese Umgebung entwickelt und unsere Anwendung läuft seit mehreren Jahren auf dieser Plattform.

Gibt es Änderungen, die wir an unserem Code vornehmen können, oder Verbesserungen zur Kompilierungszeit, die vorgenommen werden können, um weiche Fehler und Speicherbeschädigungen zu identifizieren / zu korrigieren, die durch einzelne Ereignisstörungen verursacht werden ? Haben andere Entwickler erfolgreich die schädlichen Auswirkungen von weichen Fehlern auf eine lang laufende Anwendung reduziert?

Turm
quelle
186
Ändern sich die Werte im Speicher oder ändern sich die Werte im Prozessor? Wenn die Hardware entworfen für die Umwelt, sollte die Software läuft wie auf einer nicht-radioaktive Umgebung ausgeführt werden .
Thomas Matthews
3
Wenn möglich, sollten Sie ein Protokollierungssystem einrichten, das Ereignisse in einem nichtflüchtigen Speicher speichert, der strahlungsbeständig ist. Speichern Sie genügend Informationen, damit Sie das Ereignis verfolgen und die Grundursache leicht finden können.
Thomas Matthews
2
@ Thomas Matthews Alle Speicher haben eine FIT-Fehlerrate, und Hardware-Hersteller machen viele Versprechungen. Die meisten Probleme werden wahrscheinlich durch SEUs verursacht, die den RAM zur Laufzeit ändern.
Turm
9
Dies ist eine kombinierte Hardware- / Softwarelösung, aber ich weiß, dass Texas Instruments (und wahrscheinlich auch andere) eingebettete Chips für sicherheitskritische Anwendungen herstellt, die aus zwei doppelten Kernen bestehen, die im Gleichschritt laufen und einen halben Taktzyklus phasenverschoben sind. Es gibt spezielle Interrupts und Reset-Aktionen, die ausgeführt werden, wenn die Hardware etwas anderes zwischen den Kernen erkennt, sodass Sie Fehler beheben können. Ich glaube, TI bezeichnet sie als "Hercules" -Sicherheitsprozessoren.
mbrig
5
Redundante robuste Motoren, einige Zahnräder, Wellen und Ratschen! Jährlich oder öfter ersetzen, je nach Dosisleistung. Nein wirklich, meine erste Frage bei solchen Problemen war immer: Benötigen Sie wirklich so viel Software? Seien Sie so analog wie möglich.
Jwdonahue

Antworten:

814

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

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

Um sehr präzise und direkt zu sein: Es gibt keinen Mechanismus, um eine erkennbare, fehlerhafte Situation durch die Software / Firmware selbst zu beheben, ohne dass mindestens eine Kopie der Mindestarbeitsversion der Software / Firmware irgendwo für Wiederherstellungszwecke vorhanden ist - und die Hardware unterstützt die Wiederherstellung (funktional).

Diese Situation wird normalerweise sowohl auf Hardware- als auch auf Softwareebene behandelt. Auf Ihre Anfrage hin werde ich Ihnen hier mitteilen, was wir auf Softwareebene tun können.

  1. ... Erholung Zweck ... . Bieten Sie die Möglichkeit, Ihre Software / Firmware in einer realen Umgebung zu aktualisieren / neu zu kompilieren / neu zu flashen. Dies ist ein Muss für jede Software / Firmware in stark ionisierten Umgebungen. Ohne dies könnten Sie so viele redundante Software / Hardware haben, wie Sie möchten, aber irgendwann werden sie alle in die Luft jagen. Bereiten Sie diese Funktion vor!

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

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

    1. Sie können 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 sich gegenseitig einen Herzschlag senden - es ist jedoch jeweils nur eine aktiv. Wenn bekannt ist, dass eine oder mehrere Software / Firmware nicht reagiert, wechseln Sie zur anderen Software / Firmware. Der Vorteil dieses Ansatzes besteht darin, dass wir sofort nach Auftreten eines Fehlers einen Funktionsaustausch durchführen können - ohne Kontakt zu einem externen System / einer externen Partei, die für die Erkennung und Reparatur des Fehlers verantwortlich ist (im Satellitenfall ist dies normalerweise das Mission Control Center). MCC)).

      Streng genommen besteht der Nachteil ohne redundante Hardware darin, dass Sie nicht alle einzelnen Fehlerquellen beseitigen können . Zumindest haben Sie immer noch einen einzigen Fehlerpunkt, nämlich den Switch selbst (oder häufig den Anfang des Codes). Für ein Gerät mit begrenzter Größe in einer stark ionisierten Umgebung (wie Pico / Femto-Satelliten) ist die Reduzierung des einzelnen Fehlerpunkts auf einen Punkt ohne zusätzliche Hardware dennoch eine Überlegung wert. Irgendwann wäre der Code für das Umschalten sicherlich viel kleiner als der Code für das gesamte Programm - was das Risiko, dass ein einzelnes Ereignis darin enthalten ist, erheblich verringert.

    2. Wenn Sie dies jedoch nicht tun, sollten Sie mindestens eine Kopie in Ihrem externen System haben, die mit dem Gerät in Kontakt kommen und die Software / Firmware aktualisieren kann (im Satellitenfall ist es wieder das Missionskontrollzentrum).

    3. Sie können die Kopie auch in Ihrem permanenten Speicher auf Ihrem Gerät haben, der ausgelöst werden kann, um die Software / Firmware des laufenden Systems wiederherzustellen
  4. ... erkennbare fehlerhafte Situation .. Der Fehler muss erkennbar sein , normalerweise durch die Hardware- Fehlerkorrektur- / Erkennungsschaltung oder durch einen kleinen Code zur Fehlerkorrektur / -erkennung. Es ist am besten, solchen Code klein, mehrfach und unabhängig von der Hauptsoftware / Firmware zu platzieren. Seine Hauptaufgabe besteht nur in der Überprüfung / Korrektur. Wenn die Hardwareschaltung / Firmware zuverlässig ist(z. B. wenn es strahlungsgehärteter ist als die Reste - oder wenn es mehrere Schaltkreise / Logiken aufweist), können Sie eine Fehlerkorrektur in Betracht ziehen. Ist dies nicht der Fall, ist es besser, die Fehlererkennung durchzuführen. Die Korrektur kann durch ein externes System / Gerät erfolgen. Für die Fehlerkorrektur können Sie einen grundlegenden Fehlerkorrekturalgorithmus wie Hamming / Golay23 verwenden, da diese sowohl in der Schaltung als auch in der Software einfacher implementiert werden können. Aber letztendlich hängt es von den Fähigkeiten Ihres Teams ab. Zur Fehlererkennung wird normalerweise CRC verwendet.

  5. ... Hardware, die die Wiederherstellung unterstützt Nun kommt der schwierigste Aspekt zu diesem Thema. Letztendlich erfordert die Wiederherstellung, dass die Hardware, die für die Wiederherstellung verantwortlich ist, mindestens funktionsfähig ist. Wenn die Hardware dauerhaft defekt ist (normalerweise, nachdem die gesamte ionisierende Dosis ein bestimmtes Niveau erreicht hat), gibt es (leider) keine Möglichkeit für die Software, bei der Wiederherstellung zu helfen. Daher ist Hardware zu Recht das Hauptanliegen eines Geräts, das einem hohen Strahlungsniveau ausgesetzt ist (z. B. Satellit).

Zusätzlich zu dem oben genannten Vorschlag, den Firmware-Fehler aufgrund einer Störung eines einzelnen Ereignisses zu antizipieren, möchte ich Ihnen auch Folgendes vorschlagen:

  1. Fehlererkennungs- und / oder Fehlerkorrekturalgorithmus im Kommunikationsprotokoll zwischen Subsystemen. Dies ist ein weiteres Muss, um unvollständige / falsche Signale von anderen Systemen zu vermeiden

  2. Filtern Sie in Ihrem ADC-Messwert. Sie nicht den ADC direkt zu lesen verwenden. Filtern Sie es nach Medianfilter, Mittelwertfilter oder anderen Filtern - vertrauen Sie niemals einem einzelnen Lesewert. Probieren Sie mehr und nicht weniger - vernünftigerweise.

Ian
quelle
401

Die NASA hat ein Papier über strahlungsgehärtete Software. Es beschreibt drei Hauptaufgaben:

  1. Regelmäßige Überwachung des Speichers auf Fehler, um diese Fehler zu beseitigen.
  2. robuste Fehlerbehebungsmechanismen und
  3. die Möglichkeit, neu zu konfigurieren, wenn etwas nicht mehr funktioniert.

Beachten Sie, dass die Speicherabtastrate so häufig sein sollte, dass Mehrbitfehler selten auftreten, da der größte Teil des ECC- Speichers von Einzelbitfehlern und nicht von Mehrbitfehlern wiederhergestellt werden kann.

Die robuste Fehlerbehebung umfasst die Übertragung des Kontrollflusses (normalerweise ein Neustart eines Prozesses zu einem Zeitpunkt vor dem Fehler), die Freigabe von Ressourcen und die Wiederherstellung von Daten.

Ihre Hauptempfehlung für die Datenwiederherstellung besteht darin, die Notwendigkeit zu vermeiden, indem Zwischendaten als vorübergehend behandelt werden, sodass ein Neustart vor dem Fehler auch die Daten in einen zuverlässigen Zustand zurückversetzt. Dies klingt ähnlich wie das Konzept der "Transaktionen" in Datenbanken.

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

  1. Softwarebasierte ECCs für zusammenhängende Speicherobjekte
  2. Vertragliche Programmierung : Überprüfen der Vor- und Nachbedingungen und anschließendes Überprüfen des Objekts, um sicherzustellen, dass es sich noch in einem gültigen Zustand befindet.

Und genau so hat die NASA C ++ für große Projekte wie den Mars Rover verwendet .

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

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

  1. Ausnahmen
  2. Vorlagen
  3. Iostream (keine Konsole)
  4. Mehrfachvererbung
  5. Überlastung des Bedieners (außer newund delete)
  6. Dynamische Zuweisung (Verwendung eines dedizierten Speicherpools und einer Platzierung new, um die Möglichkeit einer Beschädigung des Systemheaps zu vermeiden).
rsjaffe
quelle
28
Das klingt tatsächlich nach etwas, in dem eine reine Sprache gut wäre. Da sich die Werte nie ändern, können Sie bei Beschädigung einfach zur ursprünglichen Definition zurückkehren (wie es sein soll), und Sie werden nicht versehentlich zweimal dasselbe tun (wegen fehlender Nebenwirkungen).
PyRulez
20
RAII ist eine schlechte Idee, da Sie sich nicht darauf verlassen können, dass es richtig oder überhaupt funktioniert. Es könnte Ihre Daten zufällig beschädigen usw. Sie möchten wirklich so viel Unveränderlichkeit wie möglich und darüber hinaus Fehlerkorrekturmechanismen. Es ist viel einfacher, kaputte Dinge einfach wegzuwerfen, als sie irgendwie zu reparieren (wie genau wissen Sie genug, um zum richtigen alten Zustand zurückzukehren?). Sie möchten wahrscheinlich eine ziemlich dumme Sprache dafür verwenden - Optimierungen können mehr schaden als helfen.
Luaan
67
@ PyRulez: Reine Sprachen sind eine Abstraktion, Hardware ist nicht rein. Compiler sind ziemlich gut darin, den Unterschied zu verbergen. Wenn Ihr Programm einen Wert hat, den es nach Schritt X logischerweise nicht mehr verwenden sollte, überschreibt der Compiler ihn möglicherweise mit einem Wert, der in Schritt X + 1 berechnet wurde. Das heißt aber, du kannst nicht zurück. Formal bilden die möglichen Zustände eines Programms in einer reinen Sprache einen azyklischen Graphen, was bedeutet, dass zwei Zustände äquivalent sind und zusammengeführt werden können, wenn die von beiden erreichbaren Zustände äquivalent sind. Diese Fusion zerstört den Unterschied in den Pfaden, die zu diesen Staaten führen.
MSalters
2
@Vorac - Laut der Präsentation ist das Problem mit C ++ - Vorlagen Code Bloat.
JWW
3
@DeerSpotter Das genaue Problem ist viel größer als das. Durch die Ionisierung können Teile Ihres laufenden Überwachungsprogramms beschädigt werden. Dann brauchen Sie einen Beobachter eines Beobachters, dann - Beobachter eines Beobachters eines Beobachters und so weiter ...
Agnius Vasiliauskas
116

Hier sind einige Gedanken und Ideen:

Verwenden Sie ROM kreativer.

Speichern Sie alles, was Sie können, im ROM. Speichern Sie Nachschlagetabellen im ROM, anstatt Dinge zu berechnen. (Stellen Sie sicher, dass Ihr Compiler Ihre Nachschlagetabellen im schreibgeschützten Bereich ausgibt! Drucken Sie zur Laufzeit die Speicheradressen 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 im Vergleich zu Ihrem RAM ist.

Verwenden Sie Ihren besten RAM für den Stapel.

SEUs im Stapel sind wahrscheinlich die wahrscheinlichste Ursache für Abstürze, da hier normalerweise Indexvariablen, Statusvariablen, Rücksprungadressen und Zeiger verschiedener Art leben.

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

Sie können bei jedem Timer-Tick eine "Sanity Check" -Routine sowie eine Watchdog-Routine ausführen, um das System zu blockieren. Ihr Hauptcode kann auch regelmäßig einen Zähler erhöhen, um den Fortschritt anzuzeigen, und die Routine zur Überprüfung der Integrität kann sicherstellen, dass dies geschehen ist.

Implementieren Sie Fehlerkorrekturcodes in der Software.

Sie können Ihren Daten Redundanz hinzufügen, um Fehler erkennen und / oder korrigieren zu können. Dies verlängert die Verarbeitungszeit und lässt den Prozessor möglicherweise länger Strahlung ausgesetzt sein, wodurch die Wahrscheinlichkeit von Fehlern erhöht wird. Daher müssen Sie den Kompromiss berücksichtigen.

Erinnere dich an die Caches.

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

Verwenden Sie Seitenfehler-Handler geschickt.

Wenn Sie eine Speicherseite als nicht vorhanden markieren, gibt die CPU einen Seitenfehler aus, wenn Sie versuchen, darauf zuzugreifen. Sie können einen Seitenfehler-Handler 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 Assemblersprache für kritische Dinge (die alles sein können).

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

Verwenden Sie objdumpdiese Option, um die generierte Assemblersprache anzuzeigen und herauszufinden, wie viel Code jede Ihrer Routinen belegt.

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 können.

Denken Sie daran, es ist ein Spiel der Wahrscheinlichkeiten.

Ein Kommentator sagte

Jede Routine, die Sie schreiben, um Fehler abzufangen, kann aus derselben Ursache selbst fehlschlagen.

Während dies zutrifft, ist die Wahrscheinlichkeit von Fehlern in den (sagen wir) 100 Bytes Code und Daten, die erforderlich sind, damit eine Überprüfungsroutine ordnungsgemäß funktioniert, viel geringer als die Wahrscheinlichkeit von Fehlern an anderer Stelle. Wenn Ihr ROM ziemlich zuverlässig ist und fast der gesamte Code / die Daten tatsächlich im ROM sind, sind Ihre Chancen sogar noch besser.

Verwenden Sie redundante Hardware.

Verwenden Sie zwei oder mehr identische Hardware-Setups mit identischem Code. Wenn die Ergebnisse unterschiedlich sind, sollte ein Reset ausgelöst werden. Bei 3 oder mehr Geräten können Sie mithilfe eines "Abstimmungssystems" versuchen, festzustellen, welches kompromittiert wurde.

Artelius
quelle
14
Heutzutage ist ECC über Hardware verfügbar, was die Verarbeitungszeit spart. Schritt eins wäre die Auswahl eines Mikrocontrollers mit integriertem ECC.
Lundin
23
Irgendwo im Hinterkopf befindet sich ein Hinweis auf Avionik-Flughardware (vielleicht Space Shuttle?), Bei der die redundante Architektur explizit so konzipiert wurde, dass sie nicht identisch ist (und von verschiedenen Teams). Auf diese Weise wird die Möglichkeit eines Systemfehlers im Hardware- / Software-Design verringert und die Möglichkeit verringert, dass alle Abstimmungssysteme gleichzeitig abstürzen, wenn sie mit denselben Eingaben konfrontiert werden.
Peter M
8
@PeterM: AFAIK, das auch für die Flugsoftware für die Boeing 777 beansprucht wird: Drei Versionen von drei Teams in drei Programmiersprachen.
Monica wieder herstellen - M. Schröder
7
@ DanEsparza RAM hat normalerweise entweder einen Kondensator (DRAM) oder einige Transistoren in Rückkopplung (SRAM), die Daten speichern. Ein Strahlungsereignis kann den Kondensator fälschlicherweise laden / entladen oder das Signal in der Rückkopplungsschleife ändern. ROM benötigt normalerweise nicht die Fähigkeit zum Schreiben (zumindest ohne besondere Umstände und / oder höhere Spannungen) und kann daher auf physikalischer Ebene von Natur aus stabiler sein.
Nanofarad
7
@ DanEsparza: Es gibt mehrere Arten von ROM-Speichern. Wenn das "ROM" durch Eeprom oder Flash emuliert wird, das nur bei 5 V schreibgeschützt, aber bei 10 V programmierbar ist, dann ist dieses "ROM" tatsächlich immer noch anfällig für Ionisation. Vielleicht nur weniger als andere. Es gibt jedoch gute alte Hardcore-Dinge wie Mask ROM oder Fuse-basiertes PROM, von denen ich denke, dass sie eine wirklich ernsthafte Menge an Strahlung benötigen würden, um zu versagen. Ich weiß jedoch nicht, ob es noch hergestellt werden.
Quetzalcoatl
105

Vielleicht interessieren Sie sich auch für die umfangreiche Literatur zum Thema algorithmische Fehlertoleranz. Dies schließt die alte Zuordnung ein: Schreiben Sie eine Sortierung, die ihre Eingabe korrekt sortiert, wenn eine konstante Anzahl von Vergleichen fehlschlägt (oder die etwas bösere Version, wenn die asymptotische Anzahl fehlgeschlagener Vergleiche wie log(n)bei nVergleichen skaliert ).

Ein Ort, an dem man mit dem Lesen beginnen kann, ist Huangs und Abrahams 1984 erschienenes Papier " Algorithm-Based Fault Tolerance for Matrix Operations ". Ihre Idee ähnelt vage der homomorphen verschlüsselten Berechnung (aber sie ist nicht wirklich dieselbe, da sie versuchen, Fehler auf Betriebsebene zu erkennen / zu korrigieren).

Ein neuerer Nachkomme dieses Papiers ist Bosilca, Delmas, Dongarra und Langous " Algorithmusbasierte Fehlertoleranz für Hochleistungsrechnen ".

Eric Towers
quelle
5
Ihre Antwort gefällt mir sehr gut. Dies ist ein allgemeinerer Softwareansatz für die Datenintegrität, und in unserem Endprodukt wird eine algorithmisch basierte Fehlertoleranzlösung verwendet. Vielen Dank!
Turm
41

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

Zusätzlich zu dem, was bereits erwähnt wurde, gibt es hier einige verschiedene Tipps:

  • Verwenden Sie alltägliche "Brot & Butter" -Sicherheitsmaßnahmen, die in jedem semiprofessionellen eingebetteten System vorhanden sein sollten: interner Watchdog, interne Niederspannungserkennung, interner Uhrenmonitor. Diese Dinge sollten im Jahr 2016 nicht einmal erwähnt werden müssen und sind bei so ziemlich 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 über ein unternehmenskritisches Echtzeitsystem verfügen.
  • Verwenden Sie im Allgemeinen eine MCU, die für diese Art von Systemen geeignet ist, und keine generischen Mainstream-Flusen, die Sie in einer Packung Cornflakes erhalten haben. Fast jeder MCU-Hersteller verfügt heutzutage über spezialisierte MCUs für Sicherheitsanwendungen (TI, Freescale, Renesas, ST, Infineon usw. usw.). Diese verfügen über zahlreiche integrierte Sicherheitsfunktionen, einschließlich Lock-Step-Kernen. Dies bedeutet, dass zwei CPU-Kerne denselben Code ausführen und miteinander übereinstimmen müssen.
  • WICHTIG: Sie müssen die Integrität der internen MCU-Register sicherstellen. Alle beschreibbaren Steuerungs- und Statusregister von Hardware-Peripheriegeräten befinden sich möglicherweise im RAM-Speicher und sind daher anfällig.

    Um sich vor Registerverfälschungen zu schützen, wählen Sie vorzugsweise einen Mikrocontroller mit integrierten "Write-Once" -Funktionen von Registern. Darüber hinaus müssen Sie die Standardwerte aller Hardwareregister in NVM speichern und diese Werte in regelmäßigen Abständen in Ihre Register kopieren. Auf die gleiche Weise können Sie die Integrität wichtiger Variablen sicherstellen.

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

  • Es gibt alle Arten von Methoden, um nach Fehlern im RAM oder NVM zu suchen: Prüfsummen, "Laufmuster", Software-ECC usw. usw. Die beste Lösung besteht heutzutage darin, keine dieser Methoden zu verwenden, sondern eine MCU mit integriertem ECC und ähnliche Prüfungen. Da dies in der Software komplex ist und die Fehlerprüfung an sich Fehler und unerwartete Probleme verursachen kann.

  • 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. Jedem Segment kann eine CRC-Prüfsumme zugeordnet sein.
  • Vermeiden Sie die Verwendung externer Speicher außerhalb der MCU.
  • Implementieren Sie eine Standard-Interrupt-Serviceroutine / Standard-Ausnahmehandler für alle möglichen Interrupts / Ausnahmen. Sogar die, die Sie nicht verwenden. Die Standardroutine sollte nichts anderes tun, als die eigene Interruptquelle auszuschalten.
  • Das Konzept der defensiven Programmierung verstehen und annehmen. Dies bedeutet, dass Ihr Programm alle möglichen Fälle behandeln muss, auch diejenigen, die theoretisch nicht auftreten können. Beispiele .

    Hochwertige unternehmenskritische Firmware erkennt so viele Fehler wie möglich und ignoriert sie dann auf sichere Weise.

  • Schreiben Sie niemals Programme, die auf schlecht spezifiziertem Verhalten beruhen. Es ist wahrscheinlich, dass sich ein solches Verhalten bei unerwarteten Hardwareänderungen, die durch Strahlung oder EMI verursacht werden, drastisch ändert. Der beste Weg, um sicherzustellen, dass Ihr Programm frei von solchem ​​Mist ist, ist die Verwendung eines Codierungsstandards wie MISRA zusammen mit einem statischen Analysetool. Dies hilft auch bei der defensiven Programmierung und beim Entfernen von Fehlern (warum sollten Sie Fehler in keiner Anwendung erkennen wollen?).
  • WICHTIG: Implementieren Sie keine Abhängigkeit von den Standardwerten der Variablen für die statische Speicherdauer. Vertrauen Sie also nicht dem Standardinhalt von .dataoder .bss. Zwischen dem Zeitpunkt der Initialisierung und dem Zeitpunkt, an dem die Variable tatsächlich verwendet wird, kann eine beliebige Zeitspanne liegen. Möglicherweise hat der RAM genügend Zeit, um beschädigt zu werden. Schreiben Sie stattdessen das Programm so, dass alle diese Variablen zur Laufzeit von NVM festgelegt werden, kurz vor dem Zeitpunkt, zu dem eine solche Variable zum ersten Mal verwendet wird.

    In der Praxis bedeutet dies, dass Sie eine Variable, wenn sie im Dateibereich oder als deklariert staticist, niemals =zum Initialisieren verwenden sollten (oder Sie könnten, aber es ist sinnlos, da Sie sich sowieso nicht auf den Wert verlassen können). Stellen Sie es immer zur Laufzeit ein, kurz vor dem Gebrauch. Wenn es möglich ist, solche Variablen wiederholt über NVM zu aktualisieren, tun Sie dies.

    Verlassen Sie sich in C ++ nicht auf Konstruktoren für statische Speicherdauervariablen. Lassen Sie den / die Konstruktor (en) eine öffentliche "Setup" -Routine aufrufen, die Sie auch später zur Laufzeit direkt aus der Aufruferanwendung aufrufen können.

    Wenn möglich, entfernen Sie den Startcode "Kopieren", der C ++ - Konstruktoren initialisiert .dataund .bss(und aufruft) vollständig, so dass Sie Linkerfehler erhalten, wenn Sie Code schreiben, der auf solchen basiert. Viele Compiler haben die Möglichkeit, dies zu überspringen, was normalerweise als "minimaler / schneller Start" oder ähnliches bezeichnet wird.

    Dies bedeutet, dass externe Bibliotheken überprüft werden müssen, damit sie keine solche Abhängigkeit enthalten.

  • Implementieren und definieren Sie einen sicheren Status für das Programm, in den Sie bei kritischen Fehlern zurückkehren.

  • Die Implementierung eines Fehlerbericht- / Fehlerprotokollsystems ist immer hilfreich.
Lundin
quelle
Eine Möglichkeit, mit beschädigten Booleschen Werten umzugehen (wie in Ihrem Beispiellink), könnte darin bestehen, die Verwendung mit einem Schwellenwert TRUEgleichzusetzen . 0xffffffffPOPCNT
wizzwizz4
@ wizzwizz4 Angesichts der Tatsache, dass der Wert 0xff der Standardwert einer nicht programmierten Flash-Zelle ist, klingt dies nach einer schlechten Idee.
Lundin
%01010101010101010101010101010101, XOR dann POPCNT?
wizzwizz4
1
@ wizzwizz4 Oder nur der Wert 0x1, wie vom C-Standard gefordert.
Lundin
1
@ wizzwizz4 Warum Sie einige oder alle der oben genannten Methoden (ECC, CRC usw.) verwenden. Andernfalls kann der kosmische Strahl auch ein einzelnes Bit in Ihrem .textAbschnitt umdrehen und einen Operationscode oder ähnliches ändern.
Lundin
34

Mit C können möglicherweise Programme geschrieben werden, die sich in solchen Umgebungen robust verhalten, jedoch nur, wenn die meisten Formen der Compileroptimierung deaktiviert sind. Optimierende Compiler sollen viele scheinbar redundante Codierungsmuster durch "effizientere" ersetzen und haben möglicherweise keine Ahnung, dass der Grund, warum der Programmierer testet, x==42wenn der Compiler weiß, dass es xunmöglich ist, etwas anderes zu halten, darin besteht, dass der Programmierer dies verhindern möchte die Ausführung eines bestimmten Codes mit xeinem anderen Wert - selbst in Fällen, in denen dieser Wert nur dann gehalten werden kann, wenn das System eine Art elektrischen Fehler empfängt.

Das Deklarieren von Variablen volatileist oft hilfreich, aber möglicherweise kein Allheilmittel. Beachten Sie insbesondere, dass für eine sichere Codierung häufig gefährliche Vorgänge Hardware-Verriegelungen erfordern, deren Aktivierung mehrere Schritte erfordert, und dass der Code mithilfe des folgenden Musters geschrieben wird:

... 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 alle Überprüfungen des Systemstatus nach dem wiederholt werden prepare_for_activation(), ist das System möglicherweise robust gegen nahezu jedes plausible Einzelfehlerereignis, selbst gegen solche, die den Programmzähler und den Stapel willkürlich beschädigen würden. Wenn ein Fehler unmittelbar nach einem Anruf bei auftritt prepare_for_activation(), würde dies bedeuten, dass die Aktivierung angemessen gewesen wäre (da prepare_for_activation()vor dem Fehler kein anderer Grund aufgerufen worden wäre). Wenn der Fehler dazu führt, dass der Code prepare_for_activation()unangemessen erreicht wird, es jedoch keine nachfolgenden Fehlerereignisse gibt, kann der Codetrigger_activation() ohne zuvor die Validierungsprüfung durchlaufen oder cancel_preparations aufgerufen zu haben [Wenn der Stapel fehlerhaft ist, wird die Ausführung möglicherweise an einer Stelle fortgesetzt kurz bevortrigger_activation()Nach dem Kontext, der aufgerufen wurde, wird prepare_for_activation()zurückgegeben, aber der Aufruf von cancel_preparations()wäre zwischen den Aufrufen von prepare_for_activation()und aufgetreten trigger_activation(), wodurch der letztere Aufruf unschädlich wird.

Ein solcher Code ist in herkömmlichem C sicher, in modernen C-Compilern jedoch nicht. Solche Compiler können in solchen Umgebungen sehr gefährlich sein, da sie aggressiv danach streben, nur Code einzuschließen, der in Situationen relevant ist, die über einen genau definierten Mechanismus entstehen könnten und deren daraus resultierende Konsequenzen ebenfalls genau definiert wären. Code, dessen Zweck darin besteht, Fehler zu erkennen und zu bereinigen, kann in einigen Fällen die Situation verschlimmern. Wenn der Compiler feststellt, dass die versuchte Wiederherstellung in einigen Fällen ein undefiniertes Verhalten hervorruft, kann daraus geschlossen werden, dass die Bedingungen, die eine solche Wiederherstellung in solchen Fällen erfordern würden, möglicherweise nicht eintreten können, wodurch der Code eliminiert wird, der nach ihnen gesucht hätte.

Superkatze
quelle
6
Wie viele moderne Compiler gibt es realistisch gesehen, die keinen -O0oder einen gleichwertigen Switch anbieten ? GCC wird viele seltsame Dinge tun, wenn Sie ihm die Erlaubnis geben , aber wenn Sie ihn bitten, sie nicht zu tun, kann es im Allgemeinen auch ziemlich wörtlich sein.
Leushenko
24
Sorry, aber diese Idee ist grundsätzlich gefährlich. Das Deaktivieren von Optimierungen führt zu einem langsameren Programm. Mit anderen Worten, Sie benötigen eine schnellere CPU. Schnellere CPUs sind zwar schneller, weil die Ladungen an ihren Transistorgates kleiner sind. Dies macht sie weitaus anfälliger für Strahlung. Die bessere Strategie besteht darin, einen langsamen, großen Chip zu verwenden, bei dem ein einzelnes Photon mit weit geringerer Wahrscheinlichkeit ein wenig umkippt und die Geschwindigkeit mit zurückgewinnt -O2.
MSalters
27
Ein zweiter Grund, warum -O0eine schlechte Idee ist, ist, dass sie weitaus nutzlosere Anweisungen ausgibt. Beispiel: Ein nicht inline-Aufruf enthält Anweisungen zum Speichern von Registern, zum Tätigen des Anrufs und zum Wiederherstellen von Registern. All dies kann fehlschlagen. Eine Anweisung, die nicht vorhanden ist, kann nicht fehlschlagen.
MSalters
15
Ein weiterer Grund, warum dies -O0eine schlechte Idee ist: Es werden Variablen eher im Speicher als in einem Register gespeichert. Jetzt ist es nicht sicher, ob der Speicher anfälliger für SEUs ist, aber Daten im Flug sind anfälliger als Daten in Ruhe. Nutzlose Datenverschiebungen sollten vermieden werden und -O2helfen dort.
MSalters
9
@MSalters: Wichtig ist nicht, dass Daten gegen Störungen immun sind, sondern dass das System Störungen so behandeln kann, dass sie den Anforderungen entsprechen. Bei vielen Compilern führt das Deaktivieren aller Optimierungen zu Code, der eine übermäßige Anzahl von Verschiebungen von Register zu Register ausführt. Dies ist schlecht, aber das Speichern von Variablen im Speicher ist vom Standpunkt der Wiederherstellung aus sicherer als das Speichern in Registern. Wenn man zwei Variablen im Speicher hat, die einer bestimmten Bedingung entsprechen sollen (z. B. v1=v2+0xCAFEBABEund alle Aktualisierungen der beiden Variablen durchgeführt werden ...
Supercat
28

Dies ist ein äußerst breites Thema. Grundsätzlich können Sie sich nicht wirklich von einer Speicherbeschädigung erholen, aber Sie können zumindest versuchen, sofort zu scheitern . Hier sind einige Techniken, die Sie verwenden können:

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

  • Variablen mit Redundanz speichern . Wenn Sie eine wichtige Variable haben x, schreiben Sie seinen Wert in x1, x2und x3und lesen Sie es wie (x1 == x2) ? x2 : x3.

  • Programmflussüberwachung implementieren . XOR ein globales Flag mit einem eindeutigen Wert in wichtigen Funktionen / Zweigen, die von der Hauptschleife aufgerufen werden. Wenn Sie das Programm in einer strahlungsfreien Umgebung mit einer Testabdeckung von nahezu 100% ausführen, erhalten Sie am Ende des Zyklus eine Liste der zulässigen Werte des Flags. Zurücksetzen, wenn Abweichungen auftreten.

  • Überwachen Sie den Stapelzeiger . Vergleichen Sie am Anfang der Hauptschleife den Stapelzeiger mit seinem erwarteten Wert. Bei Abweichung zurücksetzen.

Dmitry Grigoryev
quelle
27

Was Ihnen helfen könnte, ist ein Wachhund . Wachhunde wurden in den 1980er Jahren in großem Umfang im industriellen Computer eingesetzt. Hardwarefehler waren damals viel häufiger - eine andere Antwort bezieht sich auch auf diesen Zeitraum.

Ein Watchdog ist eine kombinierte Hardware- / Softwarefunktion. 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 wesentlichen Systeme überwacht. Wenn diese Routine korrekt ausgeführt wird = der Computer ordnungsgemäß ausgeführt wird, wird der Zähler auf 1023 zurückgesetzt.

Das Gesamtdesign ist so, dass die Software unter normalen Umständen verhindert, dass der Hardware-Zähler 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 der Zählerperspektive ist Null gleich 1024 und der Zähler zählt weiter herunter.

Dieser Watchdog stellt sicher, dass der angeschlossene Computer in vielen, vielen Fehlerfällen 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 heute viel komplexer als früher.

Ein inhärenter Nachteil des Watchdogs besteht darin, dass das System ab dem Zeitpunkt des Ausfalls nicht verfügbar ist, bis der Watchdog-Zähler Null + Neustartzeit erreicht. Während diese Zeit im Allgemeinen viel kürzer ist als jeder externe oder menschliche Eingriff, müssen die unterstützten Geräte für diesen Zeitraum ohne Computersteuerung weiterarbeiten können.

OldFrank
quelle
9
Binary Counter Watchdogs mit TTL-Standard-ICs sind in der Tat eine Lösung aus den 1980er Jahren. Tu das nicht. Heutzutage gibt es keine einzige MCU auf dem Markt ohne integrierte Watchdog-Schaltung. Sie müssen lediglich überprüfen, ob der integrierte Watchdog über eine einzelne Taktquelle verfügt (gut, höchstwahrscheinlich) oder ob er seine Uhr von der Systemuhr erbt (schlecht).
Lundin
1
Oder implementieren Sie den Watchdog in einem FPGA: ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20130013486.pdf
Nr.
2
Wird übrigens immer noch häufig in eingebetteten Prozessoren verwendet.
Graham
5
@Peter Mortensen Bitte stoppen Sie Ihre Bearbeitung bei jeder Antwort auf diese Frage. Dies ist keine Wikipedia, und diese Links sind nicht hilfreich (und ich bin sicher, dass jeder weiß, wie man Wikipedia findet ...). Viele Ihrer Änderungen sind falsch, weil Sie das Thema nicht kennen. Ich mache Rollbacks für Ihre falschen Änderungen, wenn ich auf sie stoße. Sie drehen diesen Faden nicht besser, sondern schlechter. Stoppen Sie die Bearbeitung.
Lundin
Jack Ganssle hat einen guten Artikel über Wachhunde: ganssle.com/watchdogs.htm
Igor Skochinsky
23

Bei dieser Antwort wird davon ausgegangen, dass Sie sich mit einem System befassen, das ordnungsgemäß funktioniert, und über ein System, das nur minimale Kosten aufweist oder schnell ist. Die meisten Menschen, 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 hier bereits viele gute Dinge in den Antworten, und ich beabsichtige nicht, alles zu wiederholen), und andere haben Redundanz vorgeschlagen (im Prinzip großartig), aber ich denke nicht Jeder hat vorgeschlagen, wie diese Redundanz in der Praxis funktionieren könnte. Wie scheitern Sie? Woher wissen Sie, wenn etwas schief gelaufen ist? Viele Technologien arbeiten auf der Basis, dass alles funktioniert, und Fehler sind daher eine schwierige Sache. Einige für die Skalierung konzipierte verteilte Computertechnologien erwarten jedoch einen Ausfall (schließlich ist bei ausreichender Skalierung ein Ausfall eines Knotens von vielen bei jeder MTBF für einen einzelnen Knoten unvermeidlich). Sie können dies für Ihre Umgebung nutzen.

Hier sind ein paar Ideen:

  • Stellen Sie sicher, dass Ihre gesamte Hardware repliziert nwird (wobei ngrößer als 2 und vorzugsweise ungerade ist) und dass jedes Hardwareelement miteinander kommunizieren kann. Ethernet ist ein offensichtlicher Weg, dies zu tun, aber es gibt viele andere weitaus einfachere Routen, die einen besseren Schutz bieten würden (z. B. CAN). Minimieren Sie gängige Komponenten (auch Netzteile). Dies kann beispielsweise bedeuten, dass ADC-Eingänge an mehreren Stellen abgetastet werden.

  • Stellen Sie sicher, dass sich Ihr Anwendungsstatus an einem einzigen Ort befindet, z. B. in einer endlichen Zustandsmaschine. Dies kann vollständig RAM-basiert sein, schließt jedoch eine stabile Speicherung nicht aus. Es wird somit an mehreren Stellen 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 bekannte gute Bibliothek für den Protokollstapel und das Quorum-Protokoll, anstatt selbst eine zu rollen, oder all Ihre gute Arbeit an Redundanz wird verschwendet, wenn das Quorum-Protokoll auflegt.

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

  • Bauen Sie so viele andere interne Überprüfungen wie möglich in Ihr System ein, damit Knoten, die ihren eigenen Fehler erkennen, neu gestartet werden (dies ist besser, als die Hälfte der Arbeit fortzusetzen, vorausgesetzt, Sie haben genügend Knoten). Versuchen Sie, sie sich 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) überprüfen und führen Sie einen vollständigen RAM-Test durch, bevor Sie sich wieder dem Quorum vorstellen.

  • Verwenden Sie Hardware, um Sie zu unterstützen, aber gehen Sie vorsichtig vor. 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). Statischer RAM (aus dem Speicher) ist jedoch weitaus toleranter gegenüber ionisierender Strahlung als DRAM an erster Stelle. Daher ist es möglicherweise besser, stattdessen statischen DRAM zu verwenden. Siehe auch den ersten Punkt unter "Dinge, die ich nicht tun würde".

Angenommen, Sie haben eine 1% ige Ausfallwahrscheinlichkeit eines bestimmten Knotens 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 mehr kommen Sie auf die Idee.

Dinge, die ich nicht tun würde:

  • Unterschätzen Sie den Wert, das Problem zunächst nicht zu haben. Wenn das Gewicht keine Rolle spielt, ist ein großer Metallblock um Ihr Gerät eine weitaus billigere und zuverlässigere Lösung, als ein Team von Programmierern es sich vorstellen kann. Das Gleiche gilt für die optische Kopplung von EMI-Eingängen usw. Versuchen Sie bei der Beschaffung Ihrer Komponenten, die am besten gegen ionisierende Strahlung bewerteten Komponenten zu beschaffen.

  • Rollen Sie Ihre eigenen Algorithmen . Die Leute haben dieses Zeug schon einmal gemacht. Verwenden Sie ihre Arbeit. Fehlertoleranz und verteilte Algorithmen sind schwierig. Verwenden Sie nach Möglichkeit die Arbeit anderer Personen.

  • Verwenden Sie komplizierte Compilereinstellungen in der naiven Hoffnung, dass Sie weitere Fehler erkennen. Wenn Sie Glück haben, können Sie weitere Fehler feststellen. 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 als Ergebnis viele Fehlermodi verpassen. Sie sind in der „glücklichen“ Lage, bei Bedarf häufig auszufallen. Testen Sie also jede Technik und stellen Sie sicher, dass ihre tatsächliche Anwendung die MTBF 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 Quorum-Algorithmen usw. an.

abligh
quelle
2
Ethernet ist wahrscheinlich keine gute Idee für geschäftskritische Anwendungen. I2C befindet sich auch nicht außerhalb der Leiterplatte. Etwas Robustes wie CAN wäre weitaus besser geeignet.
Lundin
1
@Lundin Fairer Punkt, obwohl alles, was optisch verbunden ist (inkl. Ethernet), in Ordnung sein sollte.
Abligh
1
Das physische Medium ist nicht so sehr der Grund, warum Ethernet ungeeignet ist, sondern das Fehlen eines deterministischen Echtzeitverhaltens. Obwohl ich denke, dass es heutzutage auch Möglichkeiten gibt, etwas zuverlässiges Ethernet bereitzustellen, gruppiere ich es aus alter Gewohnheit einfach mit kommerzieller / Spielzeugelektronik.
Lundin
1
@Lundin, das ist ein fairer Punkt, aber da ich vorschlage, RAFT damit auszuführen, wird der Algorithmus ohnehin (theoretisch) nicht deterministisches Echtzeitverhalten aufweisen (z. B. gleichzeitige Führerwahlen, die zu einer erneuten Wahl führen, die CSMA / ähnelt) CD). Wenn striktes Echtzeitverhalten erforderlich ist, hat meine Antwort wahrscheinlich mehr Probleme als Ethernet (und am Anfang meiner Antwort habe ich gesagt, dass "richtig" wahrscheinlich oft auf Kosten von "schnell" geht). Ich habe Ihren Punkt bezüglich CAN aufgenommen.
Abligh
1
@Lundin: Kein System, das asynchrone Aspekte beinhaltet, kann vollständig nicht deterministisch sein. Ich denke, das Worst-Case-Verhalten von Ethernet kann ohne Hardware-Störungen eingeschränkt werden, wenn Softwareprotokolle in geeigneter Weise eingerichtet werden und Geräte eindeutige IDs haben und die Anzahl der Geräte bekanntermaßen begrenzt ist (je mehr Geräte, desto größer die Worst-Case-Anzahl von Wiederholungsversuchen).
Supercat
23

Da Sie speziell nach Softwarelösungen fragen und C ++ verwenden, können Sie mithilfe der Operatorüberladung Ihre eigenen, sicheren Datentypen erstellen. Zum Beispiel:

Anstelle der Verwendung uint32_t(und double, int64_tusw.), machen sie ihre eigenen , SAFE_uint32_tdie ein Vielfaches (mindestens 3) von uint32_t enthält. Überladen Sie alle Operationen, die Sie ausführen möchten (* + - / << >> = ==! = Usw.), und lassen Sie die überladenen Operationen für jeden internen Wert unabhängig ausführen, dh führen Sie sie nicht einmal aus und kopieren Sie das Ergebnis. Überprüfen Sie vorher und nachher, ob alle internen Werte übereinstimmen. Wenn die Werte nicht übereinstimmen, können Sie den falschen Wert auf den am häufigsten verwendeten Wert aktualisieren. Wenn es keinen häufigsten Wert gibt, können Sie sicher benachrichtigen, dass ein Fehler vorliegt.

Auf diese Weise spielt es keine Rolle, ob eine Beschädigung in der ALU, in den Registern, im RAM oder auf einem Bus 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 - Ihr Stapelzeiger ist beispielsweise weiterhin anfällig.

Eine Nebengeschichte: Ich bin auf ein ähnliches Problem 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 Randfällen einen Fehler auslöste, der (manchmal) beschädigte Werte an Funktionen weitergab. Stellen Sie sicher, dass Ihr Gerät keine Probleme hat, bevor Sie die Radioaktivität dafür verantwortlich machen, und ja, manchmal handelt es sich um einen Compiler-Fehler =)

jkflying
quelle
1
Einige dieser Vorschläge haben etwas mit einer ähnlichen "Multi-Bit-Sanity-Check" -Mentalität zur Erkennung von Korruption zu
tun.
2
Es gibt Systeme auf der Welt, in denen jeder redundante Knoten von verschiedenen Teams mit einem Schiedsrichter entworfen und entwickelt wurde, um sicherzustellen, dass sie sich nicht versehentlich für dieselben Lösungen entschieden haben. Auf diese Weise gehen nicht alle für denselben Fehler aus, und ähnliche Transienten weisen keine ähnlichen Fehlermodi auf.
Jwdonahue
16

Haftungsausschluss: Ich bin kein Radioaktivitätsprofi und habe auch nicht für diese Art von Anwendung gearbeitet. Aber ich habe an weichen Fehlern und Redundanz für die langfristige Archivierung kritischer Daten gearbeitet, die etwas miteinander verbunden sind (gleiches Problem, unterschiedliche Ziele).

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

Die Frage ist dann: Wie kann man zuverlässig rechnen, wenn das Gedächtnis unzuverlässig ist?

Um die Rate weicher Fehler erheblich zu reduzieren (auf Kosten des Rechenaufwands, da es sich hauptsächlich um softwarebasierte Lösungen handelt), können Sie entweder:

  • Verlassen Sie sich auf das gute alte Redundanzschema und insbesondere auf die effizienteren 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. Mit dieser Art von Lösung müssen Sie jederzeit den vollständigen Status Ihres Programms in einer Mastervariablen / -klasse (oder einer Struktur?) Speichern, eine ECC berechnen und überprüfen, ob die ECC korrekt ist, bevor Sie etwas tun, und wenn 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 funktioniert nicht, wenn nicht, da ECC Ihnen mitteilen kann, wenn etwas nicht stimmt, und in diesem Fall können Sie Ihre Software stoppen, damit Sie keine falschen Ergebnisse erhalten).

  • oder du kannst verwenden belastbare algorithmische Datenstrukturen verwenden, die bis zu einem gewissen Grad garantieren, dass Ihr Programm auch bei weichen Fehlern korrekte Ergebnisse liefert. Diese Algorithmen können als eine Mischung aus gängigen algorithmischen Strukturen mit nativ eingemischten ECC-Schemata angesehen werden. Dies ist jedoch wesentlich widerstandsfähiger, da das Ausfallsicherheitsschema eng an die Struktur gebunden ist, sodass Sie keine zusätzlichen Prozeduren codieren müssen um die 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 ausfallsicher codieren und den Rest mit den verbrauchbaren Daten, die Sie aus den Hauptdatenstrukturen neu berechnen können).

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

  • Einführung in Datenstrukturen für elastische Algorithmen von Giuseppe F.Italiano, Universität Roma "Tor Vergata"

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

  • Ferraro-Petrillo, U., Grandoni, F. & Italiano, GF (2013). Datenstrukturen, die gegenüber Speicherfehlern widerstandsfähig sind: eine experimentelle Untersuchung von Wörterbüchern. Journal of Experimental Algorithmics (JEA), 18, 1-6.

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

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

/ EDIT: Ich habe die Verhinderung / Wiederherstellung von Soft-Fehlern hauptsächlich für RAM-Speicher und Datenspeicherung veranschaulicht, aber ich habe nicht über Rechenfehler (CPU) gesprochen . Andere Antworten wiesen bereits auf die Verwendung atomarer Transaktionen wie in Datenbanken hin, daher werde ich ein anderes, einfacheres Schema vorschlagen: Redundanz und Mehrheitsentscheidung .

Die Idee ist, dass Sie einfach x-mal dieselbe 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 eine Mehrheitsentscheidung verwenden, um den korrekten Wert zu erhalten. Da dies bedeutet, dass die Berechnung teilweise beschädigt wurde, 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 ausfallsichere Prozedur auszulösen (Neustart, Benachrichtigung des Benutzers usw.).

Dieses Redundanzschema ist im Vergleich zu ECC (praktisch O (1)) sehr schnell und liefert Ihnen bei Bedarf ein klares Signal ausfallsicher sein müssen . Es ist auch (fast) garantiert, dass die Mehrheitsentscheidung niemals eine beschädigte Ausgabe erzeugt und sich auch von geringfügigen Rechenfehlern erholt , da die Wahrscheinlichkeit, dass x-Berechnungen dieselbe Ausgabe liefern, infinitesimal ist (da es eine große Menge möglicher Ausgaben gibt, ist dies fast unmöglich zufällig 3 mal gleich bekommen, noch weniger Chancen wenn x> 3).

Mit Stimmenmehrheit sind Sie also vor einer beschädigten Ausgabe sicher, und mit Redundanz x == 3 können Sie 1 Fehler wiederherstellen (mit x == 4 sind 2 Fehler wiederherstellbar usw. - die genaue Gleichung lautet, nb_error_recoverable == (x-2)wo x die Zahl ist von Berechnungswiederholungen, da Sie mindestens 2 zustimmende Berechnungen benötigen, um sich mit der Mehrheit der Stimmen zu erholen).

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

Wenn Sie besonders sicherstellen möchten, dass die Berechnungen korrekt durchgeführt werden, können Sie, wenn Sie Ihre eigene Hardware erstellen können, Ihr Gerät mit x CPUs konstruieren und das System so verkabeln, dass die Berechnungen automatisch mit einer Mehrheitsentscheidung über die x CPUs dupliziert werden mechanisch am Ende (zum Beispiel mit UND / ODER-Gattern). Dies wird häufig in Flugzeugen und unternehmenskritischen Geräten implementiert (siehe dreifache modulare Redundanz ). Auf diese Weise hätten Sie keinen Rechenaufwand (da die zusätzlichen Berechnungen parallel durchgeführt werden) und Sie haben eine weitere Schutzschicht vor weichen Fehlern (da die Duplizierung der Berechnung und die Mehrheitsentscheidung direkt von der Hardware und nicht von verwaltet werden Software - die leichter beschädigt werden kann, da ein Programm einfach aus im Speicher gespeicherten Bits besteht ...).

gaborous
quelle
9

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

Die Antwort ist normalerweise ein automatisierter Komponententest. Schreiben Sie Testkabelbäume, die den Code auf dem Entwicklungssystem ausführen, und führen Sie dann dieselben Testkabelbäume auf dem Zielsystem aus. Suche nach Unterschieden!

Überprüfen Sie auch Ihr eingebettetes Gerät auf Errata. Möglicherweise haben Sie etwas mit "Tun Sie dies nicht, da es abstürzt, aktivieren Sie also diese Compiler-Option und der Compiler wird es umgehen".

Kurz gesagt, Ihre wahrscheinlichste Ursache für Abstürze sind Fehler in Ihrem Code. Machen Sie sich (noch) keine Sorgen über esoterischere Fehlermodi, bis Sie verdammt sicher sind, dass dies nicht der Fall ist.

Graham
quelle
1
Nirgendwo im Test der Frage erwähnt der Autor, dass die Anwendung außerhalb der radioaktiven Umgebung einwandfrei funktioniert.
23. März 77,
9

Sie möchten mehr als 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 einen Hardware-Watchdog haben, und der Aufruf, sie zu stoß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 Verbindungsverlust zum Master innerhalb weniger Sekunden einem Neustart gleichkommt.

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

Bearbeiten: Aus den Kommentaren habe ich das Bedürfnis, die "CRC-Idee" zu klären. Die Möglichkeit, dass der Slave seinen eigenen Watchdog stößt, ist nahe Null, wenn Sie die Beule mit CRC umgeben oder zufällige Daten vom Master auf Digest prüfen. Diese zufälligen Daten werden nur vom Master gesendet, wenn der zu untersuchende Slave mit den anderen ausgerichtet ist. Die Zufallsdaten und CRC / Digest werden sofort nach jeder Erhebung gelöscht. Die Master-Slave-Bump-Frequenz sollte mehr als doppelt so hoch sein wie das Watchdog-Timeout. Die vom Master gesendeten Daten werden jedes Mal eindeutig generiert.

Jonas Byström
quelle
7
Ich versuche ein Szenario zu ergründen, in dem Sie einen Master außerhalb der Strahlungsumgebung haben können, der zuverlässig mit Slaves innerhalb der Strahlungsumgebung kommunizieren kann, in dem Sie die Slaves nicht einfach außerhalb der Strahlungsumgebung platzieren können.
Fostandy
1
@fostandy: Die Slaves messen oder steuern entweder mit Geräten, die eine Steuerung benötigen. Sagen Sie einen Geigerzähler. Der Master benötigt aufgrund der Slave-Redundanz keine zuverlässige Kommunikation.
Jonas Byström
4
Die Einführung eines Masters bedeutet nicht automatisch eine erhöhte Sicherheit. Wenn Slave x aufgrund einer Speicherbeschädigung verrückt geworden ist und sich wiederholt sagt "Master ist hier, Master ist glücklich", wird es nicht durch eine Anzahl von CRCs oder bellenden Befehlen des Masters gespeichert. Sie müssten dem Master die Möglichkeit geben, die Stromversorgung dieses Sklaven zu unterbrechen. Wenn Sie einen Fehler mit häufigen Ursachen haben, erhöht das Hinzufügen weiterer Slaves die Sicherheit nicht. Denken Sie auch daran, dass die Anzahl der Softwarefehler und die Anzahl der Dinge, die kaputt gehen können, mit der Komplexität zunehmen.
Lundin
5
Abgesehen davon wäre es natürlich schön, so viel Programm wie möglich an einen weniger exponierten Ort auszulagern und gleichzeitig die Elektronik in der radioaktiven Umgebung so einfach wie möglich zu halten, wenn Sie diese Option haben.
Lundin
7

Wie wäre es, wenn Sie viele Instanzen Ihrer Anwendung ausführen. Wenn Abstürze auf zufällige Änderungen der Speicherbits zurückzuführen sind, schaffen es wahrscheinlich einige Ihrer App-Instanzen, genaue Ergebnisse zu erzielen. Es ist wahrscheinlich ziemlich einfach (für jemanden mit statistischem Hintergrund) zu berechnen, wie viele Instanzen Sie bei gegebener Bit-Flop-Wahrscheinlichkeit benötigen, um einen so kleinen Gesamtfehler zu erzielen, wie Sie möchten.

ren
quelle
2
Sicherlich würde ein eingebettetes System sicherheitskritische Fänge in einer Instanz einer robusten Anwendung viel vorziehen, als nur mehrere Instanzen abzufeuern, die Hardwareanforderungen zu erhöhen und in gewissem Maße auf blindes Glück zu hoffen, dass mindestens eine Instanz in Ordnung ist? Ich habe die Idee und sie ist gültig, aber ich
neige
7

Was Sie fragen, ist ein ziemlich komplexes Thema - nicht leicht zu beantworten. Andere Antworten sind in Ordnung, aber sie decken nur einen kleinen Teil aller Dinge ab, die Sie tun müssen.

Wie aus den Kommentaren hervorgeht , ist es nicht möglich, Hardwareprobleme zu 100% zu beheben. Es ist jedoch mit hoher Wahrscheinlichkeit möglich, sie mithilfe verschiedener Techniken zu reduzieren oder abzufangen.

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

BЈовић
quelle
11
Oder besser gesagt, lesen Sie die technischen Anforderungen durch und implementieren Sie die sinnvollen. Ein großer Teil der SIL-Standards ist Unsinn. Wenn Sie sie dogmatisch befolgen, erhalten Sie unsichere und gefährliche Produkte. Bei der heutigen SIL-Zertifizierung geht es hauptsächlich darum, eine Menge Dokumentation zu erstellen und dann ein Testhaus zu bestechen. Die SIL-Stufe sagt nichts über die tatsächliche Sicherheit des Systems aus. Stattdessen möchten Sie sich auf die tatsächlichen technischen Sicherheitsmaßnahmen konzentrieren. Es gibt einige sehr gute in den SIL-Dokumenten, und es gibt einige völlige Unsinn.
Lundin
7

Jemand erwähnte die Verwendung langsamerer Chips, um zu verhindern, dass Ionen so leicht Bits umdrehen. In ähnlicher Weise verwenden Sie möglicherweise eine spezielle CPU / RAM, die tatsächlich mehrere Bits zum Speichern eines einzelnen Bits verwendet. Somit 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 Zugriffszeit, aber eine viel zuverlässigere Datendarstellung. Sie können dies wahrscheinlich sowohl auf Softwareebene mit einem spezialisierten Compiler (zuweisen x mehr Speicherplatz für alles) als auch zur Sprachimplementierung (Write Wrapper für Datenstrukturen, die Dinge auf diese Weise zuweisen) tun.

Alex C.
quelle
7

Vielleicht wäre es hilfreich zu wissen, ob die Hardware "für diese Umgebung ausgelegt" ist. Wie korrigiert und / oder zeigt es das Vorhandensein von SEU-Fehlern an?

Bei einem Weltraumforschungsprojekt hatten wir eine benutzerdefinierte MCU, die eine Ausnahme / Unterbrechung bei SEU-Fehlern auslöste, aber mit einer gewissen Verzögerung, dh einige Zyklen können vergehen / Anweisungen werden nach dem einen ausgeführt, der die SEU-Ausnahme verursacht hat.

Besonders anfällig war der Datencache, sodass ein Handler die fehlerhafte Cache-Zeile ungültig machte und das Programm neu startete. Nur dass aufgrund der Ungenauigkeit der Ausnahme die Reihenfolge der Insns, die von der Ausnahme ausgelöst werden, die Insn auslöst, möglicherweise nicht neu gestartet werden kann.

Wir haben die gefährlichen (nicht neu startbaren) Sequenzen identifiziert (wie lw $3, 0x0($2), gefolgt von einem Insn, das modifiziert $2und nicht datenabhängig ist $3), und ich habe Änderungen an GCC vorgenommen, sodass solche Sequenzen nicht auftreten (z. B. als letzter Ausweg, der die trennt) zwei insns von anop ).

Nur etwas zu beachten ...

Ausruhen
quelle
7

Wenn Ihre Hardware ausfällt, können Sie sie mithilfe eines mechanischen Speichers wiederherstellen. Wenn Ihre Codebasis klein ist und über physischen Speicherplatz verfügt, können Sie einen mechanischen Datenspeicher verwenden.

Geben Sie hier die Bildbeschreibung ein

Es wird eine Materialoberfläche geben, die nicht durch Strahlung beeinträchtigt wird. Es werden mehrere Gänge vorhanden sein. Ein mechanisches Lesegerät läuft auf allen Zahnrädern und kann flexibel auf und ab bewegt werden. Ab bedeutet, dass es 0 ist, und auf bedeutet, dass es 1 ist. Aus 0 und 1 können Sie Ihre Codebasis generieren.

Hitul
quelle
2
Vielleicht würde ein optisches Medium wie eine CD-ROM diese Definition erfüllen. Es hätte den zusätzlichen Bonus einer großen Kapazität.
Wossname
2
Ja, es wird ähnlich sein, aber CD-ROM wird weniger verwenden, aber dies wird ein vollmechanisches System sein.
Hitul
7
Ich frage mich, ob es einen Grund gibt, warum sie im Weltraum keine Lochkartenleser verwenden.
Soren
3
@Soren Geschwindigkeit und physischer Raum können ein Grund sein.
Hitul
5

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 Stapel zwischen den Zyklen neu initialisieren. Verwenden Sie die Stapel nicht für Interrupt-Aufrufe, sondern richten Sie für jeden wichtigen Interrupt-Aufruf einen separaten Stapel ein.

Ähnlich wie beim Watchdog-Konzept sind Deadline-Timer. Starten Sie einen Hardware-Timer, bevor Sie eine Funktion aufrufen. Wenn die Funktion nicht zurückkehrt, bevor der Deadline-Timer unterbrochen wird, laden Sie den Stapel neu und versuchen Sie es erneut. Wenn es nach 3/5 Versuchen immer noch fehlschlägt, müssen Sie es aus dem 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, Datenvornahme, Hauptalgorithmus und Implementierung / Übertragung der Ergebnisse. Dies bedeutet, dass ein Fehler in einem Teil keine Fehler im Rest des Programms verursacht. Während wir also die Signalerfassung reparieren, werden die restlichen Aufgaben mit veralteten Daten fortgesetzt.

Alles braucht CRCs. Wenn Sie nicht genügend RAM haben, 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 generieren, und einige Prozessoren verfügen über dedizierte Hardware für CRC-Berechnungen, aber ich denke, das würde nicht in den Rahmen Ihrer Frage fallen. Durch Überprüfen der CRCs wird der ECC-Controller im Speicher außerdem aufgefordert, Einzelbitfehler zu reparieren, bevor ein Problem auftritt.

Gerhard
quelle
4

Erstens gestalten Sie Ihre Anwendung um Versagen . Stellen Sie sicher, dass im Rahmen des normalen Durchflussbetriebs ein Zurücksetzen erwartet wird (abhängig von Ihrer Anwendung und der Art des Fehlers, entweder weich oder hart). Dies ist schwer zu perfektionieren: Kritische Vorgänge, die ein gewisses Maß an Transaktionsfähigkeit erfordern, müssen möglicherweise auf Baugruppenebene überprüft und optimiert werden, damit eine Unterbrechung an einem wichtigen Punkt nicht zu inkonsistenten externen Befehlen führen kann. Fehler schnell ausfallen, sobald eine nicht behebbare Speicherbeschädigung oder Abweichung des Kontrollflusses festgestellt wird. Protokollieren Sie nach Möglichkeit Fehler.

Zweitens, wenn möglich, korrigieren Sie die Korruption und fahren Sie fort . Dies bedeutet, dass konstante Tabellen (und Programmcode, wenn möglich) häufig überprüft und korrigiert werden. Vielleicht vor jeder größeren Operation oder bei einem zeitgesteuerten Interrupt und Speichern von Variablen in Strukturen, die automatisch korrigiert werden (erneut vor jeder größeren Operation oder bei einem zeitgesteuerten Interrupt nehmen Sie eine Mehrheit von 3 und korrigieren Sie, wenn es sich um eine einzelne Abweichung handelt). Wenn möglich, Korrekturen protokollieren.

Drittens Testfehler . Richten Sie eine wiederholbare Testumgebung ein, in der Bits im Speicher pseudozufällig umgedreht werden. Auf diese Weise können Sie Korruptionssituationen replizieren und Ihre Anwendung um diese herum entwerfen.

MrBigglesworth
quelle
3

Angesichts der Kommentare von Supercat, der Tendenzen moderner Compiler und anderer Dinge wäre ich versucht, in die Antike zurückzukehren und den gesamten Code überall in Assembly- und statischen Speicherzuordnungen zu schreiben. Für diese Art von absoluter Zuverlässigkeit verursacht die Montage meines Erachtens keinen großen prozentualen Unterschied der Kosten mehr.

Joshua
quelle
Ich bin ein großer Fan der Assemblersprache (wie Sie meinen Antworten auf andere Fragen entnehmen können), aber ich denke nicht, dass dies eine gute Antwort ist. Es ist ziemlich gut zu wissen, was vom Compiler für den meisten C-Code zu erwarten ist (in Bezug auf die Werte in Registern im Vergleich zum Speicher), und Sie können jederzeit überprüfen, ob es das ist, was Sie erwartet haben. Das Handschreiben eines großen Projekts in asm ist nur eine Menge zusätzlicher Arbeit, selbst wenn Sie Entwickler haben, die mit dem Schreiben von ARM asm sehr vertraut sind. Wenn Sie beispielsweise das gleiche Ergebnis dreimal berechnen möchten, ist es möglicherweise sinnvoll, einige Funktionen in asm zu schreiben. (Compiler werden es weg CSE)
Peter Cordes
Das höhere Risiko, das sonst gegen das Upgrade des Compilers abgewogen werden muss, kann zu unerwarteten Änderungen führen.
Joshua
1

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

Etwas, das abstürzt oder nicht richtig funktioniert, kann auf eigene Fehler zurückzuführen sein. Dann sollte es leicht zu beheben sein, wenn Sie das Problem finden. Es besteht aber auch die Möglichkeit von Hardwarefehlern - und das ist insgesamt schwierig, wenn nicht unmöglich zu beheben.

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

Die Wiederherstellung nach einer solchen Fehlersituation erfolgt entweder durch einen Neustart (wenn die Software noch aktiv ist und funktioniert) oder durch einen Hardware-Reset (z. B. hw watchdogs). Einfacher mit dem ersten zu beginnen.

Wenn das Problem mit der Hardware zusammenhängt, sollte die Protokollierung Ihnen helfen, festzustellen, bei welchem ​​Funktionsaufrufproblem eintritt, und Ihnen so Insiderwissen darüber geben, was wo nicht funktioniert.

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

Wenn das Problem nach einiger Zeit auftritt - dann kann ein Stapelüberlauf vermutet werden -, ist es besser, Stapelpunktregister zu überwachen - wenn sie ständig wachsen.

Und wenn Sie es schaffen, Ihren Code vollständig zu minimieren, bis eine Anwendung der Art "Hallo Welt" - und sie immer noch zufällig fehlschlägt -, werden Hardwareprobleme erwartet - und es muss ein "Hardware-Upgrade" durchgeführt werden - was bedeutet, dass Sie eine solche CPU / RAM / ... erfinden. -Hardware-Kombination, die Strahlung besser verträgt.

Das Wichtigste ist wahrscheinlich, wie Sie Ihre Protokolle zurückerhalten, wenn der Computer vollständig gestoppt / zurückgesetzt / nicht funktioniert - wahrscheinlich sollte Bootstap als erstes einen Rückweg nach Hause tun, wenn eine problematische Situation festgestellt wird.

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-Remote-Debugging-Umgebung zu erstellen, aber dann müssen mindestens Kommunikationsmedien funktionieren und ein Prozessor / ein RAM im Betriebszustand sein. Und mit Remote-Debugging meine ich entweder einen 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, Aufrufstapel herunterladen, RAM herunterladen, Neustart).

TarmoPikaro
quelle
Entschuldigung, aber die Frage bezieht sich auf eine radioaktive Umgebung, in der Hardwarefehler auftreten. Ihre Antwort bezieht sich auf die allgemeine Softwareoptimierung und das Auffinden von Fehlern. Aber in dieser Situation werden die Fehler nicht durch Fehler verursacht
jeb
Ja, Sie können auch die Erdgravitation, Compiler-Optimierungen, Bibliotheken von Drittanbietern, radioaktive Umgebungen usw. verantwortlich machen. Aber bist du sicher, dass es nicht deine eigenen Fehler sind? :-) Sofern nicht bewiesen - ich glaube nicht. Ich habe einmal ein Firmware-Update ausgeführt und die Ausschaltsituation getestet. Meine Software hat alle Ausschaltsituationen erst überstanden, nachdem ich alle meine eigenen Fehler behoben habe. (Über 4000 Ausschaltungen während der Nacht) Aber es ist schwer zu glauben, dass es in einigen Fällen einen Fehler gab. Besonders wenn es um Speicherbeschädigung geht.
TarmoPikaro
0

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 Verbindungsstelle, die Taktfrequenz, den Hersteller, das Gehäuse usw. variieren, wird ein anderes Verhalten beobachtet.

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


quelle