// Die Schleife wird immer gleichoft durchlaufen, egal welche Taste
15
// gedrueckt ist
16
for(i=0;i<N_KEYVALUE-1;i++){
17
18
// Division durch 2 vor der Addition erhoeht Ungenauigkeit auf
19
// 2, bleibt aber immer im Wertebereich uint8_t.
20
thresh=keyvalue[i]/2+keyvalue[i+1]/2;
21
22
if(aval<thresh){
23
// Diese Zuweisung erfolgt unterschiedlich oft, je nachdem
24
// welche Taste gedrueckt ist
25
keystate=i;
26
}
27
else{
28
// Wird wegoptimiert, zeigt aber, was ich meine
29
dummy=i;
30
}
31
}
32
33
returnkeystate;
34
}
Jetzt will ich dafür sorgen, daß diese Funktion immer möglichst gleich
lange zur Ausführung benötigt, egal mit welchem Eingabewert sie
aufgerufen wird.
In der bestehenden Form ist der Unterschied zwischen einzelnen Aufrufen
bis zu fünfmal dem Sprung + Zuweisung, und die dummy-Variable wird
ohnehin wegoptimiert.
Gibt es unter C überhaupt eine sinnvolle Möglichkeit, eine Funktion
konstanter Laufzeit zu implementieren und wenn ja: wie?
Viele Grüße
W.T.
Peter Dannegger schrieb:Frank M. schrieb:> Starte zu Beginn der Funktion einen Timer und warte am Ende der Funktion> darauf, dass dieser Timer abläuft.
Ich hab's schon befürchtet...
Peter Dannegger schrieb:> Warum machst Du die Berechnung der Schwellen nicht gleich in der> Tabelle?
Reine Faulheit - der µC langweilt sich in dieser Anwendung eh zu Tode.
So kann ich einfach alle Tasten mal drücken, den Rohwert auf dem Display
anzeigen lassen und dann direkt in die Tabelle tippen.
Die Frage nach konstanter Laufzeit ist auch nur aus Neugier und weniger
aus Nutzen.
Und ich sehe, Du hast auch hierfür mal wieder eine fertige Library
geschrieben und veröffentlicht. Sehr schön.
Würde nicht statt der Dummy-Zuweisung
keystate = N_KEYVALUE-1;
ausreichen?
Dies sollte nicht wegoptimiert werden, bin aber nicht sicher, ob das
schneller geht, da kein Variablenzugriff erfolgt.
Guest schrieb:> Würde nicht statt der Dummy-Zuweisung> keystate = N_KEYVALUE-1;> ausreichen?
Das würde die Laufzeit ändern - aber es würde nicht mehr das Gleiche aus
der Funktion herauskommen.
Walter Tarpan schrieb:> Guest schrieb:>> Würde nicht statt der Dummy-Zuweisung>> keystate = N_KEYVALUE-1;>> ausreichen?>> Das würde die Laufzeit ändern - aber es würde nicht mehr das Gleiche aus> der Funktion herauskommen.
Stimmt. Ist wohl noch zu früh..
Walter Tarpan schrieb:> Gibt es unter C überhaupt eine sinnvolle Möglichkeit, eine Funktion> konstanter Laufzeit zu implementieren und wenn ja: wie?
Konstante Laufzeit = konstanter Code (bei jedem Programmaufruf wird der
selbe code durchlaufen
-> keinerlei Programmverzweigung (while/for/if/switch) verwenden
-> loop unrooling
-> ...
Alternativ kann man dafür sorgen das das aufrufende programm immer zur
selben zeit weitermacht:
//WDT/timer etc aktivieren
//"konstante" Funktion aufrufen
//endless loop|sleep
//Einsprung nach WDT-IRQ
MfG,
Markus F. schrieb:> Du könntest dummy und keystate volatile deklarieren, dann sollte die> Laufzeit konstant werden.
Gefährlicher Ansatz. Man weiss nie genau, was der Compiler sonst noch
optimieren könnte oder ob die verwendeten Sprungbefehle alle gleich
viele Taktzyklen brauchen.
Die einzig saubere Lösung IST hier der Timer. Alles andere kommt nur
dann in Frage, wenn man haargenau weiss, was der Compiler und der
Prozessor daraus machen UND sich sicher ist, dass dies für alle
Zielplattformen gilt. Aber dann schreibt man sowas sowieso besser in
Assembler.
Timer hat den Nachteil, das man eine bestimmte Zeit festsetzt, Jahre
spaeter einen Parameter aendert, die Funktion dann laenger braucht als
der Timer und dann bekommt man die schoensten Fehler. Also wenn timer,
dann muss auch eine Fehlermeldung weitergegeben werden falls er schon
abgelaufen ist. Zudem scheint es ja hier auf einzelne Taktzyklen
anzukommen, dies ist m.M.n nicht oder nur mit hohem Aufwand mit einem
Timer machbar.
Moegliche Alternative: Funktion in eigene Datei und ohne Optimierung nur
diese Datei kompilieren.
Dumdi Dum schrieb:> Timer hat den Nachteil, das man eine bestimmte Zeit festsetzt, Jahre> spaeter einen Parameter aendert, die Funktion dann laenger braucht als> der Timer und dann bekommt man die schoensten Fehler.
Stimmt.
Dumdi Dum schrieb:> Moegliche Alternative: Funktion in eigene Datei und ohne Optimierung nur> diese Datei kompilieren.
Und auch hier: Was passiert, wenn beim Linken nochmals optimiert wird?
Generell muss man zu der Frage sagen: Kommt drauf an, was du genau
willst. Und eine immer sichere Lösung für das Problem gibt es ganz
sicher nicht. Du wirst den Ansatz immer für den konkreten Zweck anpassen
und prüfen müssen.
Stefan schrieb:> Ich frag mich ehr warum eine Funktion zur Tastenauswertung immer die> gleiche Ausführungszeit braucht.
Z.B. damit Wim van Eck nicht aus mehreren Metern Entfernung hören kann
welche Tasten am Geldautomaten gerdrückt wurden.
P. M. schrieb:> Gefährlicher Ansatz. Man weiss nie genau, was der Compiler sonst noch> optimieren könnte oder ob die verwendeten Sprungbefehle alle gleich> viele Taktzyklen brauchen.>> Die einzig saubere Lösung IST hier der Timer.
Gefährlich? Man kann's auch übertreiben.
Ich habe nicht den Eindruck, daß es hier unbedingt auf die Mikrosekunde
ankommt (in anderen Fällen mag das anders sein).
Auch der Timer ist - je nach Auflösung - nicht unbedingt die Garantie
dafür, daß die Laufzeiten exakt konstant bleiben. Je nachdem, wo der
Programmzähler beim Ablaufen des Timers in der Abfrageschleife grad
steht, kann's auch hier Abweichungen geben.
Wenn man's denn unbedingt ganz genau haben will, wird man um Assembler
und Taktzyklenzählen nicht rumkommen.
Stefan schrieb:> Ich frag mich ehr warum eine Funktion zur Tastenauswertung immer die> gleiche Ausführungszeit braucht.
Es sind schon Patienten verstrahlt worden weil der User schneller tippte
als das System erlaubt:
https://de.wikipedia.org/wiki/Therac-25#Programmfehler
MfG,
P. M. schrieb:> Und auch hier: Was passiert, wenn beim Linken nochmals optimiert wird?
Linker optimieren nicht. (Maximal schmeißen sie nicht genutzte Bereiche
weg. Der Bereich hier wird jedoch genutzt, wenn er nicht genutzt würde
dürfte er natürlich auch weggeschmissen werden.)
Hast Du ein Beispiel von einem Linker das .obj noch optimiert?
Fpga K. schrieb:> https://de.wikipedia.org/wiki/Therac-25#Programmfehler
Das ist zwar OT, aber wenn man die Programmierfehler liest, kann man aus
heutiger Sicht nur mit dem Kopf schütteln.
Aus meiner Sicht sind das eindeutig Zeichen, daß der Programmierer den
Code direkt in die Tastatur gehämmert hat.
Es fehlt einfach die Planung (Programmablaufplan). So einen PAP kann man
viel leichter auf logische Fehler überprüfen und vor allem, das können
auch nicht-Programmierer.
Auch zeigt es schön die Risiken des Multitasking, wenn man die dadurch
wegfallende deterministische Ausführung nicht berücksichtigt.
Beim Multitasking ist nichts atomar, das muß man sich immer wieder in
den Kopf hämmern. Ansonsten darf man es nicht benutzen.
Peter D. schrieb:> Fpga K. schrieb:>> https://de.wikipedia.org/wiki/Therac-25#Programmfehler>> Das ist zwar OT, aber wenn man die Programmierfehler liest
IMHO ist das schon On und nicht Offtopic. In älteren WP-Beschreibung
wurde der Fehler als "schneller getippt als vorgesehen" beschrieben.
Benutzt man nun eine (Tastatur-)Routine mit garantierter Laufzeit
vereinfacht man die (Test-) Szenarien in dem man solche Race-Conditions
von vornherein ausschliesst. Genau darin kann man den Sinn sehen ->
Stefan schrieb:> Ich frag mich ehr warum eine Funktion zur Tastenauswertung immer die> gleiche Ausführungszeit braucht.https://de.wikipedia.org/wiki/Race_Condition
MfG
@Peter Dannegger (peda)
>> https://de.wikipedia.org/wiki/Therac-25#Programmfehler>Das ist zwar OT, aber wenn man die Programmierfehler liest, kann man aus>heutiger Sicht nur mit dem Kopf schütteln.
Nicht nur aus heutiger! Auch in den 80er Jahren gab es solide
Programmierer und Leute, die wissen was sie tun! Dort hat man
anscheinend einen totalen Amateur rangelassen und keinerlei
Qualitätssicherung betrieben. Und das bei einem nuklearmedizinischen
Gerät! Irre!
Heute würde man für jeden Toaster mehr CE-Prüfungsaufwand betreiben
müssen!
@ Fpga Kuechle (fpgakuechle) Benutzerseite
>Benutzt man nun eine (Tastatur-)Routine mit garantierter Laufzeit>vereinfacht man die (Test-) Szenarien in dem man solche Race-Conditions>von vornherein ausschliesst. Genau darin kann man den Sinn sehen ->
???
>> Ich frag mich ehr warum eine Funktion zur Tastenauswertung immer die>> gleiche Ausführungszeit braucht.>https://de.wikipedia.org/wiki/Race_Condition
Also wenn dir schon eine einfache Routine zur Tastaturauswertng Race
Conditions beschert, dann ist wohl nix mehr zu retten!
In wieviel Fällen hat High level Software (und das ist auch C) eine
konstante Laufzeit? In wie vielen Fällen wird explizit durch Tuning in
Funktionen erreicht?
Gegen Race Conditions gibt es ganz andere, sinnvolle Mittel! Funktionen
mit konstanter Laufzeit sind es in den seltensten Fällen.
Fpga K. schrieb:> https://de.wikipedia.org/wiki/Race_Condition
Race-Conditions und Laufzeit haben nichts miteinander zu tun.
Eine längere Laufzeit eines kritischen Teils kann aber dazu führen, daß
eine Race-Condition öfter eintritt und damit schneller debugt werden
kann.
Bzw. das Vertrödeln von Zeit in einer unkritischen Warteschleife kann
die Race-Condition wiederum seltener machen.
Eine Race-Condition hat man erst dann gefunden, wenn man den logischen
Fehler auch plausibel erklären kann.
Keinesfalls sollte man aber denken, daß durch planloses Umschreiben des
Codes die Race-Condition magisch verschwindet!
Peter D. schrieb:> Fpga K. schrieb:>> https://de.wikipedia.org/wiki/Race_Condition>> Race-Conditions und Laufzeit haben nichts miteinander zu tun.>
Doch. In Digitalschaltungen wie bspw. in FPGA's löst man race conditions
insbesonders die dadurch entstehenden Glitches in dem man die Logik
taktet also das Berechnungsergebnis erst nach eine Mindestlaufzeit
(Taktperiode)
abspeichert, einer Mindestzeit die ausreichend um die race conditions zu
klären.
https://en.wikipedia.org/wiki/Race_condition#ElectronicsPeter D. schrieb:>Keinesfalls sollte man aber denken, daß durch planloses Umschreiben des>Codes die Race-Condition magisch verschwindet!
Das ist keinesfalls planlos, der dahinter stehende Plan ist die
Verringerung der Komplexität zu einem beherrschbaren Level.
Mit dem erzwungenen Gleichlauf von Routinen nimmt man Komplexität aus
dem System - man muss das system nicht für alle möglichen Eingangsströme
auslegen sondern nur noch für eine begrenzte Untermenge. Man könnte auch
Paralleln zum Entprellen ziehen.
MfG,
Fpga K. schrieb:> Doch. In Digitalschaltungen wie bspw. in FPGA's löst man race conditions> insbesonders die dadurch entstehenden Glitches in dem man die Logik> taktet
Du schweifst vom Thema ab.
Wir waren hier bei CPUs und die sind immer getaktet.
Es ging auch nicht um Glitches, sondern um Race-Conditions.
Eine Race-Condition ist, wenn zwei Tasks die selben(n) Variable(n)
bearbeiten. Man muß genau diese Stelle finden und dann den Zugriff
atomar machen.
Planloses Umschreiben des Codes macht aber niemals etwas atomar und löst
damit die Race-Condition nicht. Es kann aber erheblich die
Warscheinlichkeit ändern und damit vorgaukeln, man hätte das Problem
gelöst.
Geht der Fehler nicht weg, sondern ändert sich nur dessen Häufigkeit,
ist das ein sicheres Zeichen dafür, daß man an der falschen Stelle
gesucht hat.
Wenn man so will, ist das "atomar" gleichbedeutend mit der
Synchronisation bei FPGAs. Ein Task wird solange verzögert, bis die
andere ihren atomaren Block beendet hat.
Peter D. schrieb:> Fpga K. schrieb:> Eine Race-Condition ist, wenn zwei Tasks die selben(n) Variable(n)> bearbeiten. Man muß genau diese Stelle finden und dann den Zugriff> atomar machen.
Ich beziehe mich auf die auch oben verlinkte beschreibung des Fehlers
als Folge eine racer condition:
"The software interlock could fail due to a "race condition". The defect
was as follows: a one-byte counter in a testing routine frequently
overflowed; if an operator provided manual input to the machine "at the
precise moment" that this counter overflowed, the interlock would fail.
aus: https://en.wikipedia.org/wiki/Therac-25#Problem_description
Die Ursache war also das der overflow und die Operatoreingabe
gleichzeitig auftrat.
Dies kann man verhindern in dem die Maximaldauer des einen prozesses auf
einen Wert kleiner als als die Minimaldauer des anderen prozesses (bspw
Tastatureingabe) begrenzt.
MfG,
Fpga K. schrieb:> Dies kann man verhindern in dem die Maximaldauer des einen prozesses auf> einen Wert kleiner als als die Minimaldauer des anderen prozesses (bspw> Tastatureingabe) begrenzt.
Das ist ein Spiel mit dem Feuer, bzw. bei Multitasking schlichtweg nicht
möglich.
Der Scheduler verteilt die CPU-Zeit auf alle Tasks gleichmäßig bzw. nach
ihrer Priorität.
Wann eine Task durchlaufen wurde, ist also rein zufällig und steht auch
in keiner Beziehung zu anderen Tasks.
Und die Dauer von Nutzereingaben kann man generell nicht bestimmen, da
ist jeder Mensch eben anders.
@ Fpga Kuechle (fpgakuechle) Benutzerseite
>Die Ursache war also das der overflow und die Operatoreingabe>gleichzeitig auftrat.>Dies kann man verhindern in dem die Maximaldauer des einen prozesses auf>einen Wert kleiner als als die Minimaldauer des anderen prozesses (bspw>Tastatureingabe) begrenzt.
Das halte ich für einen gefährlichen Irrtum! Das ist genauso "schlau",
wie ein Timing einer Digitlaschaltung mit RC-Gliedern hinzupfuschen!
Erstens darf kein Overflow auftreten, egal was passiert. Und zweitens
muss bei so einer Maschine ein einzelner, allein verantwortlicher
Prozess/Funktion existieren, der ALLE Parameter irgendwann mal
einfriert, dann prüft und entsprechend verarbeitet. So wie es
beschrieben wurde, schien das alles recht lax verzaht gewsesen zu sein
und diverse Prozesse konnten on the fly diverse Parameter immer wieder
ändern. Dort ist MASSIV gepfuscht worden. Angefangen beim Design bis zur
Qualitätssicherung! Und das hätte man auch mit Funktionen im konstanter
Laufzeit nicht verhindert!
Falk B. schrieb:> @ Fpga Kuechle (fpgakuechle) Benutzerseite>>>Die Ursache war also das der overflow und die Operatoreingabe>>gleichzeitig auftrat.>>Dies kann man verhindern in dem die Maximaldauer des einen prozesses auf>>einen Wert kleiner als als die Minimaldauer des anderen prozesses (bspw>>Tastatureingabe) begrenzt.>> Das halte ich für einen gefährlichen Irrtum!
Wo steckt da der Irrtum?
T1 <= Ta # Maximaldauer
T2 >= Tb # Minimaldauer
Ta < Tb # Parameterbedingung
-> T1 != T2
> Erstens darf kein Overflow auftreten, egal was passiert.
? Nö Overflow ist ein propates Mittel um Fehlzustände zu erkennen,
was nicht passieren darf ist das ein overflow der ein Fehlzuständ
signalisiert ignoriert oder ohne korrekte Behandlung zurückgesetzt wird
-> das scheint hier passiert zu sein.
> ...> Und das hätte man auch mit Funktionen im konstanter> Laufzeit nicht verhindert!
Hatt ja auch keiner behauptet. Es ist ja nur darauf hingewiesen worden
das eine Tastaturroutine mit konstanter Laufzeit das systemdesign
dahingehend vereinfacht das keine zu schnelle Eingaben passieren können.
Halt wie der Tiefpass bei der AD Wandlung die Aliaseffekte verhindert.
Nimm es einfach als eine HAL die Unterschiede in der Tippgeschwindigkeit
wegbügelt.
UART ohne built-in-FIFO wie der 8250 wären auch ein Grund für eine
Tastaturroutine mit konstanter Laufzeit.
Das man dennoch vor dem Schuß sicherstellen muß das die Kanone nicht auf
tödliche Dosis gestellt ist, bleibt davon unberührt.
MfG,
Fpga K. schrieb:> Wo steckt da der Irrtum?>> T1 <= Ta # Maximaldauer> T2 >= Tb # Minimaldauer>> Ta < Tb # Parameterbedingung
Darin, daß Du eine CPU mit einem FPGA verwechselst.
Die Tasks laufen nicht gleichzeitig ab, sondern ineinander
geschachtelt nacheinander. Ein CPU kann immer nur nacheinander
ausführen. Damit gibt es keinerlei Zeitbezug, der geprüft und
eingehalten werden kann.
Alle Tasks kriegen vom Scheduler in jeder Loop mindestens einmal
CPU-Zeit zugeteilt, das ist der einzige Zusammenhang.
Außerdem kann man die Minimalzeit kaum ermitteln. Wenn eine Task wenig
zu tun hat, sind das vielleicht 10 CPU-Tyklen. Die Maximalzeit kann
durchaus 10.000 mal länger sein. Damit sind Deine Bedingungen quasi
undurchführbar.
Und der Programmierer, der guten Gewissens absichtlich CPU-Zeit
verplempert, muß erst noch geboren werden.
Peter D. schrieb:> Und der Programmierer, der guten Gewissens absichtlich CPU-Zeit> verplempert, muß erst noch geboren werden.
Naja, z.B. im Krypto-Bereich wird ja schon darauf geachtet, daß z.B.
eine Routine immer gleichviel Zeit benötigt, egal wieviele Ziffern einer
PIN oder Stellen eines Schlüssels richtig oder falsch sind - um
Seitenkanalangriffe zu erschweren.
Oder ich kann mir einen Timer sparen, wenn die Berechnung einer
Stellgröße immer gleichlang dauert - dann kann ich den IRQ des
A/D-Wandlers direkt mitbenutzen, ohne daß die Ausgabe allzusehr jittert.
Fpga K. schrieb:> Ich beziehe mich auf die auch oben verlinkte beschreibung des Fehlers> als Folge eine racer condition:>> "The software interlock could fail due to a "race condition". The defect> was as follows: a one-byte counter in a testing routine frequently> overflowed; if an operator provided manual input to the machine "at the> precise moment" that this counter overflowed, the interlock would fail.>> aus: https://en.wikipedia.org/wiki/Therac-25#Problem_description>> Die Ursache war also das der overflow und die Operatoreingabe> gleichzeitig auftrat.
Kann man so nicht sagen.
Im Wikipedia Artikel ist ein Link zu einem PDF mit einer etwas genaueren
Beschreibung der Probleme. IMHO ist die Darstellung im Wiki etwas
verzerrend verkürzt.
Das Hauptproblem, so wie ich das sehe, war hier, dass man sich nicht
überlegt hat, wie Benutzereingaben ablaufen sollen.
Wenn Werte eingestellt werden, der Benutzer danach auf 'Los' drückt und
danach kann ich die Werte immer noch verändern, ohne dass ich zuerst mal
die Maschine stoppen muss, dann ist da im Benutzerinterface was schief
gelaufen.
Wenn ich das schon lese: das Programm überwacht ob der Cursor rechts
unten ist bzw. ob er das Ende einer Zeile erreicht hatte", dann läuft es
mir kalt runter.
Aber, das war in der damaligen Zeit noch so. Die wurde noch von der IBM
Systematik des Ausfüllens von Masken dominiert. Nur: wenn man
realisiert, dass der Benutzer an einer Maske was verändert hat, dann
muss die *komplette' Maske neu ausgewertet werden. Mit derartigen
'dieses und jenes hat sich verändert also muss auch nur dieses und jenes
intern verändert werden' schiesst man sich immer nur selbst ins Knie.
Spätestens wenn dann in der Programmlogik intern noch Dinge im
nachhinein voneinander abhängig gemacht werden, sind Fehler
vorprogrammiert. Und wenn die Maschine erst mal läuft, dann sind alle
Eingaben gesperrt und fix. Man kann ja immer noch 2 Sets an Werten
haben. Die einen die der Benutzer zu Gesicht bekommt und die andere, mit
der die Maschine arbeitet. Beim Start wird von einem Set ins andere
übernommen. Aber im bereits angelaufenen Betrieb, noch dazu in einem
sicherheitskritischen Bereich, darf es nicht vorkommen, dass der
Benutzer noch Arbeitsparameter ändern kann. Eine Änderung bedeutet:
Maschine stoppt und der ganze Prozess läuft von vorne weg erneut los.
Inklusive Prüfung der kompletten Eingangswerte.
Das ganze war eine Fehldesign.
Und auch: Späte 70-er Jahre, frühe 80-er Jahre. Das war die Zeit, als
man jedem, der irgendwas mit Physik oder Technik zu tun hatte, in die
Programmierung steckte. Tausende Physik-Lehrer können ein Lied davon
singen, dass sie im nächsten Semester plötzlich für den Informatik
Unterricht zuständig waren. Wer "F ist m mal a" sagen konnte und wem das
dann auch noch was sagte, wurde zum Informatiker befördert.
Peter D. schrieb:> Fpga K. schrieb:>> Wo steckt da der Irrtum?> Darin, daß Du eine CPU mit einem FPGA verwechselst.> Die Tasks laufen nicht gleichzeitig ab, sondern ineinander> geschachtelt nacheinander. Ein CPU kann immer nur nacheinander> ausführen. Damit gibt es keinerlei Zeitbezug, der geprüft und> eingehalten werden kann.
???
time(), uptime(), clock() alles Zeitnormale auf die jeder Task zugreifen
kann. Ebenso sleep() resp. usleep() damit kann jeder task eine beliebige
"laufzeit" anfordern.
> Außerdem kann man die Minimalzeit kaum ermitteln. Wenn eine Task wenig> zu tun hat, sind das vielleicht 10 CPU-Tyklen. Die Maximalzeit kann> durchaus 10.000 mal länger sein. Damit sind Deine Bedingungen quasi> undurchführbar.
Also meines Wissens arbeiten timesharing machinen mit festen timeslots
Danach wird gewechselt. Die zeit für diesen context switch ist
ermittelbar, bei RT-systemen ist er sogar als Minimalzeit garantiert.
MfG,
Karl H. schrieb:> Im Wikipedia Artikel ist ein Link zu einem PDF mit einer etwas genaueren> Beschreibung der Probleme. IMHO ist die Darstellung im Wiki etwas> verzerrend verkürzt.
Offensichtlich, deshalb verweise ich auch immer das ich mich auf die
WP-Darstellung beziehe. Konkret auf diese
"Diese war völlig ungenügend und funktionierte nur dann, wenn der
Benutzer seine Eingaben relativ langsam machte. Aber nach einer gewissen
Einarbeitungszeit konnten die Benutzer die Eingaben schneller tätigen,
als der Therac-25 zwischen den verschiedenen Modi umgeschaltet werden
kann"
https://de.wikipedia.org/w/index.php?title=Therac-25&oldid=96876886#Programmfehler
MfG,
Fpga K. schrieb:> Karl H. schrieb:>>> Im Wikipedia Artikel ist ein Link zu einem PDF mit einer etwas genaueren>> Beschreibung der Probleme. IMHO ist die Darstellung im Wiki etwas>> verzerrend verkürzt.>> Offensichtlich, deshalb verweise ich auch immer das ich mich auf die> WP-Darstellung beziehe. Konkret auf diese
Schon klar.
Ich hab mich auch geirrt. Der Link stammt nicht aus dem Wiki
Es ist dieser hier
https://www.google.at/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=Therac-25
der die ganze Sache ein wenig ausführlicher beleuchtet, als es ein WIki
naturgemäss kann.
Aber wie sind wir eigentlich darauf gekommen?
Ach ja. Ausführungszeit.
Aus dem PDF geht hervor, dass die Ausführungszeit der Tastatureingabe
nicht die eigentlich wesentliche Ursache war. Sie war Mittel zum Zweck,
um das Problem hervorzurufen. Eigentliche Ursache waren ganz andere
Fehler.
Ich geh übrigens nicht mit der Meinung des PDF-Autors konform, dass man
den Bug leicht hätte beheben können, indem man das Flag an anderer
Stelle hätte löschen sollen. Ich seh nämlich oft auch, dass schon die
Verwendung von vielen Flags viele Softwareprobleme hervorrufen können.
Irgendwann landet man dann in der Falle, dass man den Überblock
verliert, wer wann warum und zu welchem Zeitpunkt welches Flag setzt und
was das jetzt bedeutet. Flags sind manchmal notwendig, manchmal aber
auch ein Zeichen für schlechtes Design.
Karl H. schrieb:> Wenn ich das schon lese: das Programm überwacht ob der Cursor rechts> unten ist bzw. ob er das Ende einer Zeile erreicht hatte", dann läuft es> mir kalt runter.
Ja das waren Zeiten, da hat die CPU bei Z80 Einplatinencomputer noch den
Videospeicher als Parameterspeicher benutzt.
Aber bei dem system ist doch von einem VT100 terminal die Rede. Sendet
das der Mainframe immer die aktuelle Cursorposition?
MfG
@ Karl Heinz (kbuchegg) (Moderator)
>Wenn Werte eingestellt werden, der Benutzer danach auf 'Los' drückt und>danach kann ich die Werte immer noch verändern, ohne dass ich zuerst mal>die Maschine stoppen muss, dann ist da im Benutzerinterface was schief>gelaufen.
Meine Rede!
>Benutzer noch Arbeitsparameter ändern kann. Eine Änderung bedeutet:>Maschine stoppt und der ganze Prozess läuft von vorne weg erneut los.>Inklusive Prüfung der kompletten Eingangswerte.>Das ganze war eine Fehldesign.
GENAU!
>Unterricht zuständig waren. Wer "F ist m mal a" sagen konnte und wem das>dann auch noch was sagte, wurde zum Informatiker befördert.
;-)
@ Fpga Kuechle (fpgakuechle) Benutzerseite
>> Das halte ich für einen gefährlichen Irrtum!>Wo steckt da der Irrtum?>T1 <= Ta # Maximaldauer>T2 >= Tb # Minimaldauer>Ta < Tb # Parameterbedingung>-> T1 != T2
Denkst du, diese diffusen Zeilen erklären oder beweisen IRGENDETWAS?
>> Erstens darf kein Overflow auftreten, egal was passiert.>? Nö Overflow ist ein propates Mittel um Fehlzustände zu erkennen,
OK.
>was nicht passieren darf ist das ein overflow der ein Fehlzuständ>signalisiert ignoriert oder ohne korrekte Behandlung zurückgesetzt wird>-> das scheint hier passiert zu sein.
Gut, das meinte ich dann wohl.
>> Und das hätte man auch mit Funktionen im konstanter>> Laufzeit nicht verhindert!>Hatt ja auch keiner behauptet.
Doch, das hattest du indirekt.
> Es ist ja nur darauf hingewiesen worden>das eine Tastaturroutine mit konstanter Laufzeit das systemdesign>dahingehend vereinfacht das keine zu schnelle Eingaben passieren können.
Auch das ist eine Aussage, der ich mich keine Sekunde anschließen kann.
Sie ist schlicht falsch. Wer schon mit einer Tastaturroutine mit
nichtkonstanter Laufzeit in Bedrängnis gerät, hat ein grundlegendes
Problem. Dass man prinzipiell die Komplexität eines Entwirfs möglichst
gering halten sollte, eben um die Testbarkeit zu verbessern bzw. zu
vereinfachen, ist davon unberührt.
>Halt wie der Tiefpass bei der AD Wandlung die Aliaseffekte verhindert.
Vollkommen unpassender Vergleich.
>Nimm es einfach als eine HAL die Unterschiede in der Tippgeschwindigkeit>wegbügelt.>UART ohne built-in-FIFO wie der 8250 wären auch ein Grund für eine>Tastaturroutine mit konstanter Laufzeit.
Irgendwie bist du besessen von der Idee mit der konstanten Laufzeit,
warum auch immer. Und wie Peter mehrfach feststellte, vermischt du hier
Hardwarelogik und Glitches mit Software.
>Das man dennoch vor dem Schuß sicherstellen muß das die Kanone nicht auf>tödliche Dosis gestellt ist, bleibt davon unberührt.
Aber eben DARUM geht es die ganze Zeit! Eine Funktion mit konstanter
Laufzeit hilft hier in keinster Weise! Race Conditions werden damit
nicht prinzipiell verhindert, schlimmstenfalls kaschiert, weil sie
seltener auftreten! Wie Karl heinz schon sagte hätte man den Fehler mit
ganz anderen Mitteln verhindern müssen (gescheites Softwaredesign).
Falk B. schrieb:> Denkst du, diese diffusen Zeilen erklären oder beweisen IRGENDETWAS?>> Vollkommen unpassender Vergleich.>> Irgendwie bist du besessen von der Idee mit der konstanten Laufzeit,> warum auch immer.> Und wie Peter mehrfach feststellte, vermischt du hier> Hardwarelogik und Glitches mit Software.>> Aber eben DARUM geht es die ganze Zeit!
Diesem Stakkato an wohlformulierten Argumenten habe ich nichts entgegen
zu setzen. Darum,
Over and Out
Sowas wie Therac-25 entsteht, wenn einer glaubt sein
Synchronisierungsproblem käme von der unterschiedlichen Laufzeit
verschiedener Softwarepfade. Manches muß nicht nur unter günstigen
Umständen funktionieren, sondern nie versagen. (wobei es nie im Sinne
von 0 sowenig existiert wie immer in Sinne von 100%)
Als bei einem Softwareunternehmen Arbeitender hab ich aber gelernt, daß
nicht solide Arbeit zählt, sondern wie man sein Halbwissen verkauft. Zum
Glück geht's bei uns nicht um Maschinen, die Menschen töten. Aber ich
bin mir sicher, der Therac-3000 Bug ist schon irgendwo in Arbeit. Von
einem, der sich so gut auskennt, daß er niemals an sich zweifeln würde.
Walter T. schrieb:> Jetzt will ich dafür sorgen, daß diese Funktion immer möglichst> gleich lange zur Ausführung benötigt, egal mit welchem Eingabewert> sie aufgerufen wird.
Ohne genaueres über die Hardware oder den Rest der Software (IRQs etc.)
zu wissen geht das nicht.
Falls die Ausführungszeiten einzelner Instruktionen statisch sind (keine
Cache-Effekte etc.), dann kann man versuchen den Vergleich in Arithmetik
aufzulösen, d.h. anstatt
1
if(a<b)
2
c=d;
wird der neue Wert per Maskierung zugewiesen:
1
uint16_tdelta=a<b;
2
delta=-(delta>>15);// in -1, 0
3
c=(c&~delta)|(d&delta);
Zusätzlich ist zu überprüfen, ob dies tatsächlich zu linearem Code
übersetzt wird, und für GCC zusätzlich
1
__attribute__((__noinline__,__noclone__))
Falls vom Compiler unterstützt (z.B. von gcc) oder wenn sizeof(int) > 2
geht auch
Johann L. schrieb:> d.h. anstatt> if (a < b)> c = d;> wird der neue Wert per Maskierung zugewiesen:> uint16_t delta = a < b;> delta = -(delta >> 15); // in -1, 0> c = (c & ~delta) | (d & delta);
Jetzt kommen wir der Sache näher. Wo lernt man solche Bitspielereien?
>Gibt es unter C überhaupt eine sinnvolle Möglichkeit, eine Funktion>konstanter Laufzeit zu implementieren und wenn ja: wie?
(es stellt sich hier zwar die Frage ob das überhaupt notwendig ist,
aber:)
nein, gibt es nicht
maximal wenn man sich auf EINE CPU einschränkt
den Compiler NIE updated,
ein paar "Randbedingungen" wie: SingleThread, keine IRQs,
funktionierender Quarz, KEIN first/second/usw level cache usw.
also maximal auf eine URALT CPU die seit 20 Jahren 1:1 identisch gebaut
wird..
Fpga K. schrieb:> Es ist ja nur darauf hingewiesen worden> das eine Tastaturroutine mit konstanter Laufzeit das systemdesign> dahingehend vereinfacht das keine zu schnelle Eingaben passieren können.
Das löst das Problem auf der völlig falschen Ebene.
Was man erreichen will, hat man explizit hinzuschreiben. Nebenwirkungen
(wie die Laufzeit) auszunutzen ist die schlimmste Art zu programmieren,
die ich kenne.
Apfelnudelsalat Rezept 1:
1kg Nudeln 10min lang kochen, dann abgießen. 20 Äpfel schälen und
kleinschneiden. Zusammenrühren.
Apfelnudelsalat Rezept 2:
1kg Nudeln zum kochen bringen. Dann 20 Äpfel schälen und kleinschneiden.
Ist man mit dem Kleinschneiden fertig, die Nudeln abgießen.
Zusammenrühren.
Ich verwende Rezept 2, weil ich Rezept 1 doof finde. Jetzt muss ich die
Schärfe und Länge meines Schälmessers anpassen, damit die Nudeln nicht
vermatschen. Wie geht das?
Josef G. schrieb:> Für Leute, die sich für Programme mit berechenbarer Ausführungszeit> interessieren
Auch ohne 'Schleife mit Hineinsprung' ist die Ausführungszeit
berechnbar, das ist nicht das Problem.
Und wenn sie nicht berechnbar ist (weil im Vorfeld keiner weiss,
wieviele Schleifeniterationen gemacht werden), dann ist sie das bei
deiner 'Schleife mit Hineinsprung' auch nicht.
Du löst schon wieder mal ein Problem, das in Wirklichkeit keines ist.
@ Karl Heinz (kbuchegg) (Moderator)
>Du löst schon wieder mal ein Problem, das in Wirklichkeit keines ist.
Und du redest schon wieder mit einem lernresistenten Menschen.
Karl H. schrieb:> Und wenn sie nicht berechnbar ist (weil im Vorfeld keiner weiss,> wieviele Schleifeniterationen gemacht werden)
Man zählt die Iterationen und führt danach
(Maxzahl-Istzahl) leere (Delay-) Schleifen aus.
Walter T. schrieb:> ich habe eine relativ einfache Funktion, die einen analogen Wert> klassiert:// Mittelwerte der einzelnen Tastendruecke abfallend sortiert> #define N_KEYVALUE 6> static const uint8_t keyvalue[N_KEYVALUE] = {255,159,101,63,24,0};>> /* Gedrueckte Taste an Widerstandsreihe erkennen> * aval: Analoger Wert> * return: Klassierter Wert */> uint8_t decodeAnalogKey(uint8_t aval)> {> uint8_t thresh, i, dummy;> uint8_t keystate = N_KEYVALUE-1;>> // Die Schleife wird immer gleichoft durchlaufen, egal welche Taste> // gedrueckt ist> for(i = 0; i<N_KEYVALUE-1; i++) {>> // Division durch 2 vor der Addition erhoeht Ungenauigkeit auf> // 2, bleibt aber immer im Wertebereich uint8_t.> thresh = keyvalue[i]/2+keyvalue[i+1]/2;>> if(aval < thresh ) {> // Diese Zuweisung erfolgt unterschiedlich oft, je nachdem> // welche Taste gedrueckt ist> keystate = i;> }> else {> // Wird wegoptimiert, zeigt aber, was ich meine> dummy = i;> }> }>> return keystate;> }>> Jetzt will ich dafür sorgen, daß diese Funktion immer möglichst gleich> lange zur Ausführung benötigt
Man kann die ganze Berechnung
keyvalue[i]/2+keyvalue[i+1]/2;
vorab machen
static const uint8_t thresh[N_KEYVALUE] = {207,130,82,44,12};
Dann kannst du prüfen ohne if
for(i = 0; i<N_KEYVALUE-1; i++) {
keystate = (keystate<<1) | (aval < thresh[i]) ;
Es kommt halt nicht 0..5 raus, sondern 0, 1, 3, 7, 15
Wenn das stört, kann man nochmal umsetzen
translate[]={0,1,0,2,0,0,0,4,0,0,0,0,0,0,0,15};
keystate = translate[keystate]
Und damit hat man konstante Laufzeit.
Wenn man verschiedene (und verschieden lang laufende) Pfade in einem
Programm hat und man muß egal welcher Pfad zu einem exakten Zeitpunkt
seit dem Start fertig sein, dann muß man eben am Ende auf diese
Maximallaufzeit synchronisieren. Also am Anfang Timer starten und am
Ende darauf warten. Dabei darf wegen nichtexistenter negativer Wartezeit
kein Code-Pfad länger laufen, als diese "Wunschzeit". Das Gänze per
Taktzyklenzählen lösen zu wollen, ist ein großer Aufwand, von vielen
Randbedingungen abhängig, die man nicht im Griff hat (Int's, die
ungeplant dazwischen funken, überigens auch bei delay_us()/delay_ms()
und lohnt sich allenfalls bei sowas wie "USB per Firmware".