Wie sieht es nun für String, Real usw. Datentypen aus?
[W]STRING ist ein Kapitel für sich. Sehr abhängig von der StringLänge und auch ein Bisschen von der Anzahl Bytes pro Zeichen (1 bei STRING vs. 2 bei WSTRING). Bei SPS sucht man auch oft vergebens Möglichkeiten, die in anderen Sprachen für die TextVerarbeitung sehr hilfreich sein können.
Ansonsten kann man grob einteilen nach der Länge der Daten, Bit alias BOOL, BYTE/CHAR inkl. SINT und USINT, Wort inkl. WORD und INT und UINT, DoppelWort inkl. DWORD und DINT und UNDINT und REAL, VierfachWort inkl. LINT und ULINT und LREAL.
Aber auch nach "ZahlenTypen" GleitKomma alias GleitPunkt einerseits und FestKomma alias FestPunkt alias Ganzzahl andererseits und auch noch BOOL als der grosse "Ausreisser".
Die Anzahl der Bytes eines DatenTyps besagt aber über die Schnelligkeit resp. die Langsamkeit von Operatoren mit diesen DatenTypen zunächst einmal nichts aus. Man kann nicht generell sagen, dass BYTE langsamer als BOOL ist oder INT langsamer als BYTE, DINT langsamer als INT, LDINT langsamer als DINT.
Arbeitet der "interne Prozessor" z.B. "bevorzugt" mit 32 Bit (DWORD, DINT, UDINT, REAL), so muss er mehr Aufand treiben bei längeren DatenTypen, aber wahrscheinlich auch bei kürzeren.
Das Bereitstellen/Isolieren eines bestimmten Bits aus einer grösseren Gruppe von Bits, um es anschliessend mit anderen Bits verknüpfen zu können, und das Ablegen des Ergebnisses der Bitverknüpfung in einer grösseren Gruppe von Bits sind aufwändig, zumal das einzelne Bit dort nicht die benachbarten Bits stören/verändern darf. Die Verknüpfung selbst hat einen recht kleinen Anteil an der benötigten Zeit.
Die DatenTypen (SINT,) INT, DINT, LINT sind bei arithmetischen Operationen verhältnismässig schnell, da sie "eng verwandt" sind mit dem, was der Prozessor sowieso "beherrscht" (ZweierKomplement). Dies kann man auch für die DatenTypen BYTE, CHAR, WORD, DWORD, LWORD sagen, wenn es um die logischen Operationen geht. Die Bereiche arithmetisch und logisch sind intern kaum gegeneinander abgegrenzt. Die Grenzen sind "eigentlich nicht vorhanden" über "künstlich übergestülpt" bis hin zu "schwammig".
Beim Programmieren müssen wir die notwendigen DatenTypKonvertierungen explizit programmieren, obwohl die Notwendigkeit dafür nicht immer nachvollziehbar ist. Die Compiler verlangen es, dass wir immer mit den "richtigen" DatenTypen arbeiten. In vielen Fällen können sie fehlende explizite Konvertierungen automatisch "auffüllen". Dieses automatische Auffüllen der KonvertierungsLücken, das sind dann die sog. impliziten DatenTypKonvertierungen. Wie es so ist mit Automatiken, können sie einem RoutineArbeiten abnehmen und meistens auch genau das tun, was sie sollen. Aber wenn sie mal nicht durchschauen, was man da genau programmieren will, dann sorgen sie für FehlFunktionen, die schwer aufzuspüren und zu verstehen sind. Also lieber ohne diese Automatik programmieren, dann wird man mit der Nase auf die Stellen gestossen, wo es etwas zu beachten gibt.
DatenTypKonvertierungen, die die Daten umrechnen müssen, kosten zur Laufzeit des Programms natürlich AusführungsZeit. Diejenigen, die den Daten lediglich einen anderen Typ überstülpen ("TypeCast"), ohne die Daten selbst zu verändern, eigentlich nicht. Aber, es gibt auch TypeCasts, die je nach Inhalt der betroffenen Variablen, zu Fehlern führen können. Z.B. kann ein UINT grössere Zahlen enthalten, als sich in INT darstellen lässt. Konvertiert man UINT in INT, wird dies zur Laufzeit des Programmes überwacht und kostet AusführungsZeit. Sie wird nutzlos verschwendet, wenn man im Programm schon abgefangen hat, dass solche Fälle überhaupt auftreten können.
Es kann also schon Sinn machen, Algorithmen ggfs so zu schreiben (oder abzuwandeln), dass DatenKonvertierungen eingespart werden.
Für (Neben-)Rechnungen ist es oft sinnlos, aus PlatzSparGründen einen sehr knapp bemessenen DatenTyp (z.B. UINT) zu wählen, wenn ein reichlicher bemessener DatenTyp (z.B. DINT) mit mehr "Reserve" und ohne Überläufe arbeiten kann. Das einmalige Überprüfen des Endergebnisses sollte dann genügen.
Besonders interessant ist dieser Effekt, wenn so über viele SchleifenDurchläufe hinweg viele TypKonvertierungen umgangen werden können.
Vorsicht mit GleitPunktZahl-DatenTypen.
Die Berechnungen mit ihnen sind nicht unbedingt die schnellsten, sie sind nicht unbedingt die genauesten und wenn man häufig zwischen ihnen und GanzzahlTypen hin- und herkonvertieren zu müssen glaubt, sollte man überprüfen, warum. Mit "häufig" meine ich, wenn man einen Wert während einer längeren Berechnung mal als GleitPunktZahl, mal als Ganzzahl, dann wieder als GleitPuntZahl u.s.w. benötigt.
Manchmal benötigt man GleitPunktZahlen nur, um Funktionen nutzen zu können, die für Ganzzahlen nicht verfügbar sind. Warum nicht verfügbar? Vielleicht, weil sie leicht anders zu realisieren/umgehen wären.
Mit zwei identischen Zahlen zu rechnen kann schneller sein, als mit zwei verschiedenen Zahlen.
Z.B. kann man statt 2*x auch x+x rechnen oder statt x² kann man x*x rechnen.
Allgemein gültige Tipps oder Regeln kann man wohl kaum aufstellen. Die Eigenschaften der jeweiligen Prozessoren und die möglichen/nötigen Anpassungen der Compiler sind zu vielfältig.
Darum im Zweifelsfalle "messen":
Wie lässt sich hier die Bearbeitungszeit ableiten/bestimmen?
Siehe Michaels Link.
Mir geht es vor allem darum Zykluszeitfresser ausfindig zu machen im Anwenderprogramm.
ProgrammSchleifen (FOR, WHILE, REPEAT oder wie auch immer sie heissen mögen) sind die Kandidaten, auf die man achten muss.
Die Anwendung von Schleifen,
um Zeit zu fressen, d.h. um Wartezeiten zu realisieren/"überbrücken", ist mit ziemlicher Sicherheit nicht im Sinne einer zyklischen Programmierung. Anfällig sind hier insbesondere SPS-Neulinge, die "Hochsprachen"Kenntnisse mitbringen.
Bedenken, dass die Verwaltung/Ausführung einer Schleife auch Zeit benötigt. Werden ohnehin nur sehr wenige SchleifenDurchläufe benötigt und ist die Anzahl der Durchläufe sowieso konstant und werden in der Schleife ohnehin nur wenige Befehle ausgeführt, so sollte man die Schleife ganz vermeiden und die Befehle als Sequenz statt als Iteration schreiben.
Sind viele SchleifenDurchläufe nötig und in der Schleife viele Befehle abzuarbeiten, wird es kritisch.
Ist die SchwankungsBreite der Anzahl SchleifenDurchläufe gross, weil die Anzahl von den jeweiligen Daten abhängt, dann ist das auch kritisch und man muss von der maximal möglichen Anzahl Durchläufe (worst case) ausgehen.
Manchmal ist es sinnvoller die ZykluszeitBelastug durch die Schleife konstant zu halten, statt möglichst kurz zu machen.
Sind mehrere Schleifen ineinandergeschachtelt, dann ist auch äusserste Vorsicht geboten!
Überlegen, ob die komplette Schleife in einem einzigen Zyklus fertig werden muss. Ggfs auf mehrere Zyklen aufteilen.
Das kann jedoch die Übersichtlichkeit des Programms ruinieren. Wenn die Schleife auf viele Zyklen aufgeteilt werden muss, kann das Warten auf die Beendung der Schleife unerwartet/störend lang werden.
Wenn bei einem einzigen SchleifenDurchlauf pro Zyklus die Abarbeitung der kompletten Schleife ausreichend schnell ist, dann auf diese Schleife ganz verzichten. Das zyklische Programm läuft ja bereits in einer "Endlos"Schleife. Jeder Zyklus ist ein SchleifenDurchlauf.
Jetzt "nur" noch die Organisation der Schleife zu Fuss programmieren.
Muss in den SchleifenDurchläufen auf etwas gewartet werden? Z.B. auf das Anliefern soeben angeforderter Daten? Dann kommt ohnehin nur so eine selbstgemachte Schleife in Frage.
Muss die Funktionalität, für die die Schleife gebraucht wird, überhaupt in der SPS realisiert oder kann sie irgendwohin ausgelagert werden?
Beispielsweise wenn Siemens Funktionen im Anwenderprogramm zyklisch abgearbeitet werden
Die zyklische Bearbeitung dürfte in einer SPS eher die Regel als die Ausnahme sein, also mehr als nur "ein Beispiel".
Wenn diese Siemens Funktionen in bestimmten zeitlichen Abständen aufgerufen werden sollen/müssen, dann würde ich die MessMimik genau da drumherum einbauen, wo die Bausteine bereits aufgerufen werden und sie nicht irgendwo hin verlagern, wo sie in einem anderen ZeitTakt aufgerufen werden.
Oder man sich Supermonsterallinclusivbausteine ausgedacht hat...
oder man SuperMonsterAll-IinclusiveBausteine aus irgendwelchen Quellen (z.B. auch Hersteller der verwendeten Steuerung) verwendet, weil man sich zu Schade ist, für einfache Anwendungen etwas Angemessenes selbst zu schneidern oder aus "irgendwelchen Quellen" rauszusuchen.
Edit:
Folgende DatenTypen hatte ich ja ganz vergessen zu erwähnen:
- "ausgefallene", wie z.B. BCD, GRAY, EXCESS-3 , ..., mit denen man im Alltag eher selten zu tun hat und die von der CPU nur mässig bis gar nicht unterstützt werden.
- "normale", wie KalenderDaten und/oder Uhrzeiten.
Letztere gibt's in 2 Ausführungen.
- Für die CPU gut lesbar.
Also Anzahl Tage seit Datum x oder Anzahl der ms bzw. ns seit 0 Uhr.
- Für uns gut lesbar.
Also z.B. 2022-10-15 19:00:00.
Und dazwischen scheinen Welten zu klaffen, spätestens wenn Überraschungen wie SchaltJahre, KalenderWochen, WochenTage, Winter- und SommerZeit auftauchen. Und mit ihnen merkwürdige UmwandlungsWorkArounds.
