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?
Antworten:
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 )
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.
... 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!
... 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:
... kopieren ... irgendwo ... irgendwo redundante Software / Firmware haben.
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.
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).
... 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.
... 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:
Fehlererkennungs- und / oder Fehlerkorrekturalgorithmus im Kommunikationsprotokoll zwischen Subsystemen. Dies ist ein weiteres Muss, um unvollständige / falsche Signale von anderen Systemen zu vermeiden
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.
quelle
Die NASA hat ein Papier über strahlungsgehärtete Software. Es beschreibt drei Hauptaufgaben:
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
Und genau so hat die NASA C ++ für große Projekte wie den Mars Rover verwendet .
Sie haben bestimmte C ++ - Funktionen vermieden, die Probleme verursachen könnten:
new
unddelete
)new
, um die Möglichkeit einer Beschädigung des Systemheaps zu vermeiden).quelle
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
objdump
diese 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
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.
quelle
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)
bein
Vergleichen 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 ".
quelle
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:
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.
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.
WICHTIG: Implementieren Sie keine Abhängigkeit von den Standardwerten der Variablen für die statische Speicherdauer. Vertrauen Sie also 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 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
static
ist, 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
.data
und.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.
quelle
TRUE
gleichzusetzen .0xffffffff
POPCNT
%01010101010101010101010101010101
, XOR dann POPCNT?.text
Abschnitt umdrehen und einen Operationscode oder ähnliches ändern.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==42
wenn der Compiler weiß, dass esx
unmöglich ist, etwas anderes zu halten, darin besteht, dass der Programmierer dies verhindern möchte die Ausführung eines bestimmten Codes mitx
einem 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
volatile
ist 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: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 auftrittprepare_for_activation()
, würde dies bedeuten, dass die Aktivierung angemessen gewesen wäre (daprepare_for_activation()
vor dem Fehler kein anderer Grund aufgerufen worden wäre). Wenn der Fehler dazu führt, dass der Codeprepare_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, wirdprepare_for_activation()
zurückgegeben, aber der Aufruf voncancel_preparations()
wäre zwischen den Aufrufen vonprepare_for_activation()
und aufgetretentrigger_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.
quelle
-O0
oder 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.-O2
.-O0
eine 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.-O0
eine 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-O2
helfen dort.v1=v2+0xCAFEBABE
und alle Aktualisierungen der beiden Variablen durchgeführt werden ...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 inx1
,x2
undx3
und 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.
quelle
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.
quelle
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
n
wird (wobein
größ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.
quelle
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
(unddouble
,int64_t
usw.), machen sie ihre eigenen ,SAFE_uint32_t
die 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 =)
quelle
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 :
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 ...).
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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$2
und 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 ...
quelle
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.
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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).
quelle
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