Difference between revisions of "Talk:Code Racer"

From Second Life Wiki
Jump to navigation Jump to search
m (start towards running indefinitely many versions of code)
m (towards running indefinitely many versions of code -- this version compiles, but doesn't yet run correctly)
Line 12: Line 12:


<pre>
<pre>
// Race a few version of code in dilated time as measured by llGetTime.
// http://wiki.secondlife.com/wiki/Code_Racer
// http://wiki.secondlife.com/wiki/Code_Racer


// List every runnable version.
// List every runnable version.


list runners = [0, 1];
list theRunners = [0, 1, 2];
 
// Count runnable versions.
 
integer theRunnable;


// Count votes to place.
// Count votes to place.


list votes;
list theVotes;


// Sum the run times observed.
// Sum the run times observed.


list sums;
list theSums;


// Race a few versions of code in dilated time as measured by llGetTime.
// Count the races that ran without time running backwards.
 
integer theAverageable;
 
// Race no code alongside the other code in order to measure overhead.


runner0()
runner0()
{
{
}
}
// Race a few versions of code.


runner1()
runner1()
Line 53: Line 64:


// Run the chosen runner once.
// Run the chosen runner once.
// Run thru an equal time choosing between runners, no matter which runner runs.
// Run thru an equal time while choosing any runner.


run(integer runner)
run(integer runner)
Line 69: Line 80:
startup()
startup()
{
{
        llOwnerSay("");
    llOwnerSay("");
 
    llOwnerSay("Click Running = No to stop this script after you've seen enough ...");
        llOwnerSay("Click Running = No to stop this script after you've seen enough ...");
    llOwnerSay(llGetTimestamp());
        llOwnerSay(llGetTimestamp());
}
}


Line 88: Line 98:


// Race the runners and return the times when each ran.
// Race the runners and return the times when each ran.
// Run in llGetTime dilated time or in getTime calendar time.


list eachRunnerRun()
list eachRunnerRun()
{
{
     list befores = [];
     list befores = [];
     integer runnable = llGetListLength(runners) + 1;
     integer runnablePlus = theRunnable + 1;
     integer running;
     integer running;
     for (running = 0; running < runnable; ++running) //
     for (running = 0; running < runnablePlus; ++running)
     {
     {
        integer running = llList2Integer(theRunners, running);
         befores += llGetTime();
         befores += llGetTime();
         integer runner = llList2Integer(runners, running);
         run(running);
        run(runner);
     }
     }
     return befores;
     return befores;
Line 108: Line 119:
list getRuntimesElseNone(list befores)
list getRuntimesElseNone(list befores)
{
{
     integer runnable = llGetListLength(befores) + 1;
     list runtimes = [];
    integer running;
     float before = llList2Float(befores, 0);
     float before = llList2Float(befores, 0);
     for (running = 1; running < runnable; ++running)
    integer timing;
     for (timing = 0; timing < theRunnable; ++timing)
     {
     {
         float after = llList2Float(befores, running);
         float after = llList2Float(befores, timing + 1);
         float runtime = after - before;
         float runtime = after - before;
         if (runtime < 0) return [];
         if (runtime < 0.0) return [];
         runtimes += runtime;
         runtimes += runtime;
        before = after;
     }
     }
     return runtimes;
     return runtimes;
}
}


// Race the runners and return the times when each ran.
// 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.


raceRunners()
runRace()
{
{
    // Race the runners once.
     list runtimes = getRuntimesElseNone(eachRunnerRun());
     list runtimes = getRuntimesElseNone(eachRunnerRun());
    list sorted = llListSort(runtimes, 1, TRUE);
    ...


...
    // 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)
    {
        float runtime = llList2Float(runtimes, adding);
        theSums = addFloat(theSums, adding, 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 = (adding * 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()
{
 
    // Consider each place.
 
    llOwnerSay(llDumpList2String(theSums, ", "));
    llOwnerSay(llDumpList2String(theVotes, ", "));
    integer placing;
    for (placing = 0; placing < theRunnable; ++placing)
    {
        list votes = llList2ListStrided(theVotes, placing, -1, theRunnable);
        llOwnerSay(llDumpList2String(votes, ", "));
        integer winner = llList2Integer(llListSort(votes, 1, TRUE), -1);
 
        // Find the winner (or the winners) of that place.
 
        integer running;
        for (running = 0; running < theRunnable; ++running)
        {
            integer vote4place = llList2Integer(votes, running);
            if (vote4place == winner)
            {
 
                // Describe a winner.
 
                float summed = llList2Float(theSums, running);
                float average = summed / theAverageable;
 
                llOwnerSay(
                    (string) vote4place + " votes to place for the ~" +
                    (string) average + " ms runs of version " + (string) running
                );
            }
        }
    }
}
 
// Run a few bursts of races at each scale, for indefinitely increasing scale.
 
runRaceRepeatedly()
{
    integer scaleable = 10;
    while (TRUE)
    {
        integer repeating;
        for (repeating = 0; repeating < 3; ++repeating)
        {
            zeroBurst();
 
            integer scaling;
            for (scaling = 0; scaling < scaleable; ++scaling)
            {
                runRace();
            }
 
            llOwnerSay("");
            reportBurst();
            llOwnerSay(llGetTimestamp());
 
            theRunners = llList2List(theRunners, -1, -1) + llList2List(theRunners, 0, -2);
        }
 
        scaleable *= 10;
    }
}
 
// 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>
</pre>

Revision as of 20:54, 22 October 2007

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. -- Ppaatt Lynagh 18:08, 16 October 2007 (PDT)

Ha! Those new insights were half-grounded in nonsense! Half the win counts were wrong, courtesy one typo. Fixed now, maybe. -- 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. -- 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. -- 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. -- 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. -- Ppaatt Lynagh 16:02, 22 October 2007 (PDT)

// Race a few version of code in dilated 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()
{
}

runner2()
{
}

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());

    // 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)
    {
        float runtime = llList2Float(runtimes, adding);
        theSums = addFloat(theSums, adding, 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 = (adding * 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()
{

    // Consider each place.

    llOwnerSay(llDumpList2String(theSums, ", "));
    llOwnerSay(llDumpList2String(theVotes, ", "));
    integer placing;
    for (placing = 0; placing < theRunnable; ++placing)
    {
        list votes = llList2ListStrided(theVotes, placing, -1, theRunnable);
        llOwnerSay(llDumpList2String(votes, ", "));
        integer winner = llList2Integer(llListSort(votes, 1, TRUE), -1);

        // Find the winner (or the winners) of that place.

        integer running;
        for (running = 0; running < theRunnable; ++running)
        {
            integer vote4place = llList2Integer(votes, running); 
            if (vote4place == winner)
            {

                // Describe a winner.

                float summed = llList2Float(theSums, running);
                float average = summed / theAverageable;

                llOwnerSay(
                    (string) vote4place + " votes to place for the ~" +
                    (string) average + " ms runs of version " + (string) running
                );
            }
        }
    }
}

// Run a few bursts of races at each scale, for indefinitely increasing scale.

runRaceRepeatedly()
{
    integer scaleable = 10;
    while (TRUE)
    {
        integer repeating;
        for (repeating = 0; repeating < 3; ++repeating)
        {
            zeroBurst();

            integer scaling;
            for (scaling = 0; scaling < scaleable; ++scaling)
            {
                runRace();
            }

            llOwnerSay("");
            reportBurst();
            llOwnerSay(llGetTimestamp());

            theRunners = llList2List(theRunners, -1, -1) + llList2List(theRunners, 0, -2);
        }

        scaleable *= 10;
    }
}

// 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();
    }
}