Difference between revisions of "Code Racer"

From Second Life Wiki
Jump to navigation Jump to search
(→‎Code: fix the stuttered line of code that was making wins for 0 and 1 nearly match always)
m (→‎Sample Results: 1000 runs now producing reasonable results for both averages and wins)
Line 11: Line 11:
<pre>
<pre>


14248 == llGetFreeMemory at default state entry
14255 == llGetFreeMemory at default state entry
Click No = Running to stop this script after you've seen enough ...
Click No = Running to stop this script after you've seen enough ...
2007-10-16T23:46:18.145790Z
2007-10-17T04:20:16.445974Z


36.081123 ms on average won 4 times for version 1
38.043785 ms on average won 5 times for version 0
45.511818 ms on average won 3 times for version 0
38.680077 ms on average won 6 times for version 1
2007-10-16T23:46:19.798679Z
2007-10-17T04:20:17.800540Z


44.257927 ms on average won 4 times for version 1
31.906128 ms on average won 8 times for version 1
46.619797 ms on average won 3 times for version 0
37.332916 ms on average won 3 times for version 0
2007-10-16T23:46:21.395335Z
2007-10-17T04:20:19.190948Z


39.855003 ms on average won 5 times for version 0
35.953903 ms on average won 7 times for version 0
42.498398 ms on average won 4 times for version 1
37.122345 ms on average won 4 times for version 1
2007-10-16T23:46:22.914732Z
2007-10-17T04:20:20.763496Z


40.442619 ms on average won 47 times for version 1
40.611820 ms on average won 56 times for version 1
40.515079 ms on average won 46 times for version 0
42.019424 ms on average won 45 times for version 0
2007-10-16T23:46:36.554968Z
2007-10-17T04:20:34.070805Z


42.218056 ms on average won 50 times for version 0
39.175758 ms on average won 51 times for version 0
42.840729 ms on average won 49 times for version 1
39.368172 ms on average won 50 times for version 1
2007-10-16T23:46:50.205469Z
2007-10-17T04:20:46.986901Z


38.160728 ms on average won 59 times for version 0
38.788643 ms on average won 54 times for version 0
41.828423 ms on average won 58 times for version 1
41.306263 ms on average won 47 times for version 1
2007-10-16T23:47:03.672896Z
2007-10-17T04:20:59.801368Z


41.160179 ms on average won 491 times for version 1
40.090019 ms on average won 504 times for version 1
41.985397 ms on average won 490 times for version 0
41.344051 ms on average won 497 times for version 0
2007-10-16T23:49:16.900324Z
2007-10-17T04:23:08.844762Z


42.588852 ms on average won 490 times for version 0
39.103428 ms on average won 507 times for version 0
45.594582 ms on average won 489 times for version 1
39.274292 ms on average won 494 times for version 1
2007-10-16T23:51:35.127788Z
2007-10-17T04:25:12.787046Z
 
38.454666 ms on average won 505 times for version 0
38.675617 ms on average won 496 times for version 1
2007-10-17T04:27:15.542923Z
</pre>
</pre>



Revision as of 20:29, 16 October 2007

Introduction

Q: Want to see if one version of code usually runs faster than another?

A: Run your code inside a test harness such as the example code here to race both versions time and again. Along the way, declare the winners, measuring each win by the change in llGetTimestamp.

Sample Results


14255 == llGetFreeMemory at default state entry
Click No = Running to stop this script after you've seen enough ...
2007-10-17T04:20:16.445974Z

38.043785 ms on average won 5 times for version 0
38.680077 ms on average won 6 times for version 1
2007-10-17T04:20:17.800540Z

31.906128 ms on average won 8 times for version 1
37.332916 ms on average won 3 times for version 0
2007-10-17T04:20:19.190948Z

35.953903 ms on average won 7 times for version 0
37.122345 ms on average won 4 times for version 1
2007-10-17T04:20:20.763496Z

40.611820 ms on average won 56 times for version 1
42.019424 ms on average won 45 times for version 0
2007-10-17T04:20:34.070805Z

39.175758 ms on average won 51 times for version 0
39.368172 ms on average won 50 times for version 1
2007-10-17T04:20:46.986901Z

38.788643 ms on average won 54 times for version 0
41.306263 ms on average won 47 times for version 1
2007-10-17T04:20:59.801368Z

40.090019 ms on average won 504 times for version 1
41.344051 ms on average won 497 times for version 0
2007-10-17T04:23:08.844762Z

39.103428 ms on average won 507 times for version 0
39.274292 ms on average won 494 times for version 1
2007-10-17T04:25:12.787046Z

38.454666 ms on average won 505 times for version 0
38.675617 ms on average won 496 times for version 1
2007-10-17T04:27:15.542923Z

Code

// http://wiki.secondlife.com/wiki/Code_Racer

version0()
{
}

version1()
{
}

// Count the wins.

integer wins0;
integer wins1;

