Jump to content

Script efficiency


Quistess Alpha
 Share

You are about to reply to a thread that has been inactive for 710 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

So it came up recently in the "Best scripter tips and tricks" thread, that some of the discussion we were having there about "script efficiency" might be more suited to a separate thread.

@Dyna Mole reached out to me and mentioned that if we wanted to get a thread stickied, it should have a rather specific scope, so it's easier for everyone to know what's "on topic".

We could have all manner of discussions on specific cases like "What is the best way to iterate through a list" But I think to keep this as useful as possible, and not cluttered, it would make sense to have one topic for general ideas relating to efficiency (this thread) and branch out with links to other threads for specific topics if it gets too specific. To keep things on point with some nice 'topic questions':

  • What are the most important things every scripter should know about writing efficient scripts?
  • What are some general tricks to reduce memory or script time? (If you need a line or two of code to explain it, consider making a new thread and linking it here)
  • Is efficiency always important? When and how does making a script "more efficient" result in actual benefit for SL residents? (especially now after the 2022 script efficiency update)
  • What are the best methods for measuring "how efficient" a script is in one way or another.
  • If there are any interesting discussions in other threads about making some common operation more efficient, post a link!
  • Like 1
  • Thanks 2
Link to comment
Share on other sites

A few things to know about LSL script Memory:

  • Script memory for "Mono" scripts is ~64000 bytes, which includes the actual code as well as variables.
  • The memory for your actual script is allocated in 512 byte blocks; Every 'User defined function' takes at least 512 bytes of memory away from your script.
  • Strings are stored in utf16 format in mono scripts. llChar and llOrd can be used to pack 15 bits of data into a 2-byte character. (see This thread )
  • A list of keys is rather inefficient. (Key packing unpacking functions )
  • LSL lists are usually very efficient at storing multiple copies of the same string.
  • Thanks 1
Link to comment
Share on other sites

39 minutes ago, Quistess Alpha said:
  • What are the most important things every scripter should know about writing efficient scripts?

Forget everything you leant about writing well formatted readable code broken down into dozens of neat little functions with as little code reuse as possible.

In LSL, bytecode is king. The less you waste the more you can do. Functions are expensive.

The script engine doesn't care how pretty your code is.

Set up an external editor - VS Code is awesome, cross platform and free. 

 

39 minutes ago, Quistess Alpha said:
  • What are the best methods for measuring "how efficient" a script is in one way or another.

The number of scripts your project requires. The fewer the better. Dare you to do it in one.

Are you implementing a solution to a specific problem, or are you creating a "system" that happens to do something useful?

  • Thanks 1
Link to comment
Share on other sites

25 minutes ago, Quistess Alpha said:
  • The memory for your actual script is allocated in 512 byte blocks; Every 'User defined function' takes at least 512 bytes of memory away from your script.

If you remember NOTHING ELSE, remember this.

This is 512 bytes bigger .... 

string AddSomething(string Farts) {
    return Farts + "Something";
}

default
{
    state_entry()
    {
        llSay(0, AddSomething("Hello, Avatar!"));
    }

    touch_start(integer total_number)
    {
        llSay(0, AddSomething("Hello, Avatar!"));
    }
}

.... than this ....

default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!" + "Something");
    }

    touch_start(integer total_number)
    {
        llSay(0, "Hello, Avatar!" + "Something");
    }
}

 

Script like a newbie, test like a pro, comment like future you is an idiot.

 

  • Like 4
Link to comment
Share on other sites

14 hours ago, Quistess Alpha said:
  • Every 'User defined function' takes at least 512 bytes of memory away from your script.

I don't think this is correct. This was how we used to think it worked; in fact, I used to think each state also added a full block, but just a little experimentation will show neither of these happens with every function or state addition. (I restrained myself from posting sample code to this thread, but it's not difficult to demonstrate.)

That's not to say user-defined functions have no cost. Indeed, function calls in general are pretty expensive (especially if they pass large arguments). And states are most often just syntactic sugar for a global variable, unless an event handler is only needed in some states in which case they can be a real win.

  • Thanks 1
Link to comment
Share on other sites

35 minutes ago, Qie Niangao said:

