Unit CastleTimeUtils

DescriptionUsesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

Time utilities.

Uses

  • BaseUnix
  • Unix
  • Dl
  • SysUtils
  • Math

Overview

Classes, Interfaces, Objects and Records

Name Description
Class TFramesPerSecond Utility to measure frames per second, independent of actual rendering API.

Functions and Procedures

function TimeTickSecondLater(firstTime, secondTime, timeDelay: TMilisecTime): boolean;
function TimeTickDiff(firstTime, secondTime: TMilisecTime): TMilisecTime;
function MilisecTimesAdd(t1, t2: TMilisecTime): TMilisecTime;
function MilisecTimesSubtract(t1, t2: TMilisecTime): TMilisecTime;
function GetTickCount: TMilisecTime;
function DateTimeToAtStr(DateTime: TDateTime): string;
function ProcessTimerNow: TProcessTimerResult;
function ProcessTimerDiff(a, b: TProcessTimerResult): TProcessTimerResult;
procedure ProcessTimerBegin;
function ProcessTimerEnd: Double;
function Timer: TTimerResult;

Types

TFloatTime = Double;
TMilisecTime = LongWord;
TProcessTimerResult = clock_t ;
TTimerResult = Int64;
TTimerFrequency = LongWord;

Constants

OldestTime = -MaxDouble;
MinDateTime: TDateTime = MinDouble;
ProcessTimersPerSec = 128 ;
TimerFrequency: TTimerFrequency = 1000000;

Description

Functions and Procedures

function TimeTickSecondLater(firstTime, secondTime, timeDelay: TMilisecTime): boolean;

Check is SecondTime larger by at least TimeDelay than FirstTime.

Naive implementation of this would be SecondTime - FirstTime >= TimeDelay.

FirstTime and SecondTime are milisecond times from some initial point. For example, they may be taken from a function like GetTickCount. Such time may "wrap" (TMilisecTime, just a LongWord, is limited). This function checks these times intelligently, using the assumption that the SecondTime is always "later" than the FirstTime, and only having to check if it's later by at least TimeDelay.

Always TimeTickSecond(X, X, 0) = True. that is, when both times are actually equal, it's correctly "later by zero miliseconds".

function TimeTickDiff(firstTime, secondTime: TMilisecTime): TMilisecTime;

Difference in times between SecondTime and FirstTime.

Naive implementation would be just SecondTime - FirstTime, this function does a little better: takes into account that times may "wrap" (see TimeTickSecondLater), and uses the assumption that the SecondTime for sure "later", to calculate hopefully correct difference.

function MilisecTimesAdd(t1, t2: TMilisecTime): TMilisecTime;

Simply add and subtract two TMilisecTime values.

These don't care if TMilisecTime is a point in time, or time interval. They simply add / subtract values. It's your problem if adding / subtracting them is sensible.

Range checking is ignored. In particular, this means that if you subtract smaller value from larger value, the result will be like the time "wrapped" in between (since TMilisecTime range is limited).

function MilisecTimesSubtract(t1, t2: TMilisecTime): TMilisecTime;
 
function GetTickCount: TMilisecTime;

Get current time, in miliseconds. Such time wraps after ˜49 days.

Under Windows, this is just a WinAPI GetTickCount call, it's a time since system start.

Under Unix, similar result is obtained by gettimeofday call, and cutting off some digits. So under Unix it's not a time since system start, but since some arbitrary point.

function DateTimeToAtStr(DateTime: TDateTime): string;

Convert DateTime to string in the form "date at time".

function ProcessTimerNow: TProcessTimerResult;

Current value of process (CPU) timer. This can be used to measure how much CPU time your process used. Although note that on Windows there's no way to measure CPU time, so this simply measures real time that passed. Only under Unix this uses clock() call designed to actually measure CPU time.

You take two ProcessTimerNow values, subtract them with ProcessTimerDiff, this is the time passed — in resolution ProcessTimersPerSec.

For simple usage, see ProcessTimerBegin and ProcessTimerEnd.

function ProcessTimerDiff(a, b: TProcessTimerResult): TProcessTimerResult;

Subtract two process (CPU) timer results, obtained from ProcessTimerNow.

Although it may just subtract two values, it may also do something more. For example, if timer resolution is only miliseconds, and it may wrap (just like TMilisecTime), then we may subtract values intelligently, taking into account that time could wrap (see TimeTickDiff).

procedure ProcessTimerBegin;

Simple measure of process CPU time. Call ProcessTimerBegin at the beginning of your calculation, call ProcessTimerEnd at the end. ProcessTimerEnd returns a float number, with 1.0 being one second.

Note that using this is unsafe in libraries, not to mention multi-threaded programs (it's not "reentrant") — you risk that some other code called ProcessTimerBegin, and your ProcessTimerEnd doesn't measure what you think. So in general units, do not use this, use ProcessTimerNow and ProcessTimerDiff instead. In final programs (when you have full control) using these is comfortable and Ok.

function ProcessTimerEnd: Double;
 
function Timer: TTimerResult;

Measure passed real time. Note "real time" — as opposed to e.g. process time (for this, see ProcessTimerNow and friends above). Call Timer twice, calculate the difference, and you get time passed — with frequency in TimerFrequency.

TimerFrequency says how much Timer gets larger during 1 second (how many "ticks" are during one second).

Implementation details: Under Unix this uses gettimeofday. Under Windows this uses QueryPerformanceCounter/Frequency, unless WinAPI "performance timer" is not available, then standard GetTickCount is used.

Types

TFloatTime = Double;

Time in seconds. This is used throughout my engine to represent time as a floating-point value with good accuracy in seconds. In particular, for VRML / X3D time-dependent nodes.

Implementation notes, about the choice of precision:

  • "Single" precision is sometimes not enough for this. Proof: open rotate.kanim (from demo_models). Change "on display" time pass to 1000, wait a couple seconds (world time will reach a couple of thousands), change "on display" time pass back to 1. Result: with time as Single, animation becomes jagged. Reason: the precision loss of Single time, and the fact that Render is not called all the time (because AutoRedisplay is false, and model is in Examine mode and is still (not rotating)), so incrementation steps of AnimationTime are very very small.

    Setting AutoRedisplay to true workarounds the problem too, but that's 1. unacceptable to eat 100% CPU without a reason for utility like view3dscene 2. that's asking for trouble, after all even with AutoRedisplay = true the precision loss is there, it's just not noticeable... using better precision feels much safer.

  • For X3D, SFTime has "Double" precision. Also "The Castle" and "The Rift" prooved it's enough in practice.

    I could have choosen Extended here, but for X3D sake (to avoid unnecessary floating-point convertions all around), let's stick to Double for now.

TMilisecTime = LongWord;
 
TProcessTimerResult = clock_t ;
 
TTimerResult = Int64;
 
TTimerFrequency = LongWord;
 

Constants

OldestTime = -MaxDouble;
 
MinDateTime: TDateTime = MinDouble;
 
ProcessTimersPerSec = 128 ;

Resolution of process timer.

See also
ProcessTimerNow
Current value of process (CPU) timer.
TimerFrequency: TTimerFrequency = 1000000;
 

Generated by PasDoc 0.13.0 on 2014-08-30 12:10:41