• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

Performance VS Speicherbedarf

Magus Loon

Superstar
Sylvie Munro @ [url schrieb:
http://www.slinfo.de/phpbb/viewtopic.php?p=235035#235035]Empfänger:[/url]
if(message==(string)llGetOwner()+"Licht an") licht_an();

P.S.: Natürlich würde ich den GetOwner eigentlich in den State_Entry nehmen und in einem String ablegen, nicht direkt in den eigentlich Befehl verwenden, aber mir ging's hier ums Prinzip.

Ich habe das zu Anfang auch immer so gemacht. Allerdings fressen solche Variablen immer den wichtigen Speicher, gerade Keys und Strings.

Daher bin ich dazu übergegangen, sobald der Speicher knapp wird solche Funktionen lieber immer direkt aufzurufen statt den Speicher damit vollzustopfen. Gut, ist ein schlechtes Beispiel oben, da noch eine Typenkonvertierung hinzukommt die schon ihre Rechenzeit braucht.

Wie macht ihr das? Ist der Performance-Unterschied wirklich messbar wenn man die Variablen benutzt?

Gibt es da einem Daumen-Wert wann das eine und wann das andere sinnvoller ist? Z.B. wenn die Funktion mehr als 3x aufgerufen wird und ausreichend Speicher da ist oder immer wenn eine Typenkonvertierung stattfinden muss dann lieber in Variable schreiben.

Gerade wenn Speicher knapp wird, denkt man sehr viel darüber nach. Weil nicht nur die Variable braucht dann ihren Platz, die dadurch nötige zusätzliche Codezeile auch (oder?).
 
Daher bin ich dazu übergegangen, sobald der Speicher knapp wird solche Funktionen lieber immer direkt aufzurufen statt den Speicher damit vollzustopfen.
Hm, selbst meine komplexesten Scripte sind bislang nichtmal in die Nähe der Speicherplatzgrenzen gekommen. Das mag zum Teil daran liegen, dass ich auf eine eher... hm, sagen wir unkonventionelle Weise scripte. Ich habe z.B. keinerlei Skrupel, Abfragen und Schleifen brutal mit return; zu unterbrechen, das spart mitunter einige Konstrukte, für die ich sonst geschachtelte Abfragen oder If-Else-Strukturen bräuchte. (jaja, ich habe eben mal 68k-Assembler und C-pur gelernt, net so'n geschwätziges OOP-Zeugs *g*)
 
- Als ich ein Script Speicheropimieren wollte, indem ich längere String-Konstanten wie "balbla blubblub", die an verschiedenen Stellen im Script standen, durch eine Variable ersetzen wollte, dass das Script hinterher NOCH MEHR Speicher brauchte. Dabei habe ich dann entsetzt festgestellt, dass eine Stringdefinition wie
string abc = "abc";
nicht nur die 8 Bytes für die Unicode-Darstellung verbraucht, wie man annehmen würde, sondern gleich die maximal mögliche Länge des Strings im Speicher reserviert wird. Da muss man also aufpassen.

- Keys werden leiden intern auch als Strings gespeichert, ziehen also in Unicode-Darstellung leider auch richtig Speicher.

- llDetected... inzwischen puffere ich die NICHT mehr in Variablen zwischen, weil ich irgendwo gelesen habe, dass die Werte z.B. in einem sensor event, die in den llDetected-Funktionen sowieso in den Script-Speicher geschrieben werden. Ein Aufruf von llDetectedKey(5) ist also nichts weiter als ein Variablen-Abruf aus dem Script-Speicher, dürfte genausoviel Performance kosten.

=> Ich nehme deshalb mal an, dass llGetOwner() auch wie eine Variable direkt aus dem Scriptspeicher gelesen wird, es also performancemäßig nicht langsamer ist. Dafür spricht auch, dass man das Script resetten muss, falls der Owner sich ändert. Weil man eben den Speicher resetten muss.

Ich definiere eigentlich auch immer aus Eleganzgründen eine Globale key owner, die ich im state entry auf llGetOwner setze, was aber nach meinen Überlegungen in letzter Zeit überflüssig ist, llGetOwner direkt zu benutzen liest auch nur aus dem Script-Speicher.

LSL ist da leider, vor allem weil es keine Konstanten gibt, ziemlich krank ...
 
Zwei Fragen fallen mir dazu gleich noch ein:

1)

Ist es eigentlich möglich "lokale" Variablen je State zu setzen, z.B. um sie in verschiedenen Events in einem State zu verwenden oder müssen sie dann immer global sein?

2)

Man nehme an es ist im Script irgendeine größere Formel/Schleife mit lokalen Variablen erforderlich:

Code:
state_entry() {
   ...
   integer i; // für for schleife
   integer counter; // irgendein Counter
   integer counter2; // noch irgendein Counter
   key currentKey; // für irgendeinen Key
   // hier irgendein for schleife die die lokalen Variablen benötigt;
   ...
}