I don't think this is correct. This was how we used to think it worked; in fact, I used to think each state also added a full block, but just a little experimentation will show neither of these happens with every function or state addition. (I restrained myself from posting sample code to this thread, but it's not difficult to demonstrate.)

That's not to say user-defined functions have no cost. Indeed, function calls in general are pretty expensive (especially if they pass large arguments). And states are most often just syntactic sugar for a global variable, unless an event handler is only needed in some states in which case they can be a real win.

The memory allocation happens in 512 byte blocks, but not every new function (etc etc) demands a new 512 block.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

There is a tipping point (not to be confused with a "TP Point"), where:

- You can only squeeze so much efficiency (in terms of memory remaining) or functionality into a single script, before one or the other will be sacrificed.

- Splitting one script into multiple scripts for more functionality and individual script memory, may likely result in greater inefficiency resulting from inter-script communication.

- Etcetera.

Agree? Disagree? "Diminishing Returns", that's the term I was thinking of.

Link to comment
Share on other sites

I'm seeing two different areas being discussed here: Memory, and Speed.

Memory efficiency is vital for avatar attachments so that arriving avatars get assimilated into the region with little bother.

Speed is more important to stuff that's happening all the time in a scripted object or set of objects where delays will have observable effects.

I've tried to measure them both using in-world tools and it's a real pain. We really need access to the top-scripts menu that is only available to estate managers on private regions to be able to properly assess the results of tuning scripts for speed or memory efficiency.

  • Like 2
Link to comment
Share on other sites

19 minutes ago, Profaitchikenz Haiku said:

Speed is more important to stuff that's happening all the time in a scripted object or set of objects where delays will have observable effects.

Speed when it comes to LSL is illusionary, everything that happens serverside is at the mercy of mono scheduling and the next update window when data can be sent to the client.

I have some test code that renders random PETSCII to a mesh text wall, visually it always updates at the same rate, I can't tell a slow or fast run based on looking at the object .. however if I put timing code in the script, execution times varies wildly between 250 - 600 ms. I've spent hours trying to get this script as lean and fast and repeatable as possible, and while I have pushed the timing down .. in practical terms, I have made no progress at all.

I can make it visually faster, but that actually uses a lot more scripts and uses significantly more mono execution time.

At the end of the day, trying to treat LSL as though it's running locally is a dead end. It will do what it does as fast as it does it. If you need something to appear instantaneous, find some clever way to fake it, or failing that hold the users attention while the thing catches up.

  • Like 2
Link to comment
Share on other sites

30 minutes ago, Coffee Pancake said:

At the end of the day, trying to treat LSL as though it's running locally is a dead end.

Are there many other "local" functions like llTargetOmega(), which once run don't depend on script efficiency?

I can only think of a few, like llParticleSystem().

Link to comment
Share on other sites

16 hours ago, Coffee Pancake said:

however if I put timing code in the script, execution times varies wildly between 250 - 600 ms. I've spent hours trying to get this script as lean and fast and repeatable as possible, and while I have pushed the timing down .. in practical terms, I have made no progress at all.

I encountered a similar problem when I was working on trying to measure region performance in-world using scripts instead of the metrics provide in the viewer statistics.

Any such measuring scripts are subject to the same performance issues that they are trying to assess. They add to the load, if the region is not subject to any underlying issues they impose no extra load, but otherwise, they add to the problem. The resulting measurement is effectively "for indication only" because they are not independent.

 

15 hours ago, Love Zhaoying said:

if any of your code is asynchronous (using events, dataserver(), etc.)

As with your other comment on Target Omega, it would be useful to show people where optimisation isn't possible'

Link to comment
Share on other sites

21 minutes ago, Profaitchikenz Haiku said:
16 hours ago, Love Zhaoying said:

if any of your code is asynchronous (using events, dataserver(), etc.)

As with your other comment on Target Omega, it would be useful to show people where optimisation isn't possible'

With any asynchronous code that waits for and gets a response from a server: dataserver() is a good case; you have absolutely no control of how long the call will take. So, you have no way to improve (or "optimize") the time the server will take to call back to you.

Sure, it will help if you are running on a region that is finely tuned, with few other scripts running. But besides that, how could you do any optimization for that type of call on YOUR side?

The reason llTargetOmega() is different: it is a client / viewer-side function.

Edited by Love Zhaoying
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 710 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...