Jump to content

Profaitchikenz Haiku

Resident
  • Posts

    2,837
  • Joined

  • Last visited

Everything posted by Profaitchikenz Haiku

  1. A revision to the prime number method posted above - I hadn't fully implemented the method of summing all the digits to test for division by three. The third test is purely number-driven, there are no timers or events once the test commences, so it's purely down to how much the script can get to run in the region scheduler, it won't be held up itself waiting for events. (To the mathematicians, I know there are faster, more elegant, more efficient algorithms, but for the purposes of this test I just want a pedestrian old slogger to grind away at the problem). Make a prim, drop this in, touch and go // find all the prime numbers in the positive range of SL integers. // time the routine key owner; integer startTime; integer endTime; list primes = [1,2,3,5,7]; integer freemem; announce(string message) { llSetText(message, <1.0,1.0,1.0>,1.0); } findPrimes() { integer value = 9; integer end = 101010101; // string digits; integer len; integer isPrime; string notPrimes = "024568"; integer ii; do { isPrime = 0; // assume it isn't, as primes are rare digits = (string) value; len = llStringLength(digits); if( llSubStringIndex(notPrimes, llGetSubString(digits, len-1,len-1) ) < 0) { integer sum = 0; do { for( ii = 0; ii < len; ii++) { sum += (integer) llGetSubString(digits, ii, ii); } digits = (string) sum; len = llStringLength(digits); if( len > 1) sum = 0; } while( len > 1); if( sum % 3 != 0) { ii = llGetListLength(primes) - 1; integer remainder; integer testVal; integer sqrtVal = (integer) llSqrt(value); while( llList2Integer(primes, ii) > sqrtVal) ii--; // faster than just taking the half-value to be tested do { testVal = llList2Integer(primes, ii); remainder = value % testVal; }while( (--ii > 0) && (remainder != 0) ); // don't let ii reach zero as everything is divisible by 1 if( remainder != 0) { //llOwnerSay("is prime"); primes += value; freemem = llGetFreeMemory(); announce("Free Memory " + (string) freemem + " Prime " + (string) value); } //else llOwnerSay("Was divisible by " + (string) testVal); } //else llOwnerSay("Divisible by 3"); } //else llOwnerSay("Ends with known non-prime digit"); value +=1; } while(value < end && freemem > 1000); endTime = (integer) llGetWallclock(); announce((string) llGetListLength(primes) + " Prime numbers found in " + (string) (endTime - startTime) + " seconds" + " last value " + (string) value); if( freemem <= 1000) llOwnerSay("Stopped for low memory"); } default { state_entry() { owner = llGetOwner(); freemem = llGetFreeMemory(); announce("Free Memory " + (string) freemem); } touch_start(integer touches) { key toucher = llDetectedKey(touches - 1); if( toucher == owner) { startTime = (integer) llGetWallclock(); findPrimes(); } } }
  2. It's their way of asking each other what they had for dinner. We have words so we don't need to do that.
  3. But that in turn means SL residents would have to accept an influx of Roblox/Anime/Minecraft appearances, and from the tenor of the posts I've seen here that would not go down well.
  4. "I wouldn't shop in any store that would admit the likes of me through the doors"
  5. I had one some time ago, somehow SL forums lost the uploaded picture a way back, I'm waiting fro them to find it again.
  6. I have completed some testing in five regions using a script to find as many prime numbers as the script memory will allow. I chose this method after Monty's explanation because I realised some scripts might be parked in the "not able to run" category simply because they might be waiting for the timer, as well as for something far more sinister such as a data server request or they issued one of the calls that sleep the script for anything from .1 to several seconds. Here are the results: Region, details, %script run, time to find first 403 primes Premium sandbox - almost empty - 100% - 427 secs Mainland - light residential all in use - 100% - 640 secs Full private region - busy residential 2/3rd in use - 100% - 759 secs Mainland - residential - 65% - 1388 secs Mainland - residential - 32% - 2047 secs I see a correlation between an increase in the time required to complete the task and a decreasing value of the % scripts run figure. I see it as a reasonable metric, perhaps closer to seaweed than a barometer, but it nevertheless does seem to be of some use as-is. Do bear in mind that the people who began clamouring abut this a couple of years ago weren't constantly watching their stats bars and started seeing a low figure and went "Ooh That's not right!" and became obsessed with the figure. They saw things around them not quite behaving as expected, and in looking through the things they had available, came upon this scripts run figure. They then discovered that if they requested a region restart and repeatedly did so until they got a better % scripts run figure (and it could take half a dozen goes), the poor performance that had been annoying them went away. ETA, the script that produced these figures can be found in the sub-forum LSL Library, together with a few others. I would be interested to see how homesteads perform.
  7. The third test is purely number-driven, there are no timers or events once the test commences, so it's purely down to how much the script can get to run in the region scheduler, it won't be held up itself waiting for events. (To the mathematicians, I know there are faster, more elegant, more efficient algorithms, but for the purposes of this test I just want a pedestrian old slogger to grind away at the problem). Make a prim, drop this in, touch and go // find all the prime numbers by a brute-force square-root upper bound method // exclude those numbers ending with digits 024568 // exclude numbers whose sum of all digits is evenly divisible by three // take the square root of the test number and try dividing by all known primes less than that value, exclude if one gives remainder 0 // stop at 1000 bytes of memory free // time the routine key owner; integer startTime; integer endTime; list primes = [1,2,3,5,7]; integer freemem; announce(string message) { llSetText(message, <1.0,1.0,1.0>,1.0); } findPrimes() { integer value = 9; integer end = 10101; // wildly optimistic, you'll be out of memory a qaurter of the way there string digits; integer len; integer isPrime; string notPrimes = "024568"; // numbers ending with one of these digits can never be prime integer ii; do { isPrime = 0; // assume it isn't, as primes are rare digits = (string) value; len = llStringLength(digits); if( llSubStringIndex(notPrimes, llGetSubString(digits, len-1,len-1) ) < 0) { integer sum = 0; for( ii = 0; ii < len; ii++) { sum += (integer) llGetSubString(digits, ii, ii); } if( sum % 3 != 0) { ii = llGetListLength(primes) - 1; integer remainder; integer testVal; integer sqrtVal = (integer) llSqrt(value); while( llList2Integer(primes, ii) > sqrtVal) ii--; // faster than just taking the half-value to be tested do { testVal = llList2Integer(primes, ii); remainder = value % testVal; }while( (--ii > 0) && (remainder != 0) ); // don't let ii reach zero as everything is divisible by 1 if( remainder != 0) { primes += value; freemem = llGetFreeMemory(); announce("Free Memory " + (string) freemem + " Prime " + (string) value); } //else llOwnerSay("Was divisible by " + (string) testVal); } //else llOwnerSay("Divisible by 3"); }//else llOwnerSay("Ends with known non-prime digit"); value +=1; } while(value < end && freemem > 1000); endTime = (integer) llGetWallclock(); announce((string) llGetListLength(primes) + " Prime numbers found in " + (string) (endTime - startTime) + " seconds"); } default { state_entry() { owner = llGetOwner(); freemem = llGetFreeMemory(); announce("Free Memory " + (string) freemem); } touch_start(integer touches) { key toucher = llDetectedKey(touches - 1); if( toucher == owner) { startTime = (integer) llGetWallclock(); findPrimes(); } } }
  8. So can I assume that some scripts, such as very simple lightweight ones, will always run every frame when they need to more complex scripts, (possibly waiting on events), might not run at all in any one frame and so might perhaps only get run in 40% of the frames within the measuring period? I see what you mean about the metric. I think the crucial thing is how many scripts didn't get their full run time. If a large number of simple scripts all complete, their effect is to skew the metric too far towards the "I'm alright Jack" side. In your example to ponder, the single script that managed it isn't the issue, it's the held-back others that indicate something isn't optimal. The implications for me is that the test scripts I am putting up may need to be fleshed out with a lot more stuff so that they start to challenge the scheduler.
  9. The Time has come, the Walrus said... This next test is much simpler, a single prim with a single script, making a single measurement, one second. I'm currently waiting on a better explanation of what "% scripts run" means, but this script assumes it can get everything done that it needs to in a single pass and implement a wall clock accurate to a second. If for some reason it gets delayed too much, it's going to start losing time. // Implement a 1-second counter and an internal clock, compare it with an external clock key owner; integer WCnow; // wallCLock time integer WCstart; // kickoff time in seconds integer MYnow; // calculated time string clock_time(integer when) { integer seconds = when % 60; integer minutes = (when / 60) % 60; integer hours = when / 3600; return llGetSubString("0" + (string)hours, -2, -1) + ":" + llGetSubString("0" + (string)minutes, -2, -1) + ":" + llGetSubString("0" + (string)seconds, -2, -1); } announce(string message) { llSetText(message, <1.0,1.0,1.0>,1.0); } showTimes() { WCnow = (integer) llGetWallclock(); string details = "Wall clock " + clock_time( WCnow ); if(WCnow < WCstart) { WCstart = WCnow; // midnight has been and gone } details += " Elapsed seconds " + (string) (WCnow - WCstart); details += "\nMy clock " + clock_time(MYnow); details += " Elapsed Seconds " + (string) (MYnow - WCstart) ; integer drift = WCnow - MYnow; details += "\nDrift " + (string) drift; announce(details); } default { state_entry() { owner = llGetOwner(); announce("Looking for 00 seconds"); do { WCstart = (integer) llGetWallclock(); } while( WCstart % 60 != 0); MYnow = WCstart; llSetTimerEvent(1.0); announce("Starting"); } timer() { MYnow += 1; if( MYnow % 60 == 0) { showTimes(); } } }
  10. Somebody once asked me "How come your're always happily singing and humming? What' your secret?" and without thinking I answered "I'm too stupid to be miserable" Years later, I've realised how true those words were.
  11. Is there not a risk in going so that we're all of us going to be slowing SL down? I'm reminded of the time a VAX cluster I was working on began to run slow, and everybody then suddenly put on monitor to see for themselves, and.... we swam through treacle
  12. I've started tidying up some scripts that can be posted as examples of how to measure what might be happening in a region, but in writing up a description I've realised something. I don't know precisely what "% Scripts Run" is actually purporting to show. @Monty LindenIs it a) x% of all scripts are able to complete what they should have been able to do in the frame/timeslice in question b) A typical script is able to complete x% of what it should do within the frame/timeslice in question c) neither and a reasoned explanation can be provided d) none of the above, it's analogous to the food pellets that the rats in the Behavioural Psychologists cages gambled for So far I am thinking that you favour c) and Coffee favours d). I, and many others, have always believed it's a) but reviewing some of my earlier results I'm now pondering it might be b)
  13. Is there anybody who could claim to know all and everything about LSL and be believed? (Kruger-Dunning jibes aside)
  14. In a post in the server forums it was suggested that we try and assess the behaviour of regions to see if the % scripts run figure does actually equate to acceptable or poor performance. So here goes with in-region communications This test examines region communications for delays or missed messages using llRegionSay and llSay on two high-negative channels Four (slightly more) sets of messages are sent each minute, with 13 seconds between them. The messages are sent together, and immediately after sending them a timer is set to fire in 0,04 seconds (about two frames). If either message is not heard withing this time a timeout fault is logged. (Point about the tight timer is after the scripts). This test is more of a reassurance factor, I have not detected any errors yet running on 1: Mainland with 70% scripts run (main channel) 2. Mainland with 30% scripts run (main channel) 3. Mainland with 99% scripts run (RC channel) 4. Private island (full region) with 99% scripts run (main channel) I have not yet tested it on a Homestead The idea however is to lay to rest some fears that have been expressed about messages being lost or delayed in laggy regions. There are three prims, a controller and two listeners. The controller sends an incremented number at an interval to a pair of listeners using llRegionSay and llSay on two channels, and listens for a reply echoing back that same number. If one of both replies do not arrive within a reasonable time a fail is recorded, or if the timely received message is not the same number. Each listener that receives a message first echoes it back, then checks to see if it is one greater than the previous message. If so it records a success, if not it records a missed message. Each prim has hovertext giving the number of success and failures. If the controller records a fail it logs the time and nature of the failure. When the owner touches the prim any such events are chatted out and the list or events emptied. Instructions: Rezz three Prims, name then "Controller", "Listener 1", "Listener 2" Place the controller and Listener 2 close together, less than 20 metres apart. Place Listener 1 further away, perhaps 500 metres upwards vertically, but somewhere that you can get to easily. Drop the script Listener 1 inside Listener 1 // Listener 1 to respond to and use llRegionSay for comms testing key owner; integer expected = 0; // is set to the last number recieved plus 1 for the expected next message integer rsChan; // channel to listen on integer rsHandle; integer missed = 0; // count of skipped message sequences integer key2chan(key ID) { return 0x80000000 | (integer)("0x"+(string)ID); } announce(string message) { llSetText(message, <1.0,1.0,1.0>, 1.0); } default { state_entry() { owner = llGetOwner(); llSetObjectName("Listener 1"); rsChan = key2chan(owner) + 1; rsHandle = llListen(rsChan, "Controller", "", ""); announce("Listening");; } listen(integer ch, string name, key id, string msg) { integer msgVal = (integer) msg; llRegionSay(rsChan, msg); // echo it if( msgVal == -1) // reset counters { expected = 0; missed = 0; } else { if( msgVal != expected) missed += 1; expected = msgVal + 1; } announce("Expecting " + (string) expected + "\nMissed " + (string) missed); } } Drop the script Listener 2 inside Listener 2. // Listener 2 to respond to and use llSay for comms testing key owner; integer expected = 0; // is set to the last number recieved plus 1 for the expected next message integer sChan; // channel to listen on integer sHandle; integer missed = 0; // count of skipped message sequences integer key2chan(key ID) { return 0x80000000 | (integer)("0x"+(string)ID); } announce( string message) { llSetText(message, <1.0,1.0,1.0>, 1.0); } default { state_entry() { owner = llGetOwner(); llSetObjectName("Listener 2"); sChan = key2chan(owner) - 1; sHandle = llListen(sChan, "Controller", "", ""); announce("Listening"); } listen(integer ch, string name, key id, string msg) { integer msgVal = (integer) msg; llSay(sChan, msg); // echo it if( msgVal == -1) // reset counters { expected = 0; missed = 0; } else { if( msgVal != expected) missed += 1; expected = msgVal + 1; } announce("Expecting " + (string) expected + "\nMissed " + (string) missed); } } Drop the script Controller inside the controller, which should commence once it has heard from the two listeners. // controller for region comms tests key owner; integer rsChan; // channel for llRegionSay integer rsHandle; integer sChan; // channel for llSay integer sHandle; integer counter; // sequential integer to be sent as test message, doubles as number of test attempts integer rsFails = 0; // RegionsSay incorrect reply integer sFails = 0; // llSay incorrect reply integer timeouts = 0; // nothing heard before fast timeout float interval = 13.0; // seconds between each transmission float timeout = 0.04; '// seconds to allow for reply, approx 2 frames string action; string results; integer reply1; // look for both having replied before sending a new message integer reply2; list reports = []; // Convert to human-readable HH:MM:SS format string clock_time() { integer now = (integer)llGetWallclock(); integer seconds = now % 60; integer minutes = (now / 60) % 60; integer hours = now / 3600; // reset newday at 23:00 hours so that at midnight the day advances return llGetSubString("0" + (string)hours, -2, -1) + ":" + llGetSubString("0" + (string)minutes, -2, -1) + ":" + llGetSubString("0" + (string)seconds, -2, -1); } report(string what) { string details = clock_time() + " " + what; reports += [details]; } integer key2chan(key ID) { return 0x80000000 | (integer)("0x"+(string)ID); } announce(string message) { llSetText(message, <1.0,1.0,1.0>, 1.0); } default { state_entry() { owner = llGetOwner(); llSetObjectName("Controller"); llSetTimerEvent(0.0); rsChan = key2chan(owner) + 1; rsHandle = llListen(rsChan, "Listener 1", "", ""); sChan = key2chan(owner) - 1; sHandle = llListen(sChan, "Listener 2", "", ""); counter = 0; reply1 = -2; // on a reset we will be getting back -1 reply2 = -2; action = "starting"; // send -1 to both listeners with no timeouts announce(action); llRegionSay(rsChan,(string) -1); llSay(sChan, (string) -1); } listen(integer ch, string name, key id, string msg) { llSetTimerEvent(0.0); if( ch == rsChan) reply1 = (integer) msg; else if( ch == sChan) reply2 = (integer) msg; if( action == "starting") { if( reply1 == reply2) { action = "sending"; counter = 0; results = ""; llSetTimerEvent(1.0); // send the first message ASAP } } else if( action == "waiting") { if( ch == rsChan) { if( counter != reply1) { ++rsFails; report("RegionSay reply mismatrch"); } } else if( ch == sChan) { if( counter != reply2) { ++sFails; report("Say reply mismatch"); } } if( reply1 > -1 && reply2 > -1) { results = "Sent " + (string) counter + "\n RegionSay Fails " + (string) rsFails + "\n Say Fails " + (string) sFails + "\n Timeouts " + (string) timeouts; announce(results); ++counter; action = "sending"; llSetTimerEvent(interval); reply1 = -1; reply2 = -1; } } } touch_end(integer touches) { key toucher = llDetectedKey(touches - 1); if( toucher == owner ) { integer iiMax = llGetListLength(reports); if( iiMax == 0) { llOwnerSay("Nothing to report"); } else { integer ii = 0; for(; ii < iiMax; ii++) { llOwnerSay(llList2String(reports, ii) ); } reports = []; } } } timer() { llSetTimerEvent(0.0); if( action == "sending") { llRegionSay(rsChan,(string) counter); llSay(sChan,(string) counter); action = "waiting"; llSetTimerEvent(timeout); } else if(action == "waiting") { announce("Timed out!"); report("Reply timeout"); ++timeouts; ++counter; action = "sending"; llSetTimerEvent(interval); } } } If you need to restart the monitoring, simply reset the controller script. Tight timer loops Kelly Linden stated in 2011 that there was no point in a timer resolution smaller then 0.02 seconds, and that for practical purposes 0.1 seconds was about the finest resolution. However, my experiments have shown that 0.04 is possible even in quite a busy script, and for the light loadings in the controller script 0.04 seems Ok.
  15. I believe Builders Brewery run scripting courses from time to time.
  16. In the attach event, test for the key attach value, if it is NULL_KEY, (meaning it has just been detached or isn't worn but rezzed) use llSetTimerEvent(0.0);
  17. Qie posted something about this a while back, hopefully his memory will be better than mine regarding the detail.
  18. I think with the functions already given in the jira it is going to be possible to have a list on which one can do some matrix transforms, such as list [A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D1,D2,D3,D4] Via the vertical slices in four successive takes going to list2 [A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3,A4,B4,C4,D4]
  19. I can see it giving the ability to treat a list as a classic square array or a spreadsheet. I'm intrigued to know why it might be given priority, what circumstances have arisen or will have arisen that require this extra functionality? Added my ideas to the Jira anyway
  20. Set "select by surrounding" and "select only my objects", then edit a selection box around the area, and your own prims will show up highlighted. If you're using a TPV with object area search facility you can also search for your name in the owner field, and there are usually options to return the items that are shown in the resulting list
  21. Look in the LS wiki for llSetLinkTexture, also look at llSetLinkPrimitiveParamsFast(ii, [PRIM_TeXTURE, face...]) for how to use offsets and repeats and angles to put parts of a texture onto different faces
×
×
  • Create New...