// Sum the times.

float tsum0;
float tsum1;

// Start up.

startup()
{
        llOwnerSay("");

        llOwnerSay((string) llGetFreeMemory() +
            " == llGetFreeMemory at default state entry");

        llOwnerSay("Click No = Running to stop this script after you've seen enough ...");
        llOwnerSay(llGetTimestamp());
}

// Count time elapsed since the minute began.

float elapsed()
{
    string chars = llGetTimestamp(); // "YYYY-MM-DDThh:mm:ss.ff..fZ"
    return (float) llGetSubString(chars, 17, -2); // "ss.ff..f"
//  return llGetSubString(chars,
//      llStringLength("YYYY-MM-DDThh:mm:"),
//      -1 - llStringLength("Z"));
}

// Say less time wins, else odd/even wins.

integer chooseWinner(float tv0, float tv1, integer runneds)
{
    if (tv0 < tv1)
    {
        return 0;
    }
    else if (tv1 < tv0)
    {
        return 1;
    }
    else // if (tv0 == tv1) // rare
    {
        return (runneds & 1);
    }
}

// Count the wins and sum the times.

declareWinner(float tv0, float tv1, integer runneds)
{

    // See negative delta time as rollover of 60 seconds per minute.
    
    if (tv0 < 0) { tv0 += 60;}
    if (tv1 < 0) { tv1 += 60;}

    // Count the wins.

    integer winner = chooseWinner(tv0, tv1, runneds);
    wins0 += (1 - winner);
    wins1 += winner;

    // Sum the times.

    tsum0 += tv0;
    tsum1 += tv1;
}

// Run one race between two versions of code.

runRace(integer runneds)
{
    if (runneds & 1)
    {
        float t0 = elapsed();
        version1();
        float t1 = elapsed();
        version0();
        float t2 = elapsed();
        
        declareWinner(t1 - t0, t2 - t1, runneds);
    }
    else
    {
        float t0 = elapsed();
        version0();
        float t1 = elapsed();
        version1();
        float t2 = elapsed();
        
        declareWinner(t2 - t1, t1 - t0, runneds);
    }
}

// Report the result for one version in a burst of races.

reportSpeed(list averages, list wins, integer winningVersion)
{
    llOwnerSay(llList2String(averages, winningVersion) +
        " ms on average won " +
        (string) llList2String(wins, winningVersion) + " times" +
        " for version " + (string) winningVersion);
}

// Report the result of a burst of races.

reportRace(integer scale)
{
    list wins = [wins0, wins1];
    
    list averages = [
        (1000.0 * tsum0) / scale,
        (1000.0 * tsum1) / scale];

    llOwnerSay("");
    integer winningVersion = (tsum1 <= tsum0); // bias to 1
    reportSpeed(averages, wins, winningVersion);
    reportSpeed(averages, wins, 1 - winningVersion);
    llOwnerSay(llGetTimestamp());
}

// Run several bursts of races.

raceRepeatedly(integer scale)
{
        
    // Repeat any measurement at least three times.
     
    integer repeateds;
    for (repeateds = 0; repeateds < 3; ++repeateds)
    {
        
        // Run a burst of races.

        wins0 = wins1 = 0;
        tsum0 = tsum1 = 0.0;
        
        integer runneds;
        for (runneds = 0; runneds < scale; ++runneds)
        {
            runRace(runneds);
        }
        
        // Resolve near ties in favour of lesser average.
        
        wins0 += (tsum0 < tsum1);
        wins1 += (tsum1 < tsum0);
        
        // Report frequently to pacify the human operator.
        
        reportRace(scale);
    }
}

// Race to measure relative run-time cost of multiple versions of code.
// Produce unreasonable answers when the run-time cost measured equals or exceeds 60 seconds.

default
{
    state_entry()
    {
        startup();
        integer scale = 10;
        while (TRUE)
        {
            raceRepeatedly(scale);
            scale *= 10;
        }
    }
}

Discussion

This instrument as presented quickly & accurately measures the zero difference between the two empty fragments of code found inside the functions named version0 and version1. To measure other code, insert the code you want to compare into the version0 and version1 functions.

Alternatives

See the Efficiency Tester article for a very different approach, designed to make you wait three minutes or more to get three maximally accurate measures of run times of six milliseconds or more. That test harness runs one fragment of code at a time, while reducing the run time lost to the test harness as near zero as possible, and not giving you any answer until after 10,000 runs.

This test harness differs greatly. This test harness runs two fragments of code at a time, gives you immediate results and then progressively more accurate results over time, like when you slowly fetch a detailed image from the web. This test harness burns thru hugely much run time, like as much as fifty milliseconds per version raced.

See the LSL Script Efficiency article for much discussion of the Efficiency Tester approach.

Please do try to find deserted places to run such benchmarks and remember to turn them off when you finish! Else naturally you'll be rudely lagging the sim for the other people sharing the sim with you.