[AD] Possible Timer API additions/modifications |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
- To: "Coordination of admins/developers of the game programming library Allegro" <alleg-developers@xxxxxxxxxx>
- Subject: [AD] Possible Timer API additions/modifications
- From: "Ryan Dickie" <goalieca@xxxxxxxxxx>
- Date: Sat, 26 Jan 2008 02:45:13 -0800
Since allegro is a high-level library I thought it might be useful to add some common functionality to the timer API's. In particular it would be useful to have a stopwatch timer and a countdown timer. A stopwatch simply measures time elapsed. The interface provides for pausing, resuming, and resetting. The countdown timer will expire when the time remaining reaches 0. It has a nearly identical interface as the stopwatch. The stopwatch and countdown timers were done using doubles as they were the natural choice. These timers are implemented entirely on top of al_current_time().
I have attached a quick stand-alone prototype (for *nix) which includes a quick test bench for a feel of the interface. I quickly re-implemented al_rest and al_current_time to deal with doubles as well for convenience sake.
--ryan
/**
Ryan Dickie
Jan 25, 2008
TODO:
1) how to error handle?
2) multi-cpu gettimeofday issues? (microseconds off between cores)
should not cause problems for 1ms or higher
3) the gettimeofday is microsecond accurate but context switches/scheduling
give it about 1.5ms accuracy.
In fact, the tickless kernel uses the 1us accuracy of gettimeofday and
nanosleep
4) Cross-platform ;)
compile with -lm for floor(double)
*/
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
static struct timeval _init_time;
void _al_unix_init_time()
{
gettimeofday(&_init_time, 0);
}
/*
returns time since allegro started
*/
double al_current_time()
{
struct timeval tp;
gettimeofday(&tp, 0); //null = timezone afaik
double time = (double) (tp.tv_sec - _init_time.tv_sec)
+ (double) (tp.tv_usec - _init_time.tv_usec) * 1.0e-6;
return time;
}
/**
i found select would wake up slightly early
nanosleep wakes up slightly late
both ~ 1.5ms accurate
*/
void al_rest(double time)
{
struct timespec tp;
double seconds = floor(time);
tp.tv_sec = (time_t) seconds;
tp.tv_nsec = (suseconds_t) ((time - seconds) * 1e9);
nanosleep(&tp,0);
}
/**
####################################################
########### One-Shot TIMER #########################
####################################################
should be parallel to allegro's periodic timer
Current Timers have a nice interface I think
just make it handle doubles.
*/
/**
####################################################
########### COUNTDOWN TIMER ************************
####################################################
*/
typedef struct al_countdown_timer
{
/* timeofday timer started/resumed */
double start_time;
double time_left;
char paused; //true or false
} al_countdown_timer;
/* sets/intializes timer. does not start */
void al_countdown_reset(al_countdown_timer* tim, double time)
{
if (tim && time > 0)
{
tim->time_left = time;
tim->paused = 1;
}
}
/* starts or resumes */
void al_countdown_start(al_countdown_timer* tim)
{
if (tim)
{
tim->start_time = al_current_time();
tim->paused = 0;
}
}
/* pauses or stops */
void al_countdown_stop(al_countdown_timer* tim)
{
if (tim)
{
tim->time_left -= al_current_time() - tim->start_time;
tim->paused = 1;
}
}
/* gets time left. It returns 0 if the timer has elapsed */
double al_countdown_time(al_countdown_timer* tim)
{
if (tim && !tim->paused)
{
tim->time_left -= al_current_time() - tim->start_time;
tim->start_time = al_current_time();
}
if (tim->time_left > 0)
return tim->time_left;
else
return 0;
}
/**
####################################################
########### STOPWATCH TIMER ************************
####################################################
*/
typedef struct al_stopwatch_timer
{
/* timeofday timer started/resumed */
double start_time;
double elapsed;
char paused;
} al_stopwatch_timer;
/* initializes or resets */
void al_stopwatch_reset(al_stopwatch_timer* tim)
{
if (tim && time > 0)
{
tim->elapsed = 0;
tim->paused = 1;
}
}
/* starts timing */
void al_stopwatch_start(al_stopwatch_timer* tim)
{
if (tim)
{
tim->start_time = al_current_time();
tim->paused = 0;
}
}
/* stops counter. equivalent to pause */
void al_stopwatch_stop(al_stopwatch_timer* tim)
{
if (tim)
{
tim->elapsed += al_current_time() - tim->start_time;
tim->paused = 1;
}
}
/* gets current count of the timer */
double al_stopwatch_time(al_stopwatch_timer* tim)
{
if (tim && !tim->paused)
{
tim->elapsed += al_current_time() - tim->start_time;
tim->start_time = al_current_time();
}
return tim->elapsed;
}
/**
#####################################################
################ TEST BENCH #########################
#####################################################
*/
int main(int argc, char** argv)
{
int i;
_al_unix_init_time();
// goto countdown_test;
delay_test: printf("Delay tests\n");
{
printf("1000x 10ms delays\n");
double start = al_current_time();
for(i=0; i<1000; ++i)
al_rest(.01);
double end = al_current_time()-start;
double error = end - (1000 * .01);
printf("Time Slept %6f\n",end);
printf("Cummulative error %6f\n", error);
printf("Error per sleep %6f\n\n", error / 1000);
}
{
printf("3x 3s delays\n");
double start = al_current_time();
for(i=0; i<3; ++i)
al_rest(3);
double end = al_current_time()-start;
double error = end - 9;
printf("Time Slept %6f\n",end);
printf("Cummulative error %6f\n", error);
printf("Error per sleep %6f\n\n", error / 9);
}
countdown_test: printf("Timer tests\n");
//countdown timer test
al_countdown_timer tim1;
al_stopwatch_timer tim2;
al_countdown_reset(&tim1,50);
al_stopwatch_reset(&tim2);
printf("Countdown value %6f\n",al_countdown_time(&tim1));
printf("Stopwatch value %6f\n",al_stopwatch_time(&tim2));
al_countdown_start(&tim1);
al_stopwatch_start(&tim2);
printf("Countdown value %6f\n",al_countdown_time(&tim1));
printf("Stopwatch value %6f\n",al_stopwatch_time(&tim2));
printf("20 second sleep\n");
al_rest(20.0);
al_countdown_stop(&tim1);
al_stopwatch_stop(&tim2);
printf("countdown value %6f\n",al_countdown_time(&tim1));
printf("Stopwatch value %6f\n",al_stopwatch_time(&tim2));
printf("Pausing Timers and 2.795 second sleep\n");
al_rest(2.795);
printf("countdown value %6f\n",al_countdown_time(&tim1));
printf("Stopwatch value %6f\n",al_stopwatch_time(&tim2));
printf("Resuming Timers and 5 second sleep\n");
al_countdown_start(&tim1);
al_stopwatch_start(&tim2);
al_rest(5.0);
printf("Stopwatch value %6f\n",al_stopwatch_time(&tim2));
printf("countdown value %6f\n",al_countdown_time(&tim1));
return 0;
}