TIA SCL-Schleife erhöht kurzfristig die Zykluszeit

MFreiberger

Level-3
Beiträge
3.272
Reaktionspunkte
913
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin Zusammen,

wir sind bei der Verwendung von Schleifen, die in SCL geschrieben sind, auf ein Phänomen gestossen:

Ein Kollege wollte bei einer IBN vor Ort eine FOR-Schleife mit 60 Durchgängen programmieren (das hat er auch getan!). In dieser Schleife werden, in Äbhängigkeit von zwei Arraybits, ein Bit eines anderen Array auf TRUE oder FALSE gesetzt.

Der Kollege hat die Schleife eingespielt und sofort sprang die mittlere Zykluszeit von ~20ms auf ~50ms!
Dann hat er die Schleife herausgenommen und 60 Einzelaufrufe (in AWL) programmiert. Nach dem Einspielen ist dabei die Zykluszeit nicht angestiegen.

Ich konnte die Situation nachstellen. Immer wenn ich die SCL-Schleife geladen habe, ist die Zykluszeit sprunghaft angestiegen (allerdings nur für wenige Sekunden). Danach hat sich die Zykluszeit wieder "bekrabbelt".

Kann es sein, dass bei der Schleife zunächst die Variablen referenziert werden müssen und sie erst danach performant läuft?

Ach ja: wir verwenden TIA 15.1 SP3

VG

MFreiberger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,


Kannst du die Schleife einmal kurz hier einstellen? Ein Plus von 30ms ist ja doch enorm

