[RFC] get_ticks broken on linux

It uses gettimeofday to calculate the timedifference.
Gettimeofday returns current time which is seldom monotonous.
This breaks SDL timer subsystem. (time callbacks and all that
get borked when the time difference ms is suddenly ~ 2^32)

I posted a message about this earlier but got no response.
Some thoughts on this matter would be appreciated.
(Or even an explanation for the lack of interest.)

A patch below would use the posix timers that have been around
since posix 93 and do provide a good source of monotonous time
on linux boxes (and on few others too).

The following patch is also availabe at:
http://www.hut.fi/u/tkyntola/SDL-1.2.9-clockfix.patch

It’s against 1.2.9, but I can easily rediffit against
the cvs branch is needed.

cheers,
Tommi Kyntola @Tommi_Kyntola

diff -Naur SDL-1.2.9/src/timer/linux/SDL_systimer.c SDL-1.2.9-clockfix/src/timer/linux/SDL_systimer.c
— SDL-1.2.9/src/timer/linux/SDL_systimer.c 2004-01-04 18:49:19.000000000 +0200
+++ SDL-1.2.9-clockfix/src/timer/linux/SDL_systimer.c 2005-09-27 10:49:26.000000000 +0300
@@ -34,6 +34,16 @@
#include <string.h>
#include <errno.h>

+/* The clock_gettime provides monotonous time, so we should use it if

  • it’s available. The clock_gettime function is behind ifdef
  • for __USE_POSIX199309
  • Tommi Kyntola (@Tommi_Kyntola) 27/09/2005
    +/
    +#if (defined _POSIX_TIMERS && _POSIX_TIMERS > 0)
    +#include <time.h>
    +#define USE_CLOCK_GETTIME
    +#endif+
    #include “SDL_error.h”
    #include “SDL_timer.h”
    #include “SDL_timer_c.h”
    @@ -86,6 +96,19 @@
    float cpu_mhz;
    unsigned long long tsc_start;
    unsigned long long tsc_end;
    +/
    Slight code doubling here for the sake of readability */
    +#ifdef USE_CLOCK_GETTIME
  •   struct timespec tv_start, tv_end;
    
  •   long usec_delay;
    
  •   rdtsc(tsc_start);
    
  •   clock_gettime(CLOCK_MONOTONIC,&tv_start);
    
  •   sleep(1);
    
  •   rdtsc(tsc_end);
    
  •   clock_gettime(CLOCK_MONOTONIC,&tv_end);
    
  •   usec_delay = (1000000000L * (tv_end.tv_sec - tv_start.tv_sec) +
    
  •                 (tv_end.tv_nsec - tv_start.tv_nsec)) / 1000;
    

+#else
struct timeval tv_start, tv_end;
long usec_delay;

@@ -96,6 +119,7 @@
gettimeofday(&tv_end, NULL);
usec_delay = 1000000L * (tv_end.tv_sec - tv_start.tv_sec) +
(tv_end.tv_usec - tv_start.tv_usec);
+#endif /* USE_CLOCK_GETTIME */
cpu_mhz = (float)(tsc_end-tsc_start) / usec_delay;
#if 0
printf(“cpu MHz\t\t: %.3f\n”, cpu_mhz);
@@ -105,8 +129,12 @@

#else

+#ifdef USE_CLOCK_GETTIME
/* The first ticks value of the application /
+static struct timespec start;
+#else
static struct timeval start;
+#endif /
USE_CLOCK_GETTIME */

#endif /* USE_RDTSC */

@@ -120,7 +148,11 @@
}
rdtsc(start);
#else
+#ifdef USE_CLOCK_GETTIME

  •   clock_gettime(CLOCK_MONOTONIC,&start);
    

+#else
gettimeofday(&start, NULL);
+#endif /* USE_CLOCK_GETTIME /
#endif /
USE_RDTSC */
}

@@ -134,11 +166,17 @@
rdtsc(now);
return (Uint32)((now-start)/cpu_mhz1000);
#else

  •   struct timeval now;
       Uint32 ticks;
    

+#ifdef USE_CLOCK_GETTIME

  •   struct timespec now;
    
  •   clock_gettime(CLOCK_MONOTONIC,&now);
    
  •   ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_nsec-start.tv_nsec)/1000000;
    

+#else

  •   struct timeval now;
       gettimeofday(&now, NULL);
       ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_usec-start.tv_usec)/1000;
    

+#endif /* USE_CLOCK_GETTIME /
return(ticks);
#endif /
USE_RDTSC */
}

A patch below would use the posix timers that have been around
since posix 93 and do provide a good source of monotonous time
on linux boxes (and on few others too).

This is in CVS now.

Thanks,
–ryan.

Ryan C. Gordon wrote:

A patch below would use the posix timers that have been around
since posix 93 and do provide a good source of monotonous time
on linux boxes (and on few others too).

This is in CVS now.

Err…correction.

From here:
http://www.uwsg.iu.edu/hypermail/linux/net/0304.1/0010.html

“These syscalls were added to Linux 2.5.64 or thereabouts, so if you
download a very recent Linux 2.5 kernel, you’ll be able to use it
for these syscalls. (more recent is better.)”

The clock_gettime() symbol doesn’t show up in the glibc on this Linux
system (even with the _POSIX_TIMERS check in SDL_systimer.c succeeding).

For now, I’m leaving the patch in CVS, but I’m forcibly undefining
USE_CLOCK_GETTIME. Eventually, we should check for this in the configure
scripts, or perhaps choose one at runtime.

–ryan.

I thoght that the ifdef might not be sufficient. I’ll have a look
at all the various boxes we have here (suns, hpuxes and a numerous
older and newer linux boxen) and try to figure out the correct check.

What makes it a bit strange is how it indeed was added to 2.5
but it’s missing from 2.4, where as most recent distros
currently run 2.6 kernels BUT with a glib compiled against
2.4 kernel headers (e.g. my UTS_RELEASE is 2.4.20 with a glibc
version 2.3.5 along with a posix verion 200112L) and none of the
2.4 have the necessary syscalls (well not for x86 anyways).

That is why I assumed without checking that 2.4 had the support.
Sorry bout that. Anyway I’ll look into this and try to figure out
the correct check. Because the use of gettimeofday is really not
the way to go unless it’s the last option available.

cheers,
Tommi Kyntola

Ryan C. Gordon wrote:> Ryan C. Gordon wrote:

A patch below would use the posix timers that have been around
since posix 93 and do provide a good source of monotonous time
on linux boxes (and on few others too).

This is in CVS now.

Err…correction.

From here:
http://www.uwsg.iu.edu/hypermail/linux/net/0304.1/0010.html

“These syscalls were added to Linux 2.5.64 or thereabouts, so if you
download a very recent Linux 2.5 kernel, you’ll be able to use it
for these syscalls. (more recent is better.)”

The clock_gettime() symbol doesn’t show up in the glibc on this Linux
system (even with the _POSIX_TIMERS check in SDL_systimer.c succeeding).

For now, I’m leaving the patch in CVS, but I’m forcibly undefining
USE_CLOCK_GETTIME. Eventually, we should check for this in the configure
scripts, or perhaps choose one at runtime.

–ryan.


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl