Difference between revisions of "Talk:Code Racer"

From Second Life Wiki
Jump to navigation Jump to search
((1) yes report ms not s (2) begin with a 2:1:0 ratio between examples rather than 1000:100:0)
m (archive the talk that developed the code to run a number of versions of code against one another, not just two)
Line 1: Line 1:
I've gone ahead and created this [[Code Racer]] page -- I think the approach is complete enough to be worth discussing - ''e.g.'', I get insight into [[llGetSubString]] snippets. However, something fiddly is still wrong with the implementation, I guess. As you can see in the sample results, often the sums of wins exceed the scale. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 18:08, 16 October 2007 (PDT)
This page intentionally left mostly blank.
 
Ha! Those new insights were half-grounded in nonsense! Half the win counts were wrong, courtesy one typo. Fixed now, maybe. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 21:18, 16 October 2007 (PDT)
 
[[Talk:Hex]] suggests that we should tweak this instrument to call [[llGetTime]] rather than [[llGetTimestamp]], in order to more accurately measure elapsed run time when time dilates. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 21:41, 19 October 2007 (PDT)
 
Change complete! Runs wonderfully faster too. The run time cost of the harness has dropped below two milliseconds. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 07:32, 20 October 2007 (PDT)
 
This should run indefinitely many versions of code against each other in parallel, so that we can complete an analysis like comparing all the too many versions of code at [[hex]] without attending the experiment. Also the last version of code could be an empty block of code, to measure the overhead of the harness, to throw it out, like the [[Efficiency Tester]] does. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 13:14, 22 October 2007 (PDT)
 
Below is a start towards running indefinitely many versions of code, without bias in favour of any one. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 16:02, 22 October 2007 (PDT)
 
<pre>
// Race a few version of code in dilated script time as measured by llGetTime.
// http://wiki.secondlife.com/wiki/Code_Racer
 
// List every runnable version.
 
list theRunners = [0, 1, 2];
 
// Count runnable versions.
 
integer theRunnable;
 
// Count votes to place.
 
list theVotes;
 
// Sum the run times observed.
 
list theSums;
 
// Count the races that ran without time running backwards.
 
integer theAverageable;
 
// Race no code alongside the other code in order to measure overhead.
 
runner0()
{
}
 
// Race a few versions of code.
 
runner1()
{
    integer spinning;
    for (spinning = 0; spinning < 25; ++spinning)
        ;
}
 
runner2()
{
    integer spinning;
    for (spinning = 0; spinning < 50; ++spinning)
        ;
}
 
runner3()
{
}
 
runner4()
{
}
 
runner5()
{
}
 
// Run the chosen runner once.
// Run thru an equal time while choosing any runner.
 
run(integer runner)
{
    if (runner == 0) { runner0(); }
    if (runner == 1) { runner1(); }
    if (runner == 2) { runner2(); }
    if (runner == 3) { runner3(); }
    if (runner == 4) { runner4(); }
    if (runner == 5) { runner5(); }
}
 
// Start up.
 
startup()
{
    llOwnerSay("");
    llOwnerSay("Click Running = No to stop this script after you've seen enough ...");
    llOwnerSay(llGetTimestamp());
}
 
// Measure the race in calendar time elapsed since the minute began,
// if called in place of llGetTime.
//
// Note: "YYYY-MM-DDThh:mm:ss.ff..fZ" = llGetTimestamp();
// Note: 17 = 0 + llStringLength("YYYY-MM-DDThh:mm:")
// Note: -2 = -1 - llStringLength("Z")
 
float getTime()
{
    return (float) llGetSubString(llGetTimestamp(), 17, -2); // "ss.ff..f"
}
 
// Race the runners and return the times when each ran.
// Run in llGetTime dilated time or in getTime calendar time.
 
list eachRunnerRun()
{
    list befores = [];
    integer runnablePlus = theRunnable + 1;
    integer running;
    for (running = 0; running < runnablePlus; ++running)
    {
        integer running = llList2Integer(theRunners, running);
        befores += llGetTime();
        run(running);
    }
    return befores;
}
 
// Return elapsed run time per runner,
// else return [] if time ran backwards.
 
list getRuntimesElseNone(list befores)
{
    list runtimes = [];
    float before = llList2Float(befores, 0);
    integer timing;
    for (timing = 0; timing < theRunnable; ++timing)
    {
        float after = llList2Float(befores, timing + 1);
        float runtime = after - before;
        if (runtime < 0.0) return [];
        runtimes += runtime;
        before = after;
    }
    return runtimes;
}
 
// Add to a listed float.
 
list addFloat(list sums, integer index, float addition)
{
    list results = [];
    integer summable = llGetListLength(sums);
    integer summing;
    for (summing = 0; summing < summable; ++summing)
    {
        float result = llList2Float(sums, summing);
        if (index == summing)
        {
            result += addition;
        }
        results += result;
    }
    return results;
}
 
// Add to a listed integer.
 
list addInteger(list sums, integer index, integer addition)
{
    list results = [];
    integer summable = llGetListLength(sums);
    integer summing;
    for (summing = 0; summing < summable; ++summing)
    {
        integer result = llList2Integer(sums, summing);
        if (index == summing)
        {
            result += addition;
        }
        results += result;
    }
    return results;
}
 
// Race the runners once, vote to place, and sum run time per runner.
 
runRace()
{
 
    // Race the runners once.
 
    list runtimes = getRuntimesElseNone(eachRunnerRun());
//  llOwnerSay("[" + llDumpList2String(runtimes, ", ") + "] == runtimes");
 
    // Sort the runtimes into places.
 
    list places = llListSort(runtimes, 1, TRUE); // sort least to most
    integer placeable = llGetListLength(places); // 0 or theRunnable
 
    // Sum run time per runner.
 
    integer adding;
    for (adding = 0; adding < placeable; ++adding)
    {
        integer running = llList2Integer(theRunners, adding);
        float runtime = llList2Float(runtimes, adding);
        theSums = addFloat(theSums, running, runtime);
        ++theAverageable;
 
        // Vote to place at each equal runtime.
 
        integer placing;
        for (placing = 0; placing < placeable; ++placing)
        {
            float placed = llList2Float(places, placing);
            if (runtime == placed)
            {
                integer flat = (running * placeable) + placing;
                theVotes = addInteger(theVotes, flat, 1);
            }
        }
    }
}
 
// Start up a burst of races.
 
zeroBurst()
{
    theSums = theVotes = [];
    theRunnable = llGetListLength(theRunners);
    integer placing;
    for (placing = 0; placing < theRunnable; ++placing)
    {
        theSums += 0.0;
        integer running;
        for (running = 0; running < theRunnable; ++running)
        {
            theVotes += 0;
        }
    }
}
 
// Report a burst of races.
 
reportBurst(integer scaling)
{
 
    // Consider each place.
 
    integer placing;
    for (placing = 0; placing < theRunnable; ++placing)
    {
        list votes = llList2ListStrided(llList2List(theVotes, placing, -1), 0, -1, theRunnable);
        integer winner = llList2Integer(llListSort(votes, 1, TRUE), -1);
 
        // Find the winner (or the winners) of that place.
 
        integer running;
        for (running = 1; running < theRunnable; ++running)
        {
            integer vote4place = llList2Integer(votes, running);
            if (vote4place == winner)
            {
 
                // Describe a winner.
 
                float summed = llList2Float(theSums, running) - llList2Float(theSums, 0);
                float average = 1000.0 * (summed / theAverageable);
 
                llOwnerSay("~" +
                    (string) average + " ms elapsed in version " + (string) running +
                    " to place at " + (string) placing +
                    " by " + (string) vote4place + " of " + (string) scaling + " votes"
                );
            }
        }
    }
}
 
// Run a few bursts of races at each scale, for indefinitely increasing scale.
 
runRaceRepeatedly()
{
    integer scaleable = 10;
    integer repeatable = 1; // don't bother to repeat the first burst
    while (TRUE)
    {
        integer repeating;
        for (repeating = 0; repeating < repeatable; ++repeating)
        {
            zeroBurst();
 
            integer scaling;
            for (scaling = 0; scaling < scaleable; ++scaling)
            {
                runRace();
                theRunners = llList2List(theRunners, -1, -1) + llList2List(theRunners, 0, -2);
            }
 
            llOwnerSay("");
            reportBurst(scaling);
            llOwnerSay(llGetTimestamp());
        }
       
        scaleable *= 10;
        repeatable = 3; // repeat most bursts several times
    }
}
 
// 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();
        runRaceRepeatedly();
    }
}
</pre>

Revision as of 19:48, 24 October 2007

This page intentionally left mostly blank.