Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Performance help needed

Gregory McLeod
Registered User
Join date: 21 Oct 2006
Posts: 278
08-09-2007 08:32
I have a script which is one of many that is taking too long to execute and I would appreciate the expertise of those who understand performance issues.
I have attached the script in question. If this is put in a box in world and the Test option used it will display the results and timings. Do not concern your self with the results just the timings.
Example input:-
/9005Test002003
gives
002 003
Hop.GetHopValues: 0203
Hop.GetHopValues.loop1.start: 22.90625
Hop.GetHopValues.loop1.ended: 22.92188
HopResult: 002003005

/9005Test005003
gives
005 003
Hop.GetHopValues: 0503
Hop.GetHopValues.loop1.start: 59.23438
Hop.GetHopValues.loop2.start: 59.25000
Hop.GetHopValues.loop2.ended: 59.26563
HopResult: 005003002

/9005Test121122
gives
121 122
Hop.GetHopValues: 797A
Hop.GetHopValues.loop1.start: 56.92188
Hop.GetHopValues.loop2.start: 56.95313
Hop.GetHopValues.loop2.ended: 57.00000
HopResult: 121122118

/9005Test122121
gives
122 121
Hop.GetHopValues: 7A79
Hop.GetHopValues.loop1.start: 15.28125
Hop.GetHopValues.loop2.start: 15.31250
Hop.GetHopValues.loop2.ended: 15.32813
HopResult: 122121114

I would appreciate ANY suggestion as to how to speed this up.
TIA
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
08-09-2007 08:40
Without really looking too close at this, it seems like you're timings are all under 0.1 of a second and some are closer to 0.01 of a second.

What kind of numbers did you hope to see? How closely did you look at the sim performace *before* running these tests?
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
08-09-2007 09:03
Not sure how LSL works internally but, in general, string operations can be expensive.

For example, that big honkin' string named Hop never changes but you call SubStrIndx on it in a loop and that calls llStringLength on Hop, every time. Unless LSL uses length-prefixed strings, getting the length so often is probably a big expense. Instead of doing that, have a global integer for the length and set it in LoadHop.

Also, in GetHopValues, you use "origin+blocking" and "blocking+origin" but these string variables never change - use local variables before the loop and just do the concatenations once..

There may be other things you can do to speed this up but those 2 jumped out at me. The first, I suspect, will be the biggest win.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Shadow Subagja
Registered User
Join date: 29 Apr 2007
Posts: 354
08-09-2007 09:42
Aside from the many instances of what Meade has mentioned (repeatedly calling a function to get a value that you could store and refer to instead), chat commands are slow as hell... remove all of the llOwnerSay()'s and store that data and report it at the end instead for a more accurate time result.
Kidd Krasner
Registered User
Join date: 1 Jan 2007
Posts: 1,938
08-09-2007 10:07
Parameters are passed by value, so every time you call SubStrIndx, you're making an expensive copy of the Hop string. In most languages, strings are passed by reference, so this would be fine. But as much as I hate to say it, this would be a case where using Hop as a global would make sense - except for one thing.

The one thing is that you should be able to get rid of SubStrIndx and the mod % 6 tests with the simple, decades-old tactic of using sentinels in your string.

For example, instead of
Hop = "000000"
Hop += "02030502040703050803060A04060904070B05060705083E"

use
Hop = ";000000;"
Hop += "020305;020407;030508;03060A;040609;04070B;050607;05083E;"

Then when you do your searches in the string, you can use:

llSubStringIndex(Hop, ";" + origin + blocking)

Simiilarly, for the other search, you can use

llSubStringIndex(Hop, blocking + ";" + origin)

(not tested, I might have the semicolon in the wrong place). However, I'm guessing that with this tactic, you won't need the second search at all.

Finally, I don't know if the initial 000000 is there as a placeholder or because you actually need to find the 0000 case. If you don't need it, then you can remove that line entirely, but remember to change the next to be Hop = ";...." (i.e., you still need a leading semicolon for the first search, and, of course, don't do it as a +=).
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
08-09-2007 10:13
Oooo.. Good stuff, Kidd.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Gregory McLeod
Registered User
Join date: 21 Oct 2006
Posts: 278
08-09-2007 11:11
I will try to respond to all the above in one go.
From: Meade Paravane
Without really looking too close at this, it seems like you're timings are all under 0.1 of a second and some are closer to 0.01 of a second.

What kind of numbers did you hope to see? How closely did you look at the sim performace *before* running these tests?
I admit to a little subterfuge here. SL was not available for me to make these timings so I used LSLEditor execution debug which of course gives totally false execution timings being my PC internally generated. SL timings could be obtained by doing what I suggested. I have tried it when I first wrote this code and I recognise the variations that can be caused by other load on the sim. Many repeated tests in different sims has given me a feel for the numbers loop1 is about 0.11 secs and loop2 about 0.22 secs.

From: Meade Paravane
Not sure how LSL works internally but, in general, string operations can be expensive.

For example, that big honkin' string named Hop never changes but you call SubStrIndx on it in a loop and that calls llStringLength on Hop, every time. Unless LSL uses length-prefixed strings, getting the length so often is probably a big expense. Instead of doing that, have a global integer for the length and set it in LoadHop.

Also, in GetHopValues, you use "origin+blocking" and "blocking+origin" but these string variables never change - use local variables before the loop and just do the concatenations once..

There may be other things you can do to speed this up but those 2 jumped out at me. The first, I suspect, will be the biggest win.
Removing the llStringLength inside the loop is a good one didn't notice that. Similarily taking the origin+blocking blocking+origin outside the loop is a good one too.
Thanks
From: Shadow Subagja
Aside from the many instances of what Meade has mentioned (repeatedly calling a function to get a value that you could store and refer to instead), chat commands are slow as hell... remove all of the llOwnerSay()'s and store that data and report it at the end instead for a more accurate time result.
The llOwnerSay's are only in the example code to display for debugging purposes and are not in the code in reality. Thanks for the thought.
From: Kidd Krasner
Parameters are passed by value, so every time you call SubStrIndx, you're making an expensive copy of the Hop string. In most languages, strings are passed by reference, so this would be fine. But as much as I hate to say it, this would be a case where using Hop as a global would make sense - except for one thing.

The one thing is that you should be able to get rid of SubStrIndx and the mod % 6 tests with the simple, decades-old tactic of using sentinels in your string.

For example, instead of
Hop = "000000"
Hop += "02030502040703050803060A04060904070B05060705083E"

use
Hop = ";000000;"
Hop += "020305;020407;030508;03060A;040609;04070B;050607;0 5083E;"

Then when you do your searches in the string, you can use:

llSubStringIndex(Hop, ";" + origin + blocking)

Simiilarly, for the other search, you can use

llSubStringIndex(Hop, blocking + ";" + origin)

(not tested, I might have the semicolon in the wrong place). However, I'm guessing that with this tactic, you won't need the second search at all.

Finally, I don't know if the initial 000000 is there as a placeholder or because you actually need to find the 0000 case. If you don't need it, then you can remove that line entirely, but remember to change the next to be Hop = ";...." (i.e., you still need a leading semicolon for the first search, and, of course, don't do it as a +=).
I really like that suggestion. A good lateral thought. I need time to examine whether this would work with the data as is. You may have detected that I am using the origin+blocking and blocking+origin to eliminate duplicate string content from Hop. So the search would, as you say, need to be different for each loop1 or loop2 context. The preceding 000000 is needed in this case to allow it to search the blocking+origin case for the first pair of values 0203 to find 0302 and get 00 which is significant and also make the result MOD 6 testable. Both of these I will look into.

VERY MANY THANKS FOR TAKING THE TIME TO REVIEW THE CODE.

I knew you guys would come up with the solutions, I am still open to other suggestions. It could make the difference between a reasonable response in a game and an unacceptable one. Particularily when this Hop code gets called up to about 80 times for each move.