Code:
FOR #i := 1 TO "ITEMcnt" DO // in allen Plätzen löschen
    IF
        NOT ("OPCUA_DABA".PLACE[1,#i].ITM.SIGNALS.OCC_DATA AND "OPCUA_DABA".PLACE[1,#i].ITM.SIGNALS.DATA_VLD)
    THEN
        "OPCUA_DABA".PLACE[1,#i].ITM.TASK.VLD:=false;
    END_IF;
END_FOR;


Was für eine CPU ist es ( und welche FW )

6ES7 515-2FM01-0AB0 FW 2.8.0


Ich denke du meinst Update 3, SP3 gibt es nicht. Aktuell wäre Update 4

Ja, natürlich Update 3!


Getestet haben wir an zwei Steuerungen mit gleichem Ergebnis (Zykluszeit hat sich für wenige Sekunden mehr als verdoppelt).

VG

Mario
 
Zuletzt bearbeitet:
Oder löst der Reset von "OPCUA_DABA".PLACE[1,#i].ITM.TASK.VLD:
in anderen Programmteilen was Zyklus intensives aus?

 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,

Kann es sein das ITEMcnt in den ersten Zyklen einen falschen Wert hat?

Nein, 'ITEMcnt' ist eine Anwenderkonstante und hat den Wert 60


Oder löst der Reset von "OPCUA_DABA".PLACE[1,#i].ITM.TASK.VLD:
in anderen Programmteilen was Zyklus intensives aus?

Eigentlich nicht.
Bei anderer Programmierung ohne Schleife (Einfach 60 Aufrufe) haben wir dieses Phänomen nicht.
Es ist auch so, dass die Zykluszeit nach dem Sprung auf ~50ms sich nach ein paar Sekunden wieder auf ~20ms einpendelt und keine erkennbaren Ausschläge mehr hat.

VG

Mario
 
Getestet haben wir an zwei Steuerungen mit gleichem Ergebnis (Zykluszeit hat sich für wenige Sekunden mehr als verdoppelt).
Kann es sein das ITEMcnt in den ersten Zyklen einen falschen Wert hat?
Dann wäre nur im ersten Zyklus die ZyklusZeit zu hoch und nicht über meherere Sekunden hinweg!?

Kann es sein, dass die erhöhte ZyklusZeit auf das Laden und Aktivieren [irgendeiner]einer ProgrammÄnderung zurückgeht und nicht wirklich mit der Schleife zu tun hat?
Meint das BetriebsSystem, den Speicher reorganisieren zu müssen?
Was ist hier mit ZyklusZeit gemeint? Wissen wir, ob sich die Laufzeit des OB1 entsprechend erhöht hat oder hat das BetriebsSytem zwischen den OB1-Durchläufen irgendwelche Arbeiten zusätzlich ausgeführt ... oder evtl. dazu den OB1 unterbrochen?

Den Gedanken mit dem Referenzieren hatte ich anfangs nicht verstanden, aber wenn ich die vielen Punkte in den Variablen sehe ... man schreibt im Programm die Namen einfach hin und bedenkt nicht, dass mehrfach geschachtelte DatenTypen zur AusführungsZeit ganz schön viel AdressRechnerei erfordern. Aber, dass zur Laufzeit eine zeitraubende LernPhase auftritt, die später - erst nach vielen Zyklen! - eingespart wird?

SPS scheint auch nicht mehr das zu sein, worauf man heute noch glaubt, sich verlassen zu können. :ROFLMAO:
 
Eigentlich nicht.
Bei anderer Programmierung ohne Schleife (Einfach 60 Aufrufe) haben wir dieses Phänomen nicht.
Es ist auch so, dass die Zykluszeit nach dem Sprung auf ~50ms sich nach ein paar Sekunden wieder auf ~20ms einpendelt und keine erkennbaren Ausschläge mehr hat.

Genau das könnte ja darauf hinweisen, das ganz woanders was passiert und dann eben irgendwann abgearbeitet ist oder so...
Schon mal nur den Baustein isoliert laufen lassen?
Oder andersrum: Die Schleife auskommentieren und die Bits per Variable steuern auf false setzen und gucken was passiert
 
Moin Olli_BS,

Genau das könnte ja darauf hinweisen, das ganz woanders was passiert und dann eben irgendwann abgearbeitet ist oder so...
Schon mal nur den Baustein isoliert laufen lassen?
Oder andersrum: Die Schleife auskommentieren und die Bits per Variable steuern auf false setzen und gucken was passiert

Wie gesagt: Wir haben die Funktion als Schleife (in SCL geschrieben) und, alternativ, als zeilenweise Anweisung (in AWL geschrieben) geladen.

Sobald die Funktion als Schleife (SCL) geladen wurde: Zykluszeiterhöhung für wenige Sekunden

Sobald die Funktion als zeilenweise Anweisung (AWL) geladen wurde: keine Änderung der Zykluszeit

Bei uns sind immer alle Baustein optimiert.

VG

Mario
 
Ich würde in der Funktion mal einen "Schalter" einbauen, der auf False steht. Damit umspringst du die Schleife.
Jetzt alles laden, dann online gehen und die Schleife mit dem Schalter aktivieren. Die Frage wäre, wie sich nun die Zykluszeit verhält, also ohne das "Laden".
 
Den Gedanken mit dem Referenzieren hatte ich anfangs nicht verstanden, aber wenn ich die vielen Punkte in den Variablen sehe ... man schreibt im Programm die Namen einfach hin und bedenkt nicht, dass mehrfach geschachtelte DatenTypen zur AusführungsZeit ganz schön viel AdressRechnerei erfordern. Aber, dass zur Laufzeit eine zeitraubende LernPhase auftritt, die später - erst nach vielen Zyklen! - eingespart wird?
Ist das tatsächlich der Fall, dass die Addressen erst zur Laufzeit berechnet werden !?
Ich war immer der Meinung dass der Compiler macht diese Berechnung, nicht der CPU zur Laufzeit.
Finde ich interessant und besorgniserregend zugleich. Wäre mMn. nicht kompatibel mit das Konzept von SPS Steuerungen.

In SCL Code sehe ich nichts das besonders schlimm ist. Auf gegenfall, es ist total einfach.
Keine Idéen woran es liegen kann.
Wenn es als AWL einzeln-Zeilen funktioniert ohne Zykluszeiterhöhung, wie dann mit SCL einzel-Zeilen ohne FOR Schleife ?
 
Ist das tatsächlich der Fall, dass die Addressen erst zur Laufzeit berechnet werden !?
Ich war immer der Meinung dass der Compiler macht diese Berechnung, nicht der CPU zur Laufzeit.
In dem gezeigten Beispiel gehe ich davon aus, weil es doch wohl ein array of struct ist. Der Compiler wird wohl kaum für alle inidizierbaren Fälle auf Vorrat alle Berechnungen ausführen.
Nun gut, bei 60 ArrayElementen wäre das noch vorstellbar und praktikabel.
Ausserdem ist es fraglich, ob das Auswerten von irgendwelchen vorbereiteten Tabellen wirklich so viel schneller ist, als das direkte Neuberechnen.
Ich wollte eigentlich darauf hinaus, dass a.b[idx].c.d vielleicht harmloser aussieht als a[b, c[idx]]. [Mehrdimensionale] Arrays (ohne structs) haben bei allen Elementen denselben DatenTyp und somit jedes Element dieselbe Länge -> relativ sparsame AdressRechnung. Die Elemente von Structs hingegen können sehr unterschiedliche DatenTypen enthalten mit unterschiedlichen Längen der einzelnen Elemente. Und sie können natürlich auch wieder weitere Structs enthalten. Zumindest für meinen Geschmack geht da recht schnell die Übersicht verloren.
Das, was für den Programmierer einfacher und übersichtlicher aussieht, muss für das Compilat nicht wirklich bedeuten, dass es wenig zu rechnen gibt, weil der Compiler schon alles vorab erledigen konnte.

PS:
Bei optimierten Daten kommt wohl noch hinzu, dass die Structs je nach Länge der Elemente auseinander gerissen und in verschiedene Bereiche sortiert sind. Auch dadurch fällt zusätzlicher Aufwand an.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn die Addressierung ohne "Optimierung" ist, dann kann der Compiler einfach die Offset zwischen Array-Elemente berechnen, egal ob einfache Datentypen oder Strukturen.
Wenn die Addressierung mit "Optimierung" ist, dann kann ich nicht durchschauen wie der Compiler funktioniert bzw. wie es funktioniert zur Laufzeit.
Wenn ist tatsächlich einen Laufzeitunterschied gibt wegen diesen "erstaufruf" von Addressierung, dann wäre es für mich einen fundamentalen Nachteil für "Optimierte" Daten.
Das Problem ist nicht dass diese dynamische Berechnung zur Laufzeit ein bisschen langsahmer oder schneller ist.
Das Problem ist dass es zu unerwartete Zykluszeitunterschiede vorkommen kann. Mann kann nicht davon ausgehen es wird nur beim ersten Programzyklus passieren. Wenn das Program zum Teil ereignissbassiert ist, dann kann die Zukluszeiterhöhung plötzlich und unerwartet passieren. Es ist unakseptabel.
 
Ein 1515 ist nicht der schnellste Renner, aber absolut nicht lahm.
Ist es akseptabel dass durch diese sehr einfache Array-Indizierung zu einen 20 ms Zukluszeiterhöhung kommt ??

Und ich finde auch dass einen Array von Strukturen ist in keinen Fall schlechten Programmierstil.

Sehr sehr interessant.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ist es akseptabel dass durch diese sehr einfache Array-Indizierung zu einen 20 ms Zukluszeiterhöhung kommt ??
Und ich finde auch dass einen Array von Strukturen ist in keinen Fall schlechten Programmierstil.
Mario sprach von einer Erhöhung von 20ms auf 50ms, also um 30ms bzw. einer Erhöhung um 150% auf 250%. Das ist noch inakzeptabler.
Ein array of struct ist kein schlechter Programmierstil - im Gegenteil!
Ich bleibe aber bei meiner Theorie, dass die AdressBerechnung (mehrstufig!) bei ineinander geschachtelten Structs aufwändiger ist als ein indirekter Zugriff per ArrayIndex - nur nicht so offensichtlich, wenn man den QuellCode liest.
 
Ich habe es mal nachgestellt auf verschiedenen CPUs, bei allen verhält es sich beim Code ähnlich. Siehe Bild, die Laufzeit nur der Schleife erhöht sich wesentlich, den Zyklus um bis zu 230%.

Also habe ich Heinileinis Vermutung, die Struktur verstärkt das Problem, versucht mit dem gleichen Ergebnis. Die Verschachtelungstiefe hat nix verändert.

Stelle ich es auf
Code:
FOR #i := 1 TO "ITEMcnt" DO // in allen Plätzen löschen
 "OPCUA_DABA".PLACE[1,#i].ITM.TASK.VLD:="OPCUA_DABA".PLACE[1,#i].ITM.SIGNALS.OCC_DATA) AND NOT "OPCUA_DABA".PLACE[1,#i].ITM.SIGNALS.DATA_VLD
END_FOR;
um, so verändert sich ebenfalls nicht wirklich die Zeit.

Stelle ich die Struktur aber auf eindimensional dann halbiert sich die Zykluszeiterhöhung. Scheint eher damit zusammenzuhängen.


Gemessen:
Baustein RUNTIME im OB30 (höchste Prio) um den Code auf verschiedenen 1200+1500er inklusive der oben angegebenen, also rein die Verarbeitungszeit dieser Anweisung.

Zyklus 60er Schleife.png

edit: Durch nachträglich ausgeführte Messungen ist dieser Beitrag "überholt", siehe Beitragsnummer 30
 
Zuletzt bearbeitet:
Zurück
Oben