|
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.
|