Good Scripting Standards - let's formalize this
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
05-20-2005 02:03
Hey, someone else noticed! I'm glad.
Another problem is it reports scripts as Active even when they are not. If an object is ACTIVE, the scripts at the top level are also denoted as ACTIVE - even if they're not doing anything. This also makes the metric inaccurate.
Fortunately, percentages of process time are still fairly accurate, so if you're seeing a lot of resources in Run Agts or Run Tasks, chances are scripts are to blame.
_____________________
---
|
eltee Statosky
Luskie
Join date: 23 Sep 2003
Posts: 1,258
|
06-01-2005 13:41
Just wanted to chime in here.. just because an object/script is inactive doesn't mean it cannot have listens, or repeat sensors, or timers, etc..
what it means is that the state it is 'parked' in, aka spends the lions share of its time in, is not active...
I've just finished up a chat keyed audio stream setting object for use within the lusk estates land trust, basically a land co-op where the users are members of a group that actually owns the plots that they build on, and lets them do so for free, so long as they donate the tier to support it.
We had a problem with people not being able to set the audio streams on their land however, since they are only group members, not officers.
To get around this I setup a little object which they can place on their land and deed to the group, then use it to set the relay via a touch-activated listen state.
It has both a listen and a timer, but is 'inactive' in that both of those are located in an 'active' state, that reverts back to the inactive default state, after 60 seconds. I'll post the script here when i get home, later tonight.
It is just a simple indicator of how to help be a good neighbor with your scripts... things like pose balls, animation over-rides etc could all use similar tricks, and significantly lower their overall burden on a sim, without lowering their actual in-game functionality
aka the key is to just park things in an idle state, and use pushed events, such as touches, changes, or collisions, etc, to trigger the more active state, which then reverts back to an inactive default after say a 60 second timer
_____________________
wash, rinse, repeat
|
Ritz Pinkerton
Builder/Scripter
Join date: 27 Mar 2005
Posts: 22
|
06-01-2005 13:59
I'd like to add a scripting courtesy idea here... it doesn't have to do with lag, but it still goes along with the style of scripting. When a script informs the owner/wearer/whoever of something that doesn't need to be public, use llInstantMessage or llOwnerSay... not sure about you guys, but when someone TP's in next to me, I don't want to hear all their scripts spamming, or when someone's doing something nearby, the same thing goes.. my scripts use llIM and llOS AND even have a silent option, so even the owner doesn't have to get bothered by it if they don't want to. And, has anyone noticed, half the posts in here could be avoided if people would just go to the wiki?
|
eltee Statosky
Luskie
Join date: 23 Sep 2003
Posts: 1,258
|
06-01-2005 19:58
Here's a commented up example of what I was trying to explain before, as to how to use multiple states to keep objects that only need to be active once in a blue moon, passive the rest of the time, this one using touch (but any of the interrupt style events can be used) //Basic resident stream setting script //Created for the lusk estates land trust //by eltee Statosky
//This script is PUBLIC DOMAIN aka please feel free to share with anyone
/////////////////////////////////////////////////////////////////////////
//Set the resident's name here, it will only respond to the named resident string Owner="eltee Statosky"; //Set the desired default stream url here string Stream=""; integer listener=-1;
//default state will be inactive, aka use no server resources default { state_entry() { //Use the stream string to determine the starting text if (Stream=="") { llSetText("Idle", <1.0, 1.0, 0.5>, 0.5); } else { llSetText("Streaming", <0.5, 1.0, 0.5>, 0.5); } //Set the desired stream llSetParcelMusicURL(Stream); }
//On touch, trigger the active, aka listening state touch_start(integer total_number) { //But only if touched by the selected owner if (llDetectedName(0)==Owner) { state Listening; } } }
//The listening state is active, and uses sim resources so will only be enabled briefly state Listening { state_entry() { //Setup the listen, the text, and the time out listener=llListen(0, Owner, "", ""); llSetText("Awaiting Stream URL", <1.0, 0.5, 0.5>, 0.5); llSetTimerEvent(60); }
listen(integer chan, string name, key id, string msg) { //Only listen to the owner if (name==Owner) { //If the message is off, clear the stream variable if (msg=="off") { Stream=""; } //Otherwise set the stream to the next thing said by the person else { Stream=msg; } //Clear the listen, and revert to the inactive state llListenRemove(listener); llSetTimerEvent(0); state default; } } //basic timeout to return to the inactive state timer() { //Clear the listen, and revert to the inactive state llListenRemove(listener); llSetTimerEvent(0); state default; } }
_____________________
wash, rinse, repeat
|
Zindorf Yossarian
Master of Disaster
Join date: 9 Mar 2004
Posts: 160
|
06-02-2005 15:12
I'm not a scripting or lag guru, but it occured to me that in some cases llSensorRepeat(...); could be replaced by putting in a sensor call in the sensor event. Something like this: sensor (integer numDetected) {
// Do all the sensor stuff
llSensor(...); }
This way, the sensor is only called when the script is ready for it. I think this would update as fast as possible, without the guesswork of how often to repeat, and without the extra load caused by a sensor that repeats too often.
_____________________
Badass Ninja Penguin: Killing stuff it doesn't like since sometime in May 2004.
|
Dianne Mechanique
Back from the Dead
Join date: 28 Mar 2005
Posts: 2,648
|
06-02-2005 15:37
From: Ace Cassidy ...Standards and seals of approval are bad. I am not a scripter, but this is just plain wrong. 
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
06-02-2005 15:40
From: Zindorf Yossarian I'm not a scripting or lag guru, but it occured to me that in some cases llSensorRepeat(...); could be replaced by putting in a sensor call in the sensor event. Something like this: sensor (integer numDetected) {
// Do all the sensor stuff
llSensor(...); }
The problem with general loops like that one (for/do/while loops also suffer this) is other events typically don't "break out of the loop." You usually end up looping infinitely at the expense of everything else if you're not careful. So coding it that way, Zindorf, would be at the exclusion of other events. The advantage of timers and llSensorRepeat is the fact they leave "processing time" between scheduled calls. This allows other events to break in there as needed. Again, it all comes down to how you code. 
_____________________
---
|
Phillip Archer
Registered User
Join date: 18 Apr 2005
Posts: 13
|
Is this considerd a good standard?
06-02-2005 16:16
I changed an old anti phantom script from 284 lines to 8? is that a good way to reduce lag?
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
06-02-2005 16:23
That depends completely on what the script is actually doing.
Very likely that reduced the calculation "lag" of the script - a good thing. However, if it's making repeated calls to the server in those 8 lines, you may have solved nothing.
_____________________
---
|
Zindorf Yossarian
Master of Disaster
Join date: 9 Mar 2004
Posts: 160
|
06-02-2005 19:55
From: Jeffrey Gomez The problem with general loops like that one (for/do/while loops also suffer this) is other events typically don't "break out of the loop." You usually end up looping infinitely at the expense of everything else if you're not careful. So coding it that way, Zindorf, would be at the exclusion of other events. The advantage of timers and llSensorRepeat is the fact they leave "processing time" between scheduled calls. This allows other events to break in there as needed. Again, it all comes down to how you code.  I suspected that this would allow other events to fire, since they cue up and wait their turn. When the object had something else happen to it, this would be added to the cue, and the sensor would wait its turn. After a bit of testing, this was verified: I found that touch, listen, and collision events would still fire. I assume that the rest of the events would also still work. So my method does not actually exclude other events. As another note, llSensor could also be added to the no_sensor() event, perhaps with a slight llSleep delay, so that the sensing does not stop. Of course, this many sensors is not great for a sim, but it is preferable to using llSensorRepeat every .01 seconds.
_____________________
Badass Ninja Penguin: Killing stuff it doesn't like since sometime in May 2004.
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
06-02-2005 20:27
In that case, I am (gladly) mistaken.
_____________________
---
|
eltee Statosky
Luskie
Join date: 23 Sep 2003
Posts: 1,258
|
06-02-2005 20:53
From: Zindorf Yossarian I suspected that this would allow other events to fire, since they cue up and wait their turn. When the object had something else happen to it, this would be added to the cue, and the sensor would wait its turn.
After a bit of testing, this was verified: I found that touch, listen, and collision events would still fire. I assume that the rest of the events would also still work. So my method does not actually exclude other events.
As another note, llSensor could also be added to the no_sensor() event, perhaps with a slight llSleep delay, so that the sensing does not stop. Of course, this many sensors is not great for a sim, but it is preferable to using llSensorRepeat every .01 seconds. it works but you haven't actually helped lower lag in any way, infact you have made a sensor event *considerably* more laggy since it will no longer be constrained by a relatively slow timer.. essentially what you have done is exactly the same, code wise, as saying while(true) {sensor(stuff)};
_____________________
wash, rinse, repeat
|
Zindorf Yossarian
Master of Disaster
Join date: 9 Mar 2004
Posts: 160
|
06-03-2005 05:55
eltee, I realize that my solution puts a high burden on the server. But it is only intended for when you want very fast sensors. For example, in a bullet deflecting shield. Clearly, this is not a good substitute for anything with a SensorRepeat set for anything over one second. But, if you absolutely need to have a sensor that fires as fast as possible, my method is better than setting a very fast timer.
_____________________
Badass Ninja Penguin: Killing stuff it doesn't like since sometime in May 2004.
|
eltee Statosky
Luskie
Join date: 23 Sep 2003
Posts: 1,258
|
06-03-2005 08:04
yah which is ahy it really doesn't belong in a script about good scripting standards designed to minimize lag and be better for the servers and people's clients
its not a bad idea, its jus in the wrong thread, and has a decent chance of confusing someone into thinkin that somehow thats lower lag, jus by bein here in this thread
_____________________
wash, rinse, repeat
|
Jon Marlin
Builder, Coder, RL & SL
Join date: 10 Mar 2005
Posts: 297
|
06-03-2005 08:37
eltee posted a great solution back earlier in the thread regarding using multiple states for switching between active and passive mode. I think this is great, and use the technique myself. However, sometimes you are using the FSM for other purposes, and you can't (or don't want to) afford the complexity of switching states to handle passive/active mode switches. The following script does this, and breaks the work into functions so you can do this from multiple states without duplicating a lot of code...
integer OwnerNoListener = -1; integer OwnerListener = OwnerNoListener; integer ListenerTimeout = 30;
//////////////////////////////
handleActivateListener () {
llOwnerSay ("Setting " + (string)ListenerTimeout + " second timer listen..."); llSetTimerEvent (0.0); llSetTimerEvent (ListenerTimeout); if (OwnerListener != OwnerNoListener) llListenRemove (OwnerListener); OwnerListener = llListen (0, "", llGetOwner (), "");}
handleResetListener () {
llSetTimerEvent (0.0); llSetTimerEvent (ListenerTimeout);}
//////////////////////////////
handleDeactivateListener () {
llOwnerSay ("Owner listen time expired - cancelling listen..."); llSetTimerEvent (0.0); llListenRemove (OwnerListener); OwnerListener = OwnerNoListener;}
//////////////////////////////
default {
touch_start (integer numberDetected) {
if (llDetectedKey (0) == llGetOwner ()) handleActivateListener ();}
listen (integer channel, string name, key id, string message) {
// reset the listener timeout timer... handleResetListener (); // do the normal listen event handling stuff here... }
timer () {
handleDeactivateListener ();} }
- Jon
|
Alondria LeFay
Registered User
Join date: 2 May 2003
Posts: 725
|
06-04-2005 09:48
One thing I do to decrease some sim lag is any semi-complex calculations I perform on a remote server and then just ship the data back into world. I know not everyone currently has the luxury of a seperate server to run things on but it allows a whole new window of functionality, efficiency, etc and you can pick up minimalistic hosts for dirt cheap. Now if only LL will let outgoing RPC happen, I can kill the email bottleneck in my objects.
|
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
|
09-16-2005 08:30
Well, this isn't a real benchmark in a controlled environment, but I can tell you that by making my scripts purely event-driven, I've been able to fit upwards of 3000 in a single sim while maintaining an acceptable level of performance (meaning, enough CPU left for 10+ people to use the sim).
|
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
|
09-16-2005 14:50
From: Hiro Pendragon Controls -
BAD: keep checking the same control over and over GOOD: when you can, disengage your control event and/or use edges What exactly do you mean by this?
|
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
|
09-16-2005 15:26
From: Alondria LeFay One thing I do to decrease some sim lag is any semi-complex calculations I perform on a remote server and then just ship the data back into world. I know not everyone currently has the luxury of a seperate server to run things on but it allows a whole new window of functionality, efficiency, etc and you can pick up minimalistic hosts for dirt cheap. Now if only LL will let outgoing RPC happen, I can kill the email bottleneck in my objects. I'd like to make Alondria's words my own. LSL works "well" as a thin client to a PHP/MySQL backend. Just make sure you have a dedicated server, most web hosts limit you to something like 20 concurrent MySQL connections, which is unacceptable for any serious multiuser project.
|
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
|
09-16-2005 16:13
What kind of calculations are you doing that are so intensive that you'd need to offload them onto a separate server?
|
Alondria LeFay
Registered User
Join date: 2 May 2003
Posts: 725
|
09-17-2005 08:23
From: Keknehv Psaltery What kind of calculations are you doing that are so intensive that you'd need to offload them onto a separate server? Well, one recent one I have done is searching for words within a five by five matrix against a dictionary of 10,000 or so words. In LSL, I would wager this would take literally hours and hoards of sim time. In Perl on my backend, this is a fraction of a second. Another example is manipulation of large data sets. People can and do this manipulation (and I have historically in pre-rpc days) in world via an array of "memory" scripts, however issuing a command to search for particular data against 20 memory scripts which all are performing string and/or list searchs in union does not make a sim happy. Ideally, I am of similar mind to Eggy. I feel LSL should be focused on the creation of the UI and event interpretation and ideally the calculations and "guts" of a program should be hosted elsewhere. Almost any language you can possibly choose will be more powerful, fast, and efficient than LSL. The missing element of bringing this to it's full potential is outgoing rpc (and perhaps the ability to circumvent the asset server itself and load textures/sounds/etc from an external source). In an ideal world, IMHO, LL should host external servers themselves. It would be a new source of revenue for them and would be beneficial to scriptors (and LL's assets) since turn around time on their internal network would be amazing and bandwidth (since it would be internal LAN) would be free. It would remedy the feel of utilizing outgoing RPC to DoS a site (and if someone DoS' the internal servers, LL has the ability to remove the inflicted object). (See [post]645977[/post])
|
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
|
09-17-2005 08:47
Wow. I had no idea anyone would want to do that, but I see your point.
Also, if we could get outbound XML-RPC for internal communication, we would basically have object-to-object communication.
|