Re: glib: GTimer patch for elapsed time
- From: Gavin Baker <gavinb antonym org>
- To: Owen Taylor <otaylor redhat com>
- Cc: gtk-devel-list gnome org
- Subject: Re: glib: GTimer patch for elapsed time
- Date: 15 Jul 2002 23:52:35 +1000
Greetings,
On Wed, 2002-07-10 at 09:55, Owen Taylor wrote:
>
> Gavin Baker <gavinb antonym org> writes:
> > [...]
> > The GTimer in glib resets the clock at each call to gtk_timer_start().
> > Thus it is incapable of tracking true elapsed time across consecutive
> > calls to start-stop. This rather defeats the purpose of having a timer
> > object, since you then have to implement elapsed time tracking yourself.
> > [...]
>
> This isn't a change we can make.
>
> http://developer.gnome.org/doc/API/2.0/glib/glib-timers.html#g-timer-start
>
> Describes the current behavior, and even if it didn't people would
> be very likely relying on the current behavior. An incompatible change
> could only be made for GLib-3.0, and even then we try very hard
> to avoid incompatible changes, or to make them in a way that is
> caught by the compiler.
Ok; understand. (I'll keep that in mind for future patching too!) I
have a clean solution now...
> On the other hand adding a g_timer_continue() that doesn't reset the
> timer to zero sounds reasonable to me.
I have rewritten the patch. The existing behaviour is not changed. I
have added code to g_timer_stop() to accumulate the total elapsed time,
and I have added a new function called g_timer_total_elapsed() that will
return the true elapsed time (between start-stop calls) since the last
g_timer_reset() (instead of modifying g_timer_elapsed()).
I also added g_timer_is_active() to return whether or not the timer is
running. In the process, I also added docstrings for all the functions,
that are consistent with the API reference on the web. I can update the
web reference if someone tells me where the source lives.
I have tested and verified that it works according to both the old and
the new ways. Is this ok? Shall I file this in bugzilla?
Thanks -
::gavin
Index: gtimer.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gtimer.h,v
retrieving revision 1.3
diff -u -p -r1.3 gtimer.h
--- gtimer.h 2001/06/26 16:01:14 1.3
+++ gtimer.h 2002/07/15 13:48:31
@@ -46,6 +46,9 @@ void g_timer_stop (GTimer *timer);
void g_timer_reset (GTimer *timer);
gdouble g_timer_elapsed (GTimer *timer,
gulong *microseconds);
+gdouble g_timer_total_elapsed (GTimer *timer,
+ gulong *microseconds);
+gboolean g_timer_is_active (GTimer *timer);
void g_usleep (gulong microseconds);
Index: gtimer.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gtimer.c,v
retrieving revision 1.16
diff -u -p -r1.16 gtimer.c
--- gtimer.c 2001/09/19 18:08:19 1.16
+++ gtimer.c 2002/07/15 13:48:41
@@ -51,9 +51,11 @@ struct _GTimer
#ifdef G_OS_WIN32
DWORD start;
DWORD end;
+ DWORD elapsed;
#else /* !G_OS_WIN32 */
struct timeval start;
struct timeval end;
+ struct timeval elapsed;
#endif /* !G_OS_WIN32 */
guint active : 1;
@@ -67,6 +69,13 @@ struct _GTimer
gettimeofday (&v, NULL)
#endif /* !G_OS_WIN32 */
+
+/**
+ * g_timer_new:
+ *
+ * Creates a new GTimer, and starts timing (ie. a #g_timer_start()
+ * is implicitly called for you).
+ **/
GTimer*
g_timer_new (void)
{
@@ -77,9 +86,23 @@ g_timer_new (void)
GETTIME (timer->start);
+#ifdef G_OS_WIN32
+ timer->elapsed = 0;
+#else
+ timer->elapsed.tv_usec = 0;
+ timer->elapsed.tv_sec = 0;
+#endif /* G_OS_WIN32 */
+
return timer;
}
+/**
+ * g_timer_destroy:
+ *
+ * @timer: the timer instance to destroy
+ *
+ * Destroys a timer, freeing any associated resources.
+ **/
void
g_timer_destroy (GTimer *timer)
{
@@ -88,6 +111,15 @@ g_timer_destroy (GTimer *timer)
g_free (timer);
}
+/**
+ * g_timer_start:
+ *
+ * @timer: the timer to start.
+ *
+ * Marks a start time, so that future calls to #g_timer_elapsed()
+ * will report the time since this was called. The timer is made
+ * active, and the total elapsed time is preserved.
+ **/
void
g_timer_start (GTimer *timer)
{
@@ -98,6 +130,15 @@ g_timer_start (GTimer *timer)
GETTIME (timer->start);
}
+/**
+ * g_timer_stop:
+ *
+ * @timer: the timer to stop.
+ *
+ * Marks an end time, so calls to #g_timer_elapsed() will return the
+ * difference between the start time and this end time. The timer is
+ * made inactive, and the total elapsed time is accumulated.
+ **/
void
g_timer_stop (GTimer *timer)
{
@@ -106,16 +147,90 @@ g_timer_stop (GTimer *timer)
timer->active = FALSE;
GETTIME(timer->end);
+
+ /* Calculate the time elapsed since the last start */
+
+#ifdef G_OS_WIN32
+
+ /* Check for wraparound, which happens every 49.7 days. */
+ if (timer->end < timer->start)
+ timer->elapsed += (UINT_MAX - (timer->start - timer->end)) / 1000.0;
+ else
+ timer->elapsed += (timer->end - timer->start) / 1000.0;
+
+#else /* !G_OS_WIN32 */
+
+ if (timer->start.tv_usec > timer->end.tv_usec)
+ {
+ timer->end.tv_usec += G_USEC_PER_SEC;
+ timer->end.tv_sec--;
+ }
+
+ timer->elapsed.tv_usec += timer->end.tv_usec - timer->start.tv_usec;
+ timer->elapsed.tv_sec += timer->end.tv_sec - timer->start.tv_sec;
+
+ /* Normalise elapsed time */
+ while (timer->elapsed.tv_usec > G_USEC_PER_SEC)
+ {
+ timer->elapsed.tv_usec -= G_USEC_PER_SEC;
+ timer->elapsed.tv_sec++;
+ }
+
+#endif
}
+/**
+ * g_timer_is_active:
+ *
+ * Returns whether or not the timer is currently running.
+ **/
+gboolean
+g_timer_is_active (GTimer *timer)
+{
+ g_return_val_if_fail (timer != NULL, FALSE);
+
+ return timer->active;
+}
+
+/**
+ * g_timer_reset:
+ *
+ * Stops the timer and zeroes the start time and the total elapsed
+ * time.
+ *
+ **/
void
g_timer_reset (GTimer *timer)
{
g_return_if_fail (timer != NULL);
+ timer->active = FALSE;
+
GETTIME (timer->start);
+
+#ifdef G_OS_WIN32
+ timer->elapsed = 0;
+#else
+ timer->elapsed.tv_usec = 0;
+ timer->elapsed.tv_sec = 0;
+#endif /* G_OS_WIN32 */
}
+/**
+ * g_timer_elapsed:
+ *
+ * @timer: The timer instance to query
+ * @microseconds: The number of microseconds since the last second,
+ * or NULL if this is not required.
+ *
+ * If @timer has been started but not stopped, returns the time since
+ * the timer was started. If @timer has been stopped, obtains the
+ * elapsed time between the time it was started and the time it was
+ * stopped.
+ *
+ * To get the total elapsed time since the timer was created or last
+ * reset, use #g_timer_total_elapsed().
+ **/
gdouble
g_timer_elapsed (GTimer *timer,
gulong *microseconds)
@@ -175,6 +290,99 @@ g_timer_elapsed (GTimer *timer,
return total;
}
+/**
+ * g_timer_total_elapsed:
+ *
+ * @timer: The timer instance to query
+ * @microseconds: The number of microseconds since the last second,
+ * or NULL if this is not required.
+ *
+ * Returns the total time, in fractional seconds, elapsed for this
+ * timer. Elapsed time is defined as the total time run between
+ * successive start-stop calls. If inactive, returns the total
+ * elapsed time. If active, returns the total elapsed time,
+ * including the time since the last start call. Time will accumulate
+ * until #g_timer_reset() is called.
+ **/
+gdouble
+g_timer_total_elapsed (GTimer *timer,
+ gulong *microseconds)
+{
+ gdouble total;
+#ifdef G_OS_WIN32
+ DWORD end;
+#else
+ struct timeval end;
+#endif /* G_OS_WIN32 */
+
+ g_return_val_if_fail (timer != NULL, 0);
+
+ if (timer->active)
+ GETTIME(end);
+ else
+ end = timer->start;
+
+#ifdef G_OS_WIN32
+
+ /* Check for wraparound, which happens every 49.7 days. */
+ if (end < timer->start)
+ total = (UINT_MAX - (timer->start - end)) / 1000.0;
+ else
+ total = (end - timer->start) / 1000.0;
+
+ if (microseconds)
+ {
+ if (end < timer->start)
+ *microseconds =
+ ((UINT_MAX - (timer->start - end)) % 1000) * 1000;
+ else
+ *microseconds =
+ ((timer->end - timer->start) % 1000) * 1000;
+ }
+
+#else /* !G_OS_WIN32 */
+
+ if (timer->start.tv_usec > end.tv_usec)
+ {
+ end.tv_usec += G_USEC_PER_SEC;
+ end.tv_sec--;
+ }
+
+ timer->elapsed.tv_usec += end.tv_usec - timer->start.tv_usec;
+ timer->elapsed.tv_sec += end.tv_sec - timer->start.tv_sec;
+
+ /* Normalise elapsed time */
+ while (timer->elapsed.tv_usec > G_USEC_PER_SEC)
+ {
+ timer->elapsed.tv_usec -= G_USEC_PER_SEC;
+ timer->elapsed.tv_sec++;
+ }
+
+ total = timer->elapsed.tv_sec + ((gdouble) timer->elapsed.tv_usec / 1e6);
+ if (total < 0)
+ {
+ total = 0;
+
+ if (microseconds)
+ *microseconds = 0;
+ }
+ else if (microseconds)
+ *microseconds = timer->elapsed.tv_usec;
+
+#endif /* !G_OS_WIN32 */
+
+ return total;
+}
+
+/**
+ * g_usleep:
+ *
+ * @microseconds: Number of microseconds to sleep for
+ *
+ * Puts the current thread to sleep for the given number of microseconds.
+ * This call is blocking, and the sleep time is a minimum value; depending
+ * on system load and scheduling, it may sleep longer.
+ **/
void
g_usleep (gulong microseconds)
{
--
Gavin Baker // gavinb*antonym_org // Linux|Python|Esperanto|MIDI|Cheese
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]