[PATCH] glib/gtimer: nsleep on AIX, high resolution funcs
- From: "ANDREW PAPROCKI, BLOOMBERG/ 731 LEXIN" <apaprocki bloomberg net>
- To: GTK-DEVEL-LIST GNOME ORG
- Cc:
- Subject: [PATCH] glib/gtimer: nsleep on AIX, high resolution funcs
- Date: Sun, 20 Nov 2005 15:42:56 -0500
This patch provides two things:
1) Configure-time nsleep detection so that the same nanosleep functionality
currently found in g_usleep will be used on AIX. The nsleep function is
essentially the same as nanosleep and has the same semantics, AIX just renamed
it.
2) Modification of g_timer internals to use nanosecond high resolution timers on
AIX or platforms that have a gethrtime() function. this is currently Solaris,
HP-UX, and RT-Linux implementations (possibly other flavors of UNIX as well).
There are no API changes, but the GTimer structure size contains different types
depending on the platform. (The size might not necessarily change, but that is
up to the platform.)
This is useful when wanting to instrument cross-platform production code based
upon glib with g_timer to gather function execution time data. Running the code
through Quantify shows that the high resolution timer functions take ~3 cycles.
Compared to gettimeofday(), they are about 10x faster.
If no one has objections, I ask that this be checked into glib CVS.
Thanks,
Andrew Paprocki
Bloomberg LP
--- configure.in 18 Nov 2005 14:01:59 -0000 1.474
+++ configure.in 20 Nov 2005 20:32:51 -0000
@@ -835,7 +835,10 @@
AC_MSG_RESULT(unsigned $glib_size_type)
# Check for some functions
-AC_CHECK_FUNCS(lstat strerror strsignal memmove mkstemp vsnprintf stpcpy
strcasecmp strncasecmp poll getcwd nanosleep vasprintf setenv unsetenv
getc_unlocked readlink symlink)
+AC_CHECK_FUNCS(lstat strerror strsignal memmove mkstemp vsnprintf stpcpy
strcasecmp strncasecmp poll getcwd vasprintf setenv unsetenv getc_unlocked
readlink symlink)
+
+# Check for high resolution sleep/time functions
+AC_CHECK_FUNCS(nanosleep nsleep gethrtime)
AC_CHECK_HEADERS(crt_externs.h)
AC_CHECK_FUNCS(_NSGetEnviron)
--- glib/gtimer.h 22 Jan 2004 19:56:26 -0000 1.5
+++ glib/gtimer.h 20 Nov 2005 20:32:51 -0000
@@ -38,6 +38,7 @@
typedef struct _GTimer GTimer;
#define G_USEC_PER_SEC 1000000
+#define G_NSEC_PER_SEC 1000000000
GTimer* g_timer_new (void);
void g_timer_destroy (GTimer *timer);
--- glib/gtimer.c 20 Mar 2005 11:35:48 -0000 1.26
+++ glib/gtimer.c 20 Nov 2005 20:32:51 -0000
@@ -35,17 +35,21 @@
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
-#ifndef G_OS_WIN32
+#ifdef G_OS_WIN32
+# include <windows.h>
+#else /* !G_OS_WIN32 */
#include <sys/time.h>
+# if defined(_AIX) && _AIX
+# include <sys/systemcfg.h>
+# endif
#include <time.h>
#include <errno.h>
-#endif /* G_OS_WIN32 */
-
-#ifdef G_OS_WIN32
-#include <windows.h>
-#endif /* G_OS_WIN32 */
+#endif /* !G_OS_WIN32 */
-#include "glib.h"
+#include "gtypes.h"
+#include "gmessages.h"
+#include "gmem.h"
+#include "gtimer.h"
#include "galias.h"
@@ -55,20 +59,52 @@
guint64 start;
guint64 end;
#else /* !G_OS_WIN32 */
+# if defined(HAVE_GETHRTIME)
+ /* on platforms that support gethrtime(), hrtime_t is a 64-bit
+ * integer representing a number of nanoseconds since some point
+ * of time in the past.
+ *
+ * solaris, hpux, and rt-linux implementations are known to have
+ * this function.
+ */
+ hrtime_t start;
+ hrtime_t end;
+# elif defined(_AIX) && _AIX
+ /* on AIX systems with read_real_time(), the system calls use a
+ * hardware feature to read nanosecond resolution time from special
+ * registers on the cpu.
+ */
+ timebasestruct_t start;
+ timebasestruct_t end;
+# else /* !HAVE_GETHRTIME && !_AIX */
+ /* all other systems default to gettimeofday */
struct timeval start;
struct timeval end;
+# endif /* !HAVE_GETHRTIME && !_AIX */
#endif /* !G_OS_WIN32 */
guint active : 1;
};
+static void
+g_timer_get_time(GTimer *timer, gboolean start)
+{
#ifdef G_OS_WIN32
-# define GETTIME(v) \
- GetSystemTimeAsFileTime ((FILETIME *)&v)
+ GetSystemTimeAsFileTime((FILETIME *)(start ? timer->start : timer->end));
#else /* !G_OS_WIN32 */
-# define GETTIME(v) \
- gettimeofday (&v, NULL)
+# if defined(HAVE_GETHRTIME)
+ if (start)
+ timer->start = gethrtime();
+ else
+ timer->end = gethrtime();
+# elif defined(_AIX) && _AIX
+ read_real_time(start ? &(timer->start) : &(timer->end), TIMEBASE_SZ);
+ time_base_to_time(start ? &(timer->start) : &(timer->end), TIMEBASE_SZ);
+# else /* !HAVE_GETHRTIME && !_AIX */
+ gettimeofday(start ? &(timer->start) : &(timer->end), NULL);
+# endif /* !HAVE_GETHRTIME && !_AIX */
#endif /* !G_OS_WIN32 */
+}
GTimer*
g_timer_new (void)
@@ -78,7 +114,7 @@
timer = g_new (GTimer, 1);
timer->active = TRUE;
- GETTIME (timer->start);
+ g_timer_get_time (timer, TRUE);
return timer;
}
@@ -98,7 +134,7 @@
timer->active = TRUE;
- GETTIME (timer->start);
+ g_timer_get_time (timer, TRUE);
}
void
@@ -108,7 +144,7 @@
timer->active = FALSE;
- GETTIME(timer->end);
+ g_timer_get_time (timer, FALSE);
}
void
@@ -116,7 +152,7 @@
{
g_return_if_fail (timer != NULL);
- GETTIME (timer->start);
+ g_timer_get_time (timer, TRUE);
}
void
@@ -124,9 +160,15 @@
{
#ifdef G_OS_WIN32
guint64 elapsed;
-#else
+#else /* !G_OS_WIN32 */
+# if defined(HAVE_GETHRTIME)
+ hrtime_t elapsed;
+# elif defined(_AIX) && _AIX
+ timebasestruct_t elapsed;
+# else /* !HAVE_GETHRTIME && !_AIX */
struct timeval elapsed;
-#endif /* G_OS_WIN32 */
+# endif /* !HAVE_GETHRTIME && !_AIX */
+#endif /* !G_OS_WIN32 */
g_return_if_fail (timer != NULL);
g_return_if_fail (timer->active == FALSE);
@@ -137,17 +179,39 @@
*/
#ifdef G_OS_WIN32
+ elapsed = timer->end - timer->start;
+
+ g_timer_get_time (timer, TRUE);
+ timer->start -= elapsed;
+#else /* !G_OS_WIN32 */
+# if defined(HAVE_GETHRTIME)
elapsed = timer->end - timer->start;
- GETTIME (timer->start);
+ g_timer_get_time (timer, TRUE);
timer->start -= elapsed;
+# elif defined(_AIX) && _AIX
+ /* tb_low is a nanosecond count, tb_high is a second count */
+ if (timer->start.tb_low > timer->end.tb_low) {
+ timer->end.tb_low += G_NSEC_PER_SEC;
+ timer->end.tb_high--;
+ }
-#else /* !G_OS_WIN32 */
+ elapsed.tb_low = timer->end.tb_low - timer->start.tb_low;
+ elapsed.tb_high = timer->end.tb_high - timer->start.tb_high;
- if (timer->start.tv_usec > timer->end.tv_usec)
- {
+ g_timer_get_time (timer, TRUE);
+
+ if (timer->start.tb_low < elapsed.tb_low) {
+ timer->start.tb_low += G_NSEC_PER_SEC;
+ timer->start.tb_high--;
+ }
+
+ timer->start.tb_low -= elapsed.tb_low;
+ timer->end.tb_high -= elapsed.tb_high;
+# else /* !HAVE_GETHRTIME && !_AIX */
+ if (timer->start.tv_usec > timer->end.tv_usec) {
timer->end.tv_usec += G_USEC_PER_SEC;
timer->end.tv_sec--;
}
@@ -155,17 +219,16 @@
elapsed.tv_usec = timer->end.tv_usec - timer->start.tv_usec;
elapsed.tv_sec = timer->end.tv_sec - timer->start.tv_sec;
- GETTIME (timer->start);
+ g_timer_get_time (timer, TRUE);
- if (timer->start.tv_usec < elapsed.tv_usec)
- {
+ if (timer->start.tv_usec < elapsed.tv_usec) {
timer->start.tv_usec += G_USEC_PER_SEC;
timer->start.tv_sec--;
}
timer->start.tv_usec -= elapsed.tv_usec;
timer->start.tv_sec -= elapsed.tv_sec;
-
+# endif /* !HAVE_GETHRTIME && !_AIX */
#endif /* !G_OS_WIN32 */
timer->active = TRUE;
@@ -176,30 +239,61 @@
gulong *microseconds)
{
gdouble total;
+
#ifdef G_OS_WIN32
gint64 elapsed;
-#else
+#else /* !G_OS_WIN32 */
+# if defined(HAVE_GETHRTIME)
+ hrtime_t elapsed;
+# elif defined(_AIX) && _AIX
+ timebasestruct_t elapsed;
+# else /* !HAVE_GETHRTIME && !_AIX */
struct timeval elapsed;
-#endif /* G_OS_WIN32 */
+# endif /* !HAVE_GETHRTIME && !_AIX */
+#endif /* !G_OS_WIN32 */
g_return_val_if_fail (timer != NULL, 0);
-#ifdef G_OS_WIN32
if (timer->active)
- GETTIME (timer->end);
+ g_timer_get_time (timer, FALSE);
+#ifdef G_OS_WIN32
elapsed = timer->end - timer->start;
+ /* elapsed is 100s of nanoseconds since 1/1/1601 */
total = elapsed / 1e7;
if (microseconds)
*microseconds = (elapsed / 10) % 1000000;
#else /* !G_OS_WIN32 */
- if (timer->active)
- gettimeofday (&timer->end, NULL);
+# if defined(HAVE_GETHRTIME)
+ elapsed = timer->end - timer->start;
- if (timer->start.tv_usec > timer->end.tv_usec)
- {
+ /* elapsed is a number of nanoseconds */
+ total = elapsed / 1e9;
+
+ if (microseconds)
+ *microseconds = (guint64)(elapsed / 1e3) % G_USEC_PER_SEC;
+# elif defined(_AIX) && _AIX
+ /* tb_low is a nanosecond count, tb_high is a second count */
+ if (timer->start.tb_low > timer->end.tb_low) {
+ timer->end.tb_low += G_NSEC_PER_SEC;
+ timer->end.tb_high--;
+ }
+
+ elapsed.tb_low = timer->end.tb_low - timer->start.tb_low;
+ elapsed.tb_high = timer->end.tb_high - timer->start.tb_high;
+
+ total = elapsed.tb_high + ((gdouble)elapsed.tb_low / 1e9);
+ if (total < 0) {
+ total = 0;
+ if (microseconds)
+ *microseconds = 0;
+ }
+ else if (microseconds)
+ *microseconds = elapsed.tb_low / 1000;
+# else /* !HAVE_GETHRTIME && !_AIX */
+ if (timer->start.tv_usec > timer->end.tv_usec) {
timer->end.tv_usec += G_USEC_PER_SEC;
timer->end.tv_sec--;
}
@@ -208,16 +302,14 @@
elapsed.tv_sec = timer->end.tv_sec - timer->start.tv_sec;
total = elapsed.tv_sec + ((gdouble) elapsed.tv_usec / 1e6);
- if (total < 0)
- {
+ if (total < 0) {
total = 0;
-
if (microseconds)
*microseconds = 0;
}
else if (microseconds)
*microseconds = elapsed.tv_usec;
-
+# endif /* !HAVE_GETHRTIME && !_AIX */
#endif /* !G_OS_WIN32 */
return total;
@@ -229,13 +321,21 @@
#ifdef G_OS_WIN32
Sleep (microseconds / 1000);
#else /* !G_OS_WIN32 */
-# ifdef HAVE_NANOSLEEP
+# if defined(HAVE_NANOSLEEP)
struct timespec request, remaining;
request.tv_sec = microseconds / G_USEC_PER_SEC;
request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
while (nanosleep (&request, &remaining) == -1 && errno == EINTR)
request = remaining;
-# else /* !HAVE_NANOSLEEP */
+# elif defined(HAVE_NSLEEP)
+ /* on AIX systems, nsleep is analogous to nanosleep */
+ struct timestruc_t request, remaining;
+ request.tv_sec = microseconds / G_USEC_PER_SEC;
+ request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
+ while (nsleep (&request, &remaining) == -1 && errno == EINTR)
+ request = remaining;
+# else /* !HAVE_NANOSLEEP && !HAVE_NSLEEP */
+# ifdef G_THREADS_ENABLED
if (g_thread_supported ())
{
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
@@ -263,11 +363,14 @@
}
else
{
+# endif
struct timeval tv;
tv.tv_sec = microseconds / G_USEC_PER_SEC;
tv.tv_usec = microseconds % G_USEC_PER_SEC;
select(0, NULL, NULL, NULL, &tv);
+# ifdef G_THREADS_ENABLED
}
+# endif /* G_THREADS_ENABLED */
# endif /* !HAVE_NANOSLEEP */
#endif /* !G_OS_WIN32 */
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]