Efficiency Tester

From Second Life Wiki
Revision as of 11:38, 8 February 2008 by Xaviar Czervik (talk | contribs) (Put code in <lsl> instead of <pre>)
Jump to navigation Jump to search

Q1: Want to see how small some code compiles?

A: See the Code Sizer harness for llGetFreeMemory.

Q2: Want to discover quickly if a change to code makes the code run faster?

A: See the Code Racer harness for llGetTimestamp.

Q3: Want to see approximately how fast some code runs?

A: Run your code inside code like this example to call your code time and again to measure the consequent change in llGetTimestamp.

Sample Results:

15249 free bytes of code at default.state_entry
0.177314+-??% ms may have elapsed on average in each of
10000 trials of running the code in the loop
0.176341+-??% ms may have elapsed on average in each of
10000 trials of running the code in the loop
0.201925+-??% ms may have elapsed on average in each of
10000 trials of running the code in the loop

Code:

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

// (16384 - (15267 - 18)) was the well-known byte code size of this llGetTime/ llGetTimestamp harness

// Measure the race instead // in calendar milliseconds elapsed since the day began, // if called in place of llGetTime.

integer getTime() // 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

}

default {

   state_entry()
   {
       // always measure how small, not only how fast
       llOwnerSay((string) llGetFreeMemory() + " free bytes of code at default.state_entry");
       // always take more than one measurement
       integer repeateds;
       for (repeateds = 0; repeateds < 3; ++repeateds)
       {
           // declare test variables
           float counter;
           // declare framework variables
           float i = 0;
           float j = 0;
           integer max = 10000; // 2ms of work takes 20 seconds to repeat 10,000 times, plus overhead
           // begin
           float t0 = llGetTime();
           // loop to measure elapsed time to run sample code
           do
           {
             // test once or more
             counter += 1; // 18 bytes is the well-known byte code size of this sourceline
     
           } while (++i < max);
           float t1 = llGetTime();
           // loop to measure elapsed time to run no code
           do ; while (++j < max);
           float t2 = llGetTime();
           // complain if time ran backwards
           
           if (!((t0 <= t1) && (t1 <= t2)))
           {
               llOwnerSay("MEANINGLESS RESULT -- SIMULATED TIME RAN BACKWARDS -- TRY AGAIN");
           }
           
           // report average time elapsed per run
           float elapsedms = 1000.0 * (((t1 - t0) - (t2 - t1)) / max);
           llOwnerSay((string) elapsedms + "+-??% ms may have elapsed on average in each of");
           llOwnerSay((string) max + " trials of running the code in the loop");
       }
   }

} </lsl>

Launched by Xaviar Czervik, then modified by Strife Onizuka, then further edited as the history of this article shows.

Try the empty test of deleting the { counter += 1; } source line to see the astonishing inaccuracy of this instrument. The time cost of no code, as measured here, isn't always zero!

See the LSL Script Efficiency article for a less brief discussion. Please understand, we don't mean to be arguing for many different ways to measure the costs of code. Here we do mean to be building a consensus on best practices, in one considerately short article constructed from a neutral point of view.