Damit würden die lokalen Variablen durch den gesamten nachfolgende Code in state_entry() mitgeschleppt werden, obwohl garnichtmehr benötigt.

Packt man nun diese Formel/Schleife mit ihren benötigten Varibalen in eine Funktion.

Code:
integer suche() {
   integer i; // für for schleife
   integer counter; // irgendein Counter
   integer counter2; // noch irgendein Counter
   key currentKey; // für irgendeinen Key

   // hier irgendein for schleife die die lokalen Variablen benötigt;

   return irgendwas;
}


state_entry() {
   ...
   a = suche();
   ...
}

Dann würde nach Durchlauf der Funktion wieder der Speicher freigegeben? Habe ich das richtig verstanden? Zumindest so sollte es ja eigentlich sein.

Wenn dem so ist, die Definition der Funktion benötigt ja sicher auch Speicher, ab wann ist dann eine Funktion sinnvoll?
 
Ich würde heute nicht mehr soviel Zeit mit Optimierungen
verbrauchen, bald kommt Mono .. da wird vieles
anders ... besser(?)

Angeblich:
- mehr Speicher
- schnellerer Code

Daher vermute ich auch andere Optimierungen
als jetzt notwendig
 
zu 1) nee, entweder schwanger oder nicht-schwanger, dazwischen geht nicht :) Will sagen, eine Globale ist über alle States global.

zu 2) ja, so ist es. Funktionsdefinition kostet auch etwas Speicher. Ab wann sich das lohnt, müsste man dann wohl mal im Einzelfall per ausprobieren. Also beide Methoden mal anlegen, hinterher llOwnerSay((string)llGetFreeMemory()) ausgeben und schauen, was weniger Bytecode erzeugt.


Optimierungen insgesamt: habe mal in einem sehr vollen Script Funktionen, bei denen es ging, in ein anderes Script ausgelagert, und das dann per llMessageLinked dort angestoßen. Code rausschmeißen bringt natürlich viel freien Speicher.

Aber wie Sylvie schon sagt, in Mono werden wir 32K Scriptmemory haben, da kann man sich viele Optimierungen sparen.
 
Aber wie Sylvie schon sagt, in Mono werden wir 32K Scriptmemory haben, da kann man sich viele Optimierungen sparen.
Äh, das war SandyLee ... :lol:

@Ezian
Bei Deinen Ausführungen darfst Du aber nicht vergessen, dass die Typenkonvertierung da ein ziemlicher Engpass ist, nach dem, was ich weiß wird die bei Keys dann intern sogar mehrfach durchgeführt.

Für die Optimierung setze ich oft globale Variablen ein, besonders bei Strings. Und wo immer möglich, benutze ich die dann auch durchaus multibel (dann braucht man aber Kommentare im Script, weil man den Code sonst selbst nicht mehr versteht).
 
Ezian Ecksol schrieb:
Aber wie Sylvie schon sagt, in Mono werden wir 32K Scriptmemory haben, da kann man sich viele Optimierungen sparen.

Dafür werden die Scripte dann umfangreicher und die Fragestellung kommt wieder auf den Tisch. :D
 
moin,

habe zu dem Thema auch noch einen Tipp. Variabeln global definieren und in verschiedenen States und Events einsetzen ist, wie Sylvie Munro vermeldete echt Sinnvoll. Ich beginne solche Variablen mit dem vermerk "temp" für Temporär.

Und bei allen Variablen die oft verändert werden lohnt es sich, dann die Variable gleich zurückzusetzen.

also statt:
Code:
a = a + "neuer wert"; // (Beispiel mit Stringvariable)
einfach:
Code:
a = ("") + a + "neuer wert";

oder

Code:
list_members = ([]) + list_members + ["neues mitglied"];

Das wirkt sich besonders bei Listen deutlich aus. So kann ich in einem Skript statt ca. 40 - 50 Einträge, zuverlässig 96 Einträge speichern.

gruss thinkangel
 
Thinkangel:

macht

a = "" + a + "text"
überhaupt sinn, ist doch gleich
a = a + "text"

du meinst wohl eher
a= ""
a=a+"text"

bzw. dann
a="text"


also eher
vor einer Abfrage/Schleife wo man was zusammenbastelt mit dne String
a=""
Aktionen
... a=a+"txta"
... a=a+"txtb"
... a=a+"txtc"
... a=a+"txtd"
 
moin nochmal :)

Code:
a = ("")+ a + "weiterer text"

man beachte die Klammer.
Der Compiler führt diesen Befehl zuerst aus.

Das heisst, erst wird die Variable auf 0 gesetzt, dann aus dem Script-speicher die Variable a und zuletzt der weitere Text hinzugefügt.

gruss thinkangel
 
Mach mal den Test

string a;
a="12";
a=""+a+"x";
llSay(0,a);

a="12";
a=("")+a+"x";
llSay(0,a);

Der gibt 2 mal '12x' aus,
denn die Zuweisung wird immer zuletzt ausgeführt.
 
Globale Variablen, besonders bei Strings, machen dennoch Sinn. Ich bin damit bislang immer sehr gut gefahren. Und zwar bei Performance und bei Speicherbedarf.
Paradebeispiel ist das GRP-Collar, das trotz Textparser, der mit Listen und Strings arbeitet nur wenig Speicher und und Rechenzeit braucht.
 
Spannend, die a = [] + a + ["x"] Variante verbraucht wirklich weniger Speicher. Allerdings nur, wenn solch eine Zuweisung mehrmals durchgefuehrt wird.

Wenn man sie nur einmal losgeloest in einem Skript aufruft, verbraucht sie sogar mehr als a += ["x"].

Edit: Ob ([]) oder nur [] hat bei mir allerdings keinen Unterschied gemacht. Haette mich aber auch irgendwie ueberrascht.
 
Frage:

Ich habe eine Menge X von globalen Variablen (und es müssen leider welche sein), die bei der Kommunikation über einen Kanal als "Kommando" dienen soll.
z.B.:

Code:
string AKTION1 = "LICHT_AN";
string AKTION2 = "LICHT_AUS";
string AKTION3 = "LICHT_DIMMEN";
string AKTION4 = "LICHT_DEAKTIVIEREN";

Diese werden dann per llSay an ein andere Objekt übertragen.

vereinfacht:

Code:
llSay(CHANNEL,AKTION1);

Da das definieren von globalen String aber sehr viel Speicher braucht, würde ich diese als Integer anlegen, jeweils mit einer recht eindeutigen Zahl.

z.B.

Code:
integer AKTION1 = 111;
integer AKTION2 = 222;
integer AKTION3 = 333;
integer AKTION4 = 444;

Die Kommunikation sieht dann wie folgt aus:

Code:
llSay(CHANNEL, (string) AKTION1);

Da ich sehr viele von diesen Variablen habe die zusammen in einer Message verschickt werden, sieht das dann im Original etwa so aus:

Code:
llSay(CHANNEL, 
  (string) VAR1 + " " +
  (string) VAR2 + " " +
  (string) VAR3 + " " +
  (string) VAR4 + " " +
  (string) VAR5 + " " +
  (string) VAR6 + " " +
  (string) VAR7 + " " +
  (string) VAR8
);

Das bedeutet der Aufwand für die Typumwandlung ist recht hoch, vor allem da so eine Message sehr oft verschickt wird.

Wie sieht nun eine optimale Lösung aus, die mir einerseits erspart die Variablen (VAR*) als globale String anzulegen und zum anderen die Last durch Typkonvertierung gering hält?

Meine Idee wäre eine Liste, da ich annehme, daß die llList2String() Funktionen performanter sind als eine einfache "manuelle" Typumwandlung. Ist dem so?

Also vereinfacht sieht das dann so aus:

Code:
list VAR = [111,222,333,444];
....
llSay(CHANNEL,
   llList2String(VAR,0) + " " + 
   llList2String(VAR,1) + " " + 
   llList2String(VAR,2) + " " + 
   llList2String(VAR,3) 
);

Welche der Varianten wäre denn optimal?

(Die Codeschnipsel stehen nicht direkt im Zusammenhang, sollte nur als Beispiele zum Verständnis dienen. Also bitte keine Diskussion über Sinn und Unsinn wieviele Variablen man sendet. Es geht rein um die Code-Struktur. Und für alle hellen Köpfchen, übertragen einer Bitmaske (VAR1 & VAR2 ...) ist hier nicht möglich. ;))
 
- Als ich ein Script Speicheropimieren wollte, indem ich längere String-Konstanten wie "balbla blubblub", die an verschiedenen Stellen im Script standen, durch eine Variable ersetzen wollte, dass das Script hinterher NOCH MEHR Speicher brauchte. Dabei habe ich dann entsetzt festgestellt, dass eine Stringdefinition wie
string abc = "abc";
nicht nur die 8 Bytes für die Unicode-Darstellung verbraucht, wie man annehmen würde, sondern gleich die maximal mögliche Länge des Strings im Speicher reserviert wird. Da muss man also aufpassen.

- Keys werden leiden intern auch als Strings gespeichert, ziehen also in Unicode-Darstellung leider auch richtig Speicher.
Hm... das verstehe ich jetzt nicht so recht.
Die maximale Größe eines Strings ist der max. Speicher (lt. LSL Definition).
Wenn nun immer die max. mögliche Länge gespeichert würde, könnte man nur einen String definieren und anschließend wäre der ganze Speicher reserviert, oder habe ich da jetzt was missverstanden?

Gruß,
Sophie
 

Users who are viewing this thread

Zurück
Oben Unten