2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Io/Timer.cpp $
15 * Include file for timer stuff
18 * Revision 1.7 2002/06/09 04:41:22 relnev
19 * added copyright header
21 * Revision 1.6 2002/06/05 08:05:29 relnev
22 * stub/warning removal.
24 * reworked the sound code.
26 * Revision 1.5 2002/05/29 21:38:20 relnev
29 * Revision 1.4 2002/05/28 21:36:10 relnev
30 * some more timer junk.
32 * tried to fix software mode.
34 * Revision 1.3 2002/05/28 17:26:57 theoddone33
35 * Fill in some timer and palette setting stubs. Still no display
37 * Revision 1.2 2002/05/07 03:16:46 theoddone33
38 * The Great Newline Fix
40 * Revision 1.1.1.1 2002/05/03 03:28:09 root
44 * 4 5/26/99 3:19p Dave
45 * Fixed release build errors.
47 * 3 5/17/99 6:03p Dave
48 * Added new timing code. Put in code to allow camera speed zooming.
50 * 2 10/07/98 10:53a Dave
53 * 1 10/07/98 10:49a Dave
55 * 14 4/13/98 10:16a John
56 * Switched gettime back to timer_get_milliseconds, which is now thread
59 * 13 4/13/98 10:11a John
60 * Made timer functions thread safe. Made timer_init be called in all
63 * 12 4/13/98 8:09a John
64 * Made timer_get functions thread safe.
66 * 11 12/02/97 3:56p John
67 * fixed a bug with timestamp_until, created one with it rolling over.
69 * 10 9/11/97 7:12p Hoffoss
70 * Added more functionality to training sexp handling code.
72 * 9 8/29/97 4:49p Allender
73 * added mprintf to check for wrap problems with timestamp ticker
75 * 8 8/28/97 1:38p Allender
76 * from John: changes to timer func to detect early rollever
78 * 7 7/29/97 5:30p Lawrance
79 * move gettime() from keyboard module to timer module
81 * 6 7/16/97 4:42p Mike
82 * Make afterburner shake viewer, not ship.
83 * Shake for limited time.
84 * Add timestamp_until() function to timer library.
86 * 5 2/17/97 5:18p John
87 * Added a bunch of RCS headers to a bunch of old files that don't have
98 #include "alphacolors.h"
104 static int Timer_inited = 0;
108 if ( Timer_inited ) {
115 if ( !Timer_inited ) {
116 SDL_InitSubSystem(SDL_INIT_TIMER);
125 fix timer_get_fixed_seconds()
127 Sint64 a = SDL_GetTicks();
130 return (fix)(a / 1000);
133 fix timer_get_fixed_secondsX()
135 return timer_get_fixed_seconds();
138 fix timer_get_approx_seconds()
140 return timer_get_fixed_seconds();
143 int timer_get_milliseconds()
145 return SDL_GetTicks();
148 int timer_get_microseconds()
150 return SDL_GetTicks() * 1000;
154 // 1 means always return true
155 // 2 and above actually check the time
156 int timestamp_ticker = 2;
158 void timestamp_reset()
160 timestamp_ticker = 2;
163 // Restrict all time values between 0 and MAX_TIME
164 // so we don't have to use UINTs to calculate rollover.
165 // For debugging & testing, you could set this to
166 // something like 1 minute (6000).
167 #define MAX_TIME (INT_MAX/2)
169 void timestamp_inc(float frametime)
171 timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
173 if ( timestamp_ticker > MAX_TIME ) {
174 timestamp_ticker = 2; // Roll!
177 if (timestamp_ticker < 2 ) {
178 mprintf(("Whoa!!! timestamp_ticker < 2 -- resetting to 2!!!\n"));
179 timestamp_ticker = 2;
183 int timestamp(int delta_ms )
186 if (delta_ms < 0 ) return 0;
187 if (delta_ms == 0 ) return 1;
188 t2 = timestamp_ticker + delta_ms;
189 if ( t2 > MAX_TIME ) {
191 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
193 if (t2 < 2 ) t2 = 2; // hack??
197 // Returns milliseconds until timestamp will elapse.
198 // Negative value gives milliseconds ago that timestamp elapsed.
199 int timestamp_until(int stamp)
202 // HACK!! This doesn't handle rollover!
203 // (Will it ever happen?)
205 return stamp - timestamp_ticker;
210 delta = stamp - timestamp_ticker;
213 if (delta > UINT_MAX/2)
214 delta = UINT_MAX - delta + 1;
215 else if (delta < - ( (int) (UINT_MAX/2)))
216 delta = UINT_MAX + delta + 1;
222 // alternate timestamp functions. The way these work is you call xtimestamp() to get the
223 // current counter value, and then call
226 return timestamp_ticker;
229 int timestamp_has_time_elapsed(int stamp, int time)
237 if (t <= timestamp_ticker)
238 return 1; // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
243 // timing functions -------------------------------------------------------------------------------
245 #define MAX_TIMING_EVENTS 15
250 typedef struct timing {
252 int microseconds_total;
258 timing Timing_events[MAX_TIMING_EVENTS];
259 int Timing_event_count = 0;
263 // lookup a timing event
264 int timing_event_lookup(char *event_name)
272 if(event_name == NULL){
276 // look through all events
277 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
278 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
287 // start timing frame stuff
288 void timing_frame_start()
296 Timing_event_count = 0;
297 Timing_frame.start = timer_get_microseconds();
298 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
299 Timing_events[idx].microseconds_total = 0;
300 SDL_strlcpy(Timing_events[idx].name, "", sizeof(Timing_events[0].name));
301 Timing_events[idx].ref_count = 0;
306 // done timing the frame
307 void timing_frame_stop()
315 stop_time = timer_get_microseconds();
318 Timing_frame.microseconds_total = stop_time - Timing_frame.start;
322 // get the total frame time in microseconds
323 int timing_frame_total()
328 return Timing_frame.microseconds_total;
332 // time an individual event
333 void timing_event_start(char *event_name)
341 if(event_name == NULL){
345 // try and find the event
346 event = timing_event_lookup(event_name);
348 // if we already have one
350 SDL_assert(Timing_events[event].ref_count == 0);
351 Timing_events[event].start = timer_get_microseconds();
352 Timing_events[event].ref_count++;
354 // if we need to add a new one
356 if(Timing_event_count < MAX_TIMING_EVENTS){
357 SDL_strlcpy(Timing_events[Timing_event_count].name, event_name, sizeof(Timing_events[0].name));
358 Timing_events[Timing_event_count].start = timer_get_microseconds();
359 Timing_events[Timing_event_count++].ref_count++;
365 // stop timing an event
366 void timing_event_stop(char *event_name)
374 if(event_name == NULL){
378 // try and find the event
379 event = timing_event_lookup(event_name);
381 // if we already have one
383 SDL_assert(Timing_events[event].ref_count == 1);
384 Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
385 Timing_events[event].ref_count--;
390 // get the total time for an event in microseconds
391 int timing_event_total(char *event_name)
399 if(event_name == NULL){
403 // try and find the event
404 event = timing_event_lookup(event_name);
409 return Timing_events[event].microseconds_total;
413 // get the percentage of total frametime for the event (0.0 to 1.0)
414 float timing_event_pct(char *event_name)
422 if(event_name == NULL){
426 // try and find the event
427 event = timing_event_lookup(event_name);
432 return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
437 void timing_display(int x, int y)
444 gr_set_color_fast(&Color_bright_blue);
447 gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
450 // each event percentage
451 for(idx=0; idx<Timing_event_count; idx++){
452 gr_printf(x, y, "%s : %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));