Don't click here unless you want to be banned.

LSL Wiki : LibraryPrecisionTime

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl814.us.archive.org

Precision Timer


This is a chunk of code to show you two things.

1) llSetTimerEvent's precision is ridiculously low.
2) You can easily improve the precision by setting the timer a bit short and then waiting until your target time.

How do you use this script?

1) If you cut and paste this code into a script and put it into a box, it will send periodic messages displaying how far off llSetTimerEvent is from where it should be, in seconds.
2) If you change the first line to "integer useprectimer = 1;" it will send periodic messages displaying how close a precision timer can get.
3) If you read the timer event at the bottom, and precTimer() function at the top, they demonstrate the precision timer.

//--------------------------
// precision timer
//--------------------------

integer useprectimer = 0; // 0 for settimerevent, 1 for precision timer
float timetotest = 0.2; // how fast should the timer run?


// these two functions set timers with and without precision, and mark the desired time target
vector timeTarget;
precTimer( float secdiff )
{
    timeTarget = vecTime();
    timeTarget.z += secdiff;
    llSetTimerEvent(secdiff - 0.05);
}
nonprecTimer( float secdiff )
{
    timeTarget = vecTime();
    timeTarget.z += secdiff;
    llSetTimerEvent(secdiff);
}


// run a report of how well the timer is doing
runReport()
{
        float min;
        float max;
        float avg;
        float total;
        float cur;
        integer i;
        integer len;
        
        llSetTimerEvent(0.0); // try to clear the event queue up a bit, altho reset should do it
        if( useprectimer == 1 ) {
            llOwnerSay("Precision timer stats:");
        } else {
            llOwnerSay("llSetTimerEvent stats:");
        }
        
        len = llGetListLength(lDiffs);
        total = 0.0;
        min = 1.0;
        max = 0.0;
        for( i = 0; i < len; i++ ) {
            cur = llList2Float(lDiffs, i);
            total += cur;
            if( cur < min ) {
                min = cur;
            }
            if( cur > max ) {
                max = cur;
            }
        }
        avg = total/(float)len;
        llOwnerSay("Total drift: " + (string)total + ", timers run: " + (string)len);
        llOwnerSay("Avg   drift: " + (string)avg);
        llOwnerSay("Min   drift: " + (string)min);
        llOwnerSay("Max   drift: " + (string)max);
        llOwnerSay("Starting another run.");
        llResetScript();
}

//--------------------------
// time utility functions
//--------------------------
vector vecTime()
{
    vector tsp;
    list tsv;

    tsv = llParseString2List( llGetTimestamp(), ["T", ":", "Z"], [] );

    tsp.x = llList2Integer(tsv, 1) - 8;
    if( tsp.x < 0 ) {
        tsp.x += 24;
    }
    tsp.y = llList2Integer(tsv, 2);
    tsp.z = llList2Float(tsv, 3);

    return tsp;
}

vector fixTime( vector inTime )
{
    vector oTime = inTime;
    
    while( oTime.z >= 60.0 ) {
        oTime.z -= 60.0;
        oTime.y++;
    }
    while( oTime.y >= 60.0 ) {
        oTime.y -= 60.0;
        oTime.z++;
    }
    return oTime;
}

float timeDiffNow( vector vTarget )
{
    vector vTime = vecTime();
    return (vTarget.x - vTime.x)*3600.0 + (vTarget.y - vTime.y) * 60.0 + (vTarget.z - vTime.z);
}

// included for reference:
float timeDiff( vector vMore, vector vLess )
{
    float hours = vMore.x - vLess.x;
    float minutes = vMore.y - vLess.y;
    float seconds = vMore.z - vLess.z;
    
    float tics = hours * 3600.0 + minutes * 60.0 + seconds;
    
//    llOwnerSay("Diff between " + (string)vMore + " and " + (string)vLess );  
//    llOwnerSay("Diff returned approx. " + (string)( (integer)tics ) + " seconds.");
    return tics;
}


//--------------------------
// PrecTimer script: report the drift in llSetTimerEvent, and show an easy way to fix it:
//--------------------------
list lDiffs; // used to store statistics

default
{
    state_entry()
    {
        lDiffs = [];
        if( useprectimer == 1 ) {
            precTimer(timetotest);
        } else {
            nonprecTimer(timetotest);
        }
    }
    
    timer()
    {
        float timeleft = timeDiffNow(timeTarget);   // ETA to target time

        if( useprectimer == 1 ) {
            //Begin very simple precision countdown:
            llResetTime();
            while( (timeleft -= llGetAndResetTime()) > 0.01 );
            //Reset the target of the precision timer:
            precTimer(timetotest);
        } else {
            //Reset the target of the nonprecision timer:
            timeTarget.z += timetotest;
        }
        lDiffs = (lDiffs=[]) + lDiffs + [llFabs(timeleft)];
        if( llGetListLength(lDiffs) > 100 ) {
            runReport();
        }
    }
    
    touch_start(integer nd)
    {
        runReport();
    }
}

Example output:

[15:57] Object: Precision timer stats:
[15:57] Object: Total drift: 0.110259, timers run: 101
[15:57] Object: Avg drift: 0.001092
[15:57] Object: Min drift: 0.000000
[15:57] Object: Max drift: 0.080150

[15:59] Object: llSetTimerEvent stats:
[15:59] Object: Total drift: 2.131889, timers run: 101
[15:59] Object: Avg drift: 0.021108
[15:59] Object: Min drift: 0.000084
[15:59] Object: Max drift: 0.101887



That's right... which do you want, a drift of 1/50th of a second, or of 1/1000th of a second? Yes. Use a precision timer.

ScriptLibrary
Comments [Hide comments/form]
Attach a comment to this page: