Jump to content

Trying to find a low lag way to generate multiple semirandom values


ChinRey
 Share

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

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

Recommended Posts

I need some advice about script performance.

I'm trying to make an object seem to move around at random and I understand that llFrand(); is a rather processor heavy function. So I'm trying a slightly different method than the obvious one. Rather than have the script generate a ton of random floats, I only use a few seed values and then do some simple calculation and reshuffling to generate a list of vectors. Here's what I have right now:

 

        float Random1=llFrand(1);
        float Random2=llFrand(1);
        float Random3=llFrand(1);
        list Vectors=[
            "<" + (string) Random1 + "," + (string) Random2 + "," + (string) Random3 + ">",
            "<" + (string) Random3 + "," + (string) (Random2*.88) + "," + (string) Random1 + ">",
            "<" + (string) Random3 + "," + (string) (Random2*Random3) + "," + (string) Random1 + ">",
            "<" + (string) Random3 + "," + (string) Random2 + "," + (string) Random1 + ">",
            "<" + (string) Random2 + "," + (string) Random1 + "," + (string) Random3 + ">"
        ];

 

The main question is, does this make sense or do I loose as much performance from the calculations and list lookups as I gain from reducing the number of llFrand() calls?

Also, if this is a good idea, does anybody have any guidelines as to how many seed values and how many list items I should use? I will need at least 300 vectors - it's a temporary object and the position needs to be updated at least five times a second - but I can always recycle the list if that's a more efficient solution.

Edited by ChinRey
Link to comment
Share on other sites

My initial guess is that your method is slower, but uses less memory. (Which doesn't directly affect speed.) But in any case, llFrand is not what anyone would call "laggy." We're talking about a few milliseconds for the entire chunk of code here. My advice is always going to be "just write a functional/readable script first, then look for places to optimize."

I ran this test: http://wiki.secondlife.com/wiki/LSL_Script_Efficiency
After running this code 5 times, the results for your code were 25.5154 ms in total, 5.10308 ms on average.
After running this code 5 times, the results for the code were 26.8786 ms in total, 5.37572 ms on average.

So your method is faster but only by a fraction of a millisecond on average. And your method obviously is less random if that matters.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

6 hours ago, Wulfie Reanimator said:

So your method is faster but only by a fraction of a millisecond on average. And your method obviously is less random if that matters.

Thanks a lot! :)

A fraction of a millisecond saved for this small test script may actually matter. The full script, the way this kind of script is usually done, has to generate 5-10 vectors, that is 15-30 floats, every second for a minute before it expires and there may well be as many as 50 instances of the script running at the same time in the same sim. There may even be hundreds spread across a sim - I suppose I better warn customers about overdoing it. I already know how to drastically reduce the number of vectors needed and that's where the big saving is. But every little bit helps and if I can reduce the time it takes to generate each vector a tiny little bit without making the script more complicated, I'll sure go for that too.

The numbers don't have to be very random. All that really matters is that each instance is noticeably different from the others. I should be able to get away with a predefined list run through a llListRandomize(); on rez but that would probably require a longer list so I might loose more than I gained that way.

I suppose I should explain what it's for. A few years ago Arduenn Schwartzmann was selling a butterfly rezzer using temporary objects. Unlike particle butterflies, they are animated and unlike butterfly paths, they move around freely and they also have better animations. When I asked him why he had discontinued such a great and unique work, he told me it had turned out to be too laggy and he gave me permission to borrow the idea and see if I can get it to work.

He didn't say what kind of lag issues they caused. His butterflies have some obvious render issues but it might have caused a bit too much script load too. I already know how to reduce the render cost to a minimum - that's my speciality after all - but to cover all bases, I also want to see if I can do anything about the script time.

Traditionally a script like this generates a new random vector every time the object moves but JubJub Forder claims he has managed to reduce the script load of his flying ravens by generating a list of vectors at the beginning rather than one at a time. If anybody knows what they are talking about, he does and it makes a lot of sense anyway. The traditional script would require up to 1800 different vectors but with a few tricks (no, I'm not going to post every secret here ;))  I can reduce it considerably. Hopefully I can get it down to 10 vectors or less but I'll be happy with 20.

There are still a lot of details to work out and I don't know if it wil be possible to cut down the lag enough but this is lookign better and better. It seems there a good chance this bird butterfly will fly. ^_^

 

Edited by ChinRey
Link to comment
Share on other sites

2 hours ago, ChinRey said:

Traditionally a script like this generates a new random vector every time the object moves but JubJub Forder claims he has managed to reduce the script load of his flying ravens by generating a list of vectors at the beginning rather than one at a time. If anybody knows what they are talking about, he does and it makes a lot of sense anyway.

Nothing is free...

Odds are it's a trade off, instead of burning x milliseconds every move generating a new value, you burn a large chunk of ms ONCE when the scripts start up, ie, on rez or on sim restart, with a hefty cpu time load, but less load while actually running. So, a possible advantage for something like wandering critters that are always on the parcel.

Just NEVER put them in a persistant-temp-rerezzer to save prim count, as the repeeated startup lag every time they temp derez and rerez would lag a sim like a heart beat (yeah I've seen that kind of thing happen, firefly rerezzers that caused a drop in sim/physics fps of 60 %, every 30 seconds or so for about a 1/4 second, like a laggy heart beat...)
 

  • Like 1
Link to comment
Share on other sites

56 minutes ago, Klytyna said:

Nothing is free...

Not even lunch?

 

56 minutes ago, Klytyna said:

instead of burning x milliseconds every move generating a new value, you burn a large chunk of ms ONCE when the scripts start up

Very good point. There has to be more to JubJub's script load saving trick than the time the values were generated. A system for reusing floats in different positions in different vectors will help a little bit of course but as Wulfie's test shows, only marginally. The real saving has to be some way to generate movements that seems random enough from a reduced data set. I can think of six ways to do that. One is very simple and probably good enough for this purpose. The others require a slightly heavier script and may not be worth it.

 

56 minutes ago, Klytyna said:

Just NEVER put them in a persistant-temp-rerezzer to save prim count

Of course not! But it's a very good point.

They need to be temporary to be reasonably easy to control. With permanent critters you need a way to limit their range and that adds quite a lot of complexity to the script. Also, if/when you want to get rid of them, you want to be able to do it simply by switching them off. I don't think it's a good idea to let them all have open listens so they can be remote controlled and even with area search, finding and killing them manually can be quite a hassle.

Not counting all the different particle thingies, I have three kinds of free range critters at large at Coniston at the moment, Arduenn's butterflies, Jenne Dibou's rats and mice and ee oh's ravens and seagulls. The rats and mice can be made permanent and I swear I'll never ever make that mistake again. ;)

They are scripted meshes though so there is no real reason to limit them to the one minute temp rez time period. I can reduce the rez frequency considerably if I let them live a bit longer and kill them with llDie() instead. Yet another way to cut down the load. Thank you Klytyna! ^_^

Edited by ChinRey
Link to comment
Share on other sites

2 hours ago, ChinRey said:

erated. A system for reusing floats in different positions in different vectors

Off the top of my head...

Generate two short lists, one of random y-axis offsets, one of random x-axis offsets, positive and negative.

Then you just use two random numbers to pick an x and y axis offset from the lists and add that to the current position x & y values. Or even just pick the next list value, the 'randomness' being put in the lists when they were created on rez, a pair of lists of integer values wont use that much memory, and few people will notice that the changes in position are from two lists of 50 values each, as the addition of these to the current position, will break up the pattern even when the lists roll over and start again.

2 hours ago, ChinRey said:

With permanent critters you need a way to limit their range

Maybe add a simple 'range from original rez point' checker to make sure it doesn't stray too far. Hmm, random thought, is there a way to get the name of the current parcel via a script?

if currentparcel != rezzedparce { {llDie(); }

Solves the excessive wandering nicely if it's possible.
 

  • Like 1
Link to comment
Share on other sites

2 hours ago, Klytyna said:

Off the top of my head...

Generate two short lists, one of random y-axis offsets, one of random x-axis offsets, positive and negative.

Yes. Here's another one:

integer x=0;
integer y=0;
list seeds=[
    "<0.9,0.8,0.7>",
    "<0.888,0.54,0.352>",
    "<0.836,0.762,0.8978>",
    "<0.723,0.72,0.92>",
    "<0.76,0.98,0.65>",
    "<0.87,0.21,0.4>",
    "<0.8,0.9,0.5>",
    "<0.87,0.5,0.276>",
    "<0.65,0.45,0.465>"
];

default(){
      state_entry{
      	llSetTimerEvent(0.1);
      }
      
      timer(){
      	vector output=((vector) llList2Vector(seeds,x))*((vector) llList2Vector(seeds,y));
      	llOwnerSay((string) output);
      	x+=1;
      	y+=1;
      	if(x>=8)x=0;
      	if(y>=7)y=0;
      }
}

Unless I've overlooked some typos,  this script will produce a series of 90 vectors before it starts a complete repeat. There will be some shorter repeating sequences (there are only 72 possible values) but I can't imagine that will be a problem.

If it is:

integer x=0;
integer y=0;
list seeds=[
    "<0.9,0.8,0.7>",
    "<0.888,0.54,0.352>",
    "<0.836,0.762,0.8978>",
    "<0.723,0.72,0.92>",
    "<0.76,0.98,0.65>",
    "<0.87,0.21,0.4>",
    "<0.8,0.9,0.5>",
    "<0.87,0.5,0.276>",
    "<0.65,0.45,0.465>"
];

default(){
      state_entry{
      	llSetTimerEvent(0.1);
      }
      
      timer(){
      	vector output=((vector) llList2Vector(seeds,x))*((vector) llList2Vector(seeds,y));
      	llOwnerSay((string) output);
      	x+=1;
      	y+=1;
      	if(x>=8){
      		x=0;
      		llListRandomize(seeds,1);
      	}
      	if(y>=7)y=0;
      }
}

This will produce 81 possible values and they are constantly reshuffled so except for sheer coincidences, there won't be any recurring sequences.

I suspect both these solutions will be overkill for what I'm trying to do though.

(Edit: the more I think about this, the more I realize how similar this is to the challenges I'm working on as a builder at the moment. I'm trying to make massive plant fields of all kinds with a density never seen in SL before but without causing much lag or spending too much LI. Just like here, the problem is that the computer prefers orderly patterns but the build calls for chaos and the solution in both cases is of course to find simple patterns that look chaotic.)

Edited by ChinRey
Link to comment
Share on other sites

34 minutes ago, ChinRey said:

this script will produce a series of 90 vectors

Forget vector offsets, use signed integers, 30 x axis offsets, 30 y axis, 30 z axis...

30 x 30 x 30 = 27,000 'vectors' from 90 list entries... Random enough for you?
 

  • Like 1
Link to comment
Share on other sites

36 minutes ago, Klytyna said:

Forget vector offsets, use signed integers, 30 x axis offsets, 30 y axis, 30 z axis...

30 x 30 x 30 = 27,000 'vectors' from 90 list entries... Random enough for you?
 

Wellll, I called my 72 and 81 values overkill :P

No need to waste reqources on separate lists for x, y and z though. Get all values from the same list, only with different start and reset points.

If this gets any efficienter now, we'll end up with negative processing time. :P

Edited by ChinRey
Link to comment
Share on other sites

Why not replace llFrand with something more efficient, like this linear feedback shift register pseudorandom number generator...

integer lfsr = 12345;
integer bit;

integer rand()
{
  bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
  return lfsr =  (lfsr >> 1) | (bit << 15);
}

That produces random 16-bit integers, which should be good enough.

I quickly whacked the generation of 30 such random numbers into Wulfie's measurement harness, like this...

//IMPORTANT: Only perform tests in an empty region.
// To reduce contamination and be sure to wearing no attachments.
// Preferably do tests in a private sim with one on it.
// Don't move while performing the test.
// There is a margin of error so run the tests multiple times to determine it.
 
integer time() { // count milliseconds since the day began
    string stamp = llGetTimestamp(); // "YYYY-MM-DDThh:mm:ss.ff..fZ"
    return (integer) llGetSubString(stamp, 11, 12) * 3600000 + // hh
           (integer) llGetSubString(stamp, 14, 15) * 60000 +  // mm
           llRound((float)llGetSubString(stamp, 17, -2) * 1000000.0)/1000; // ss.ff..f
}
 
integer lfsr = 12345;
integer bit;

integer rand()
{
  bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
  return lfsr =  (lfsr >> 1) | (bit << 15);
}

default {
    state_entry() {

  }
  touch_start(integer num_detected){
              llOwnerSay((string) llGetFreeMemory());
     
        //test variables
        float counter;
     
        //framework variables
        float i = 0;
        float j = 0;
        float max = 10000; // 2ms of work takes 20 seconds to repeat 10,000 times, plus overhead
     
        float t0 = time();

        float Random;
        
        do {
            integer lc;
            for(lc=0;lc<30;lc++){ // generate Random 30 times
                Random=rand();
            }
             counter += 1;
     
        }while (++i < max);
        float t1 = time();
        do ; while (++j < max);
        float t2 = time();//remove the time required by the framework
        float elapsed = ((t1 - t0) - (t2 - t1))/max;
        llOwnerSay("The function in the loop took a total of " + (string)elapsed + " milliseconds.");
        llOwnerSay((string)Random);
    }  
}

I've no idea if I've built the harness correctly, but it seems to take 0.35 milliseconds per iteration. You'll have to scale the random numbers to suit, but that would have been necessary anyway.

Edited by Madelaine McMasters
  • Like 2
Link to comment
Share on other sites

I'm a bit confused. Why are you using strings in a list (I get the string list part) and typecasting llList2Vector to vector, if speed is the most important thing?

You've already said the positions don't need to be truly random, just "appear random enough," so you could get away with just pre-determined raw variables.

Or even better with Madelaine's function. Haven't double-checked if it's correct and it doesn't include the rest of the code required.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

18 minutes ago, Madelaine McMasters said:

Why not replace llFrand with something more efficient, like this...

...

I've no idea if I've built the harness correctly, but it seems to take 0.35 milliseconds per iteration.

You mean building a better random numebr generator from scratch than the one that comes with the package? Wouldn't that be rude?

 

15 minutes ago, Wulfie Reanimator said:

I'm a bit confused. Why are you using strings in a list and typecasting llList2Vector to vector, if speed is the most important thing?

Oh, good catch. This is just a proof-of-concept script and the list was typecast for llOwnerSay readouts at different stages. I would of have remembered to change that for the final product... certainly... probably... possibly...

 

15 minutes ago, Wulfie Reanimator said:

You've already said the positions don't need to be truly random, just "appear random enough," so you could get away with just pre-determined raw variables.

Every new copy rezzed will need a unique pattern. It will be very noticeable if they all act exactly the same right from the start. Sequence repeats at a later stage shouldn't matter though.

Edited by ChinRey
Link to comment
Share on other sites

5 minutes ago, ChinRey said:

You mean building a better random number generator from scratch than the one that comes with the package? Wouldn't that be rude?

Not better, better suited to your task. I didn't construct vectors in my example. I imagine you'd do that right where you need them. If llFrand() is the issue, it makes sense to replace it directly rather than construct some list heavy workaround. You just call rand() where you need it.

Edited by Madelaine McMasters
  • Like 1
Link to comment
Share on other sites

28 minutes ago, Wulfie Reanimator said:

Or even better with Madelaine's function. Haven't double-checked if it's correct and it doesn't include the rest of the code required.

Yeah, and it's possible that the vector construction is taking longer than the llFrand(). Are we sure llFrand() is really an issue here?

ETA: I just swapped my rand() for llFrand() in your second example and it barely speeds things up. I don't think llFrand() is an issue.

ETA2: Removing the list generation cuts execution time dramatically, suggesting that the vectors should be constructed as needed, not pulled from a list.

Edited by Madelaine McMasters
  • Like 3
Link to comment
Share on other sites

1 hour ago, ChinRey said:

You mean building a better random numebr generator from scratch than the one that comes with the package? Wouldn't that be rude?

His function isn't the same as llFrand, his function is only pseudo-random. (pseudo just means "not truly")

If you do this:

default
{
    touch_start(integer total_number)
    {
        llOwnerSay( (string)rand() );
    }
}

And touch the object a couple times, then reset the script and touch it again, you'll get the same sequence of the "random" numbers. llFrand doesn't do this.

 

1 hour ago, ChinRey said:

Every new copy rezzed will need a unique pattern. It will be very noticeable if they all act exactly the same right from the start. Sequence repeats at a later stage shouldn't matter though.

Yeah, you're right, so just cut out the "pre-determined" from what I said and still use raw variables, not a list! (What I mean by "raw" is just "normal" variables, not ones stored in a list.)

52 minutes ago, Madelaine McMasters said:

Yeah, and it's possible that the vector construction is taking longer than the llFrand(). Are we sure llFrand() is really an issue here?

Even on a non-empty rental sim, running this code (all I did was change llFrand to string and remove two multiplies) finishes as low as 1.8ms and always below 2.5ms. On an empty sim, the llFrand version averaged above 5 ms.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

44 minutes ago, Madelaine McMasters said:

Are we sure llFrand() is really an issue here?

No, we're not. It's been drilled into me by people who are suppsoed to know such things that random generators are heavy and I have to admit I've never done a reality check.

However I read this MP listing a while ago (it was crows, not ravens, sorry):

https://marketplace.secondlife.com/p/Dead-Center-Watching-Crows/2445328

As far as I can see JubJub clearly says he has reduced the script lag by eliminating continuous random calls. He knows a thing or ten about scripts of course and he is also the kind of person who tests things.

Edited by ChinRey
Link to comment
Share on other sites

28 minutes ago, Wulfie Reanimator said:

Yeah, you're right, so just cut out the "pre-determined" from what I said and still use raw variables, not a list!

I'm not sure what you mean by that. Is there another better way to store multiple values for a variable or do we misunderstand each other?

I do need several unique values for each copy, not just one. They don't have to be completely random but they can't be obviously predictable either and I certainly can't use the same value several times in a row.

 

Here's what I want to achieve:

default(){
      state_entry{
      	llSetTimerEvent(0.1);
      }
      
      timer(){
      	llSetPos(llGetPos( )+<(llFrand(1)-0.5),(llFrand(1)-0.5),(llFrand(1)-0.5)>);
      }
}

(This is a script I write here and now. I'm not even logged on to any grid so it's completely untested and I take no responsibility for any typos or logical breakdowns. Oh and if you try something like this, make sure it's a big object or a temporary one, or at least one with a name easy to identify in the area search list. I do speak from experience there ;))

 

 

Edited by ChinRey
Link to comment
Share on other sites

I've never noticed llFrand being particularly lag-inducing, but in general I don't see why you'd need to generate a new random sequence every run. Instead I might try storing a constant list of random perturbations, and then at run time pick one random initial offset plus one random starting point in the list of perturbations and declare it all "random enough".

Also, how precise do these perturbations need to be? That is, do they really need to have three 32-bit floats, or can they be a single 32-bit word, bit-masked and shifted three ways to make a vector? (Only relevant if you need such a long sequence that memory is a problem storing the full vector representation. Would need to test, though, if the bitwise operations are all that efficient in a script -- LSL library calls are pretty far from assembly language.)

But again, I suggest profiling to confirm that llFrand is any kind of problem at all. As suggested above, I certainly wouldn't want to cons up a list at runtime and then extract from it, but maybe even just the list-extraction calls exceed the cost of runtime llFrands -- and if so, whether or not one llFrand and some bitwise operations might beat three llFrands.

  • Like 2
Link to comment
Share on other sites

1 hour ago, Qie Niangao said:

But again, I suggest profiling to confirm that llFrand is any kind of problem at all.

I couldn't find a completely empty sandbox but I did my best at Mesh Sandbox 3 on the beta grid. Using the same test script as Wulfie did, setting two variabes with llFrand();

    do {
 
      float value1=llFrand(1);
      float value2=llFrand(1);
      counter += 1;
 
    }
//I'm only including the do.. loop since the rest of code is well known anyway

Six tests first, results ranging from 0.0136 to 0.024.

Next, setting ten variables with llFrand(); - Four tests, times 0.1396 to 0.1528

It is worth noticing that on both those test rounds times were dropping steadily. The highest number is from the first test, the lowest from the last (or two last for the two variables test).

Replacing llFrand(1) with the integer 1 - again, ten variables set - 7 tests, times ranging from 0.0016 to 0.0088 - no noticeable pattern

Replacing the integers with floats - 6 tests, times between 0.0016 and 0.0108.

Finally I redid the first test (two variables and llFrand()) to see if I could reproduce the speeding up tendency. I couldn't, but the times were consistently higher overall than the first round: seven tests, results varying from 0.0284 to 0.0396.

As I said, it was hardly ideal test conditions but adding Wulfie's even more casual second test and maybe also JubJub's comment on MP, I think it's fair to conclude that yes, llFrand() is a rather time consuming function for the server to perform.

The script in my previous post does exactly the right job and it's ony eight lines. But it needs to run the llFrand() function 30 times a second. If there are 100 copies of the script running at the same time - which is high but not at all unrealistic - we need 3000 randon numbers every second and if we stipulate that each take 0.01 ms to generate, we end up with 30 ms per second - or 0.67 ms per frame.

I suspect Klytyna was right that the rezzer would be the major script load factor and that calls for a completely different (and fortunately very simple) solution. But I think it's clear that generating those random vectors enough to the load it's worth looking at too.

Link to comment
Share on other sites

6 hours ago, ChinRey said:

If there are 100 copies of the script running at the same time - which is high but not at all unrealistic -

Eek. Script lag wouldn't be my first concern in this case. If a hundred objects are changing positions ten times a second, that's a scary lot of object updates to pump over the wire to each viewer looking at the scene. If only one person in the sim, probably not a big deal, but I'm always shy about exacerbating crowd scaling effects.

Anyway, in some very informal testing, it does seem that forming a vector from three calls to llFrand() takes substantially more time than accessing a vector from a list. (Ten thousand triple-llFrand vector creations in about 0.8 seconds compared to 0.3 seconds for ten thousand sequential retrievals from a 100-element list of vectors; a compromise 0.5 seconds to retrieve a random vector from that list ten thousand times).

(Tangentially, though: I'm curious why folks are using this time() function over llResetTime() and llGetTIme() ? Have I been doing it wrong all along?)

Edited by Qie Niangao
  • Like 1
Link to comment
Share on other sites

1 hour ago, Qie Niangao said:

Eek. Script lag wouldn't be my first concern in this case. If a hundred objects are changing positions ten times a second, that's a scary lot of object updates to pump over the wire to each viewer looking at the scene. If only one person in the sim, probably not a big deal, but I'm always shy about exacerbating crowd scaling effects.

Oh, I'm talking about across a whole sim, including skyboxes and sky platforms and everything. So only a handful in view at any given location - hopefully.

Maybe I should add a fucntion to the rezzer to stop it when there are nobody arund to see the butterflies though...

 

1 hour ago, Qie Niangao said:

Anyway, in some very informal testing, it does seem that forming a vector from three calls to llFrand() takes substantially more time than accessing a vector from a list.

Thank you! :)

That was the next step of course.

 

1 hour ago, Qie Niangao said:

(Tangentially, though: I'm curious why folks are using this time() function over llResetTime() and llGetTIme() ? Have I been doing it wrong all along?)

You mean Timer(){} event? :P

It's a good question. There are certainly scripts where either option would work and we do tend to default to the timer event. But in this particular case, the Timer(){} is definitely the way to go. There has to be some active event for a script to do anything at all and rigging one of the others to work as a repeating timer with llResetTime()/llGetTim() is rather cumbersome.

However, an llSetPrimitiveParams() inside a while() loop inside an on_rez(){} event is an intriguing alternative since I will need a counter for the butterfly killer anyway and the built in delay of llSetPrimitiveParams() seems to fit quite well with what I need.

I think we need to update an old saying here: There is more than one way to rez a butterfly.

Edited by ChinRey
Link to comment
Share on other sites

2 hours ago, ChinRey said:

You mean Timer(){} event?

No, I mean the time() function that Wolfie got from the wiki (and Maddie used too) in the timing measurement harness. It parses the return value of llGetTimestamp to calculate an integer milliseconds since midnight, which seems to be working but at first glance I'd expect it to introduce a lot more overhead than the library calls I mentioned -- but we all know "first glances" in LSL can be deceiving.

  • Like 1
Link to comment
Share on other sites

9 hours ago, Qie Niangao said:

but we all know "first glances" in LSL can be deceiving.

Yes, you need second sight to comprehend lsl.

I didn't even look at the code for the test script, I just added my own code to it, and I guess Wulfie and Madelaine did the same. Now that you mention it, it does look like a rather strange solution. One possible explanation is that the speed test script as it is now dates back to early 2007 and llGetTime()/llResetTime()/llGetAndResetTime() may not have been as reliable back then. Those function were affected by time dilation back then and their wiki articles did contain warnings not to use them for long term monitoring of a script's run time.

Edited by ChinRey
Link to comment
Share on other sites

There is surely more stuff relevant for the performance than llFrand. Optimizing one single thing will probably not have a visible effect on the overall performance.

However - I made a little test for llFrand:

default
{
    touch_start(integer total_number)
    {
        float avg;
        float test;
        
        llSay(0,"START");
        float t=llGetTime();

        integer i=200000;
        while (i-->0) {
            
            test = llFrand(1);
            
            avg += test;

            if (i%20000==0) llSay(0,(string)test);
            
        }
        
        llSay(0,"STOP "+(string)(llGetTime()-t)+" / "+(string)(avg/200000));
    }
}

Not too bad for 200000 numbers plus some extras.

Now with a more simple random number generation:

integer seed = 837465481;

default
{
    touch_start(integer total_number)
    {
        float avg;
        float test;
        
        llSay(0,"START");
        float t=llGetTime();

        integer i=200000;
        while (i-->0) {
            
            seed = (seed * 16807 % 2147483647) & 0x7FFFFFFF;
            test = (float)(seed-1) / 2147483646;

            avg += test;
            
            if (i%20000==0) llSay(0,(string)test);
            
        }
        
        llSay(0,"STOP "+(string)(llGetTime()-t)+" / "+(string)(avg/200000));
    }
}

That is alot faster, needs about 60% of the llFrand-test-script time.

Probably some room for optimizations but I doubt that it's possible to squeeze out much more performance since llFrand is already not too bad.

 

Edited by Nova Convair
  • Thanks 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2337 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...