After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 540545 - Monotonic time and timer offset
Monotonic time and timer offset
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Allison Karlitskaya (desrt)
gtkdev
: 615871 627655 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2008-06-27 21:37 UTC by Patrik Olsson
Modified: 2012-01-19 02:41 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
g_get_current_time bug fix (497 bytes, patch)
2008-06-27 21:39 UTC, Patrik Olsson
committed Details | Review
Monotonic time functions (4.96 KB, patch)
2008-06-27 21:40 UTC, Patrik Olsson
none Details | Review
Nanosecond (GTimeSpec) real time (2.37 KB, patch)
2008-06-27 21:41 UTC, Patrik Olsson
none Details | Review
GTimer uses monotonic time (1.80 KB, patch)
2008-06-27 21:41 UTC, Patrik Olsson
none Details | Review
Offset function for GTimer (1.55 KB, patch)
2008-06-27 21:42 UTC, Patrik Olsson
none Details | Review
Use librt regardless of threading (387 bytes, patch)
2009-10-08 11:06 UTC, Christian Dywan
none Details | Review
get_monotonic_time, with Since (4.99 KB, patch)
2009-10-08 11:33 UTC, Christian Dywan
none Details | Review
Implement g_get_monotonic_time/ g_has_monotonic_clock/ GTimeSpec (5.53 KB, patch)
2010-02-01 12:51 UTC, Christian Dywan
none Details | Review
Timeouts based on monotonic time (4.85 KB, patch)
2010-02-01 12:57 UTC, Christian Dywan
none Details | Review

Description Patrik Olsson 2008-06-27 21:37:43 UTC
Hey,

This is the first time I send in patches to a project. In fact, it's the first time I send a bug report at all. Please don't bite me. ;) I can't find any way to make attachments for my patches, but I hope I can add them after I send this in. Oh, and my OS is GNU/Linux, not just Linux.

I found a missing feature in glib. The ability to offset the start time in GTimer. While working on that I found some other things that could be done better. Oh, and one bug too.

First, let's start with the bug. A simple bug fix. On Windows the "is not null"-check would never happen.

----
g_get_current_time.patch
* glib/gmain.c (g_get_current_time):
Put g_return_if_fail (result != NULL) outside preprocessor conditional.
----

Now, something that could be done better. You are currently using a real time clock for things where you should use a monotonic clock, if available. An example is GTimer. In fact, glib does not even provide an interface to a monotonic clock, but only a real time clock (g_get_current_time). Why is not a real time clock good for a timer? Because it will break the calculations of elapsed time if the real time clock is adjusted. A monotonic clock instead keeps track of time from an unspecified start point (but usually when the computer started) that cannot be adjusted. This patch adds two functions. g_get_monotonic_time and g_has_monotonic_clock, as well as a new struct GTimeSpec, which is like GTimeVal, except with a nsec (nanosecond) field instead of a usec (microsecond) one. Like GTimeVal, it has a Unix equivalent; timespec. We should make sure that the library uses the correct function as needed. The general rule is that if real time is not needed, monotonic should be used.

----
g_get_monotonic_time.patch
* glib/gtypes.h:
Added type GTimeSpec and struct _GTimeSpec.

* glib/gmain.c (g_get_current_time):
Modified documentation to point to correct use of g_get_monotonic_time().

* glib/gmain.c (g_get_monotonic_time):
* glib/gmain.h (g_get_monotonic_time):
New function.

* glib/gmain.c (g_has_monotonic_clock):
* glib/gmain.h (g_has_monotonic_clock):
New function.

* docs/reference/glib/tmpl/date.sgml:
Document GTimeSpec, g_get_monotonic_time() and g_has_monotonic_clock().
----

It is still missing autotools rules to make librt be compiled in one some systems (e.g. GNU/Linux). Also missing runtime check if MONOTONIC_CLOCK really is available (like how it is done in gthread/gthread-posix.c). I didn't want to make the check inside the function since it would have to be checked in every call. On the other hand, I didn't find any place to put the init code for a static variable (which could be set to either CLOCK_MONOTONIC or CLOCK_REALTIME) as done in gthread/gthread-posix.c. These things needs to be fixed before the patch is complete, and I need help with them.

Logically, with a new nanosecond resolution structure we also want to get real time with nanosecond resolution. This next patch adds g_get_current_time_ns() which does exactly that. It depends on the GTimeSpec structure in the previous patch (not included in this one too!).

----
* glib/gmain.c (g_get_current_time_ns):
* glib/gmain.h (g_get_current_time_ns):
New function.

* docs/reference/glib/tmpl/date.sgml:
Document g_get_current_time_ns().
----

The next patch makes GTimer use g_get_monotonic_time instead of g_thread_gettime. I'm not sure, but maybe we should also even store start and end as GTimeSpec? I think the whole question is whether it will break compatibility if we change the _GTimer structure. But storing start and end as GTimeSpec would mean less operations in total (because as it is now it converts it twice, once to gint64 every time we start and stop and then to gdouble at gtimer_elapsed()).

----
gtimer_monotonic.patch
* glib/gtimer.c (GETTIME): Uses g_get_monotonic_time() instead.
----

On another note. g_thread_gettime is a mess. It can't be decided if it returns a real time or a monotonic one. Most does real time, one (posix) does monotonic, if available. Windows 32 implementation (at least) is also duplicated (once in glib/gthread.c and another time in gthread/gthread-win32.c). Also, all implementations in the gthread folder never seems to be built, but only distributed. I really hope the function g_thread_gettime is there only for compatibility (luckily it's not in the documentation).

If we include g_get_current_time_ns we could make g_thread_gettime use that instead. g_get_current_time_ns already uses all the implementations of gthread_gettime (I think).

Because of the uncertainty in the g_thread_gettime function (f.e. whether it is monotonic or real time) we should check in other files that might use the function if they use it correctly. In fact, I think nothing should use this function at all (unless they need a real time clock with potential nanosecond precision, in which case they could use g_get_current_time_ns if we include it). gfilemonitor.c seems to use it, but I'm not sure if it's supposed to get a real time or a monotonic one. Depending on what, it should either call g_get_current_time[-ns] or g_get_monotonic_time instead. gtimer.c also uses it, but I have already fixed that in my previous patch.

Now the last patch. The one I actually did all this for.

----
gtimer_offset.patch
* glib/gtimer.c (g_timer_offset):
* glib/gtimer.h (g_timer_offset):
New function.

* docs/reference/glib/tmpl/date.sgml:
Document g_timer_offset().
----

It adds another function to GTimer that allows you to adjust the start and end time. This is useful if one wants to reset the timer and offset with a calculated delay. That way the delays (which could be several tens of milliseconds in heavy event streams in GTK) won't stack. I noticed this problem when implementing an animation redraw in the idle event (timeout was useles anyway). The frames per second would drop when I for example moved and resized the window a lot. If I made the fps limit less strict it would still drop, however it could drop to something higher than it did with a more strict fps limit. E.g. during a lot of events: 60 FPS limit -> ~40 FPS, 240 FPS limit -> ~160 FPS. When I implemented my own timer with a way to offset the delay it kept the FPS limit at all times. This patch basically makes that possible for GTimer too.


One last thing. I think the part (from date.sgml)

"GLib doesn't contain any time-manipulation functions; however, there
is a #GTime typedef and a #GTimeVal struct which represents a more 
precise time (with microseconds). You can request the current time as 
a #GTimeVal with g_get_current_time()."

is a bit outdated. GTime is deprecated (misspelt "deprected" in the docs), and
we probably need to mention GTimeSpec and g_get_current_time_ms as well (or
instead), if we add them in. But maybe we could even just remove the whole
paragraph?

Thank you for your time. And great software!

/Patrik
Comment 1 Patrik Olsson 2008-06-27 21:39:36 UTC
Created attachment 113556 [details] [review]
g_get_current_time bug fix
Comment 2 Patrik Olsson 2008-06-27 21:40:33 UTC
Created attachment 113557 [details] [review]
Monotonic time functions
Comment 3 Patrik Olsson 2008-06-27 21:41:28 UTC
Created attachment 113558 [details] [review]
Nanosecond (GTimeSpec) real time
Comment 4 Patrik Olsson 2008-06-27 21:41:57 UTC
Created attachment 113559 [details] [review]
GTimer uses monotonic time
Comment 5 Patrik Olsson 2008-06-27 21:42:26 UTC
Created attachment 113560 [details] [review]
Offset function for GTimer
Comment 6 Matthias Clasen 2008-06-29 05:42:02 UTC
g_thread_gettime is supposed to return monotonic time where available.
It is implemented in libgthread to avoid pulling a librt and libpthread dependency into libglib. 
Comment 7 Patrik Olsson 2008-06-29 10:41:59 UTC
Hmm. I never thought about that. I mean, the dependency (I believe it's only librt) will only be there if you actually have the library. And if you have the library the extra dependency is not a problem, right? All systems that will have the dependency will have those libraries as system libraries (i.e. they are guaranteed to have it, like a libc, that's what I mean).

Would it be possible to move my g_get_monotonic_time code into gettime in gthread.c, and then make g_get_monotonic_time use g_thread_gettime, if available?
At least I have used a monotonic clock for the Windows implementation (I have never tested it though, I only used the MSDN documentation I found on the web). The POSIX/librt implementation already seems to be in gthread-posix.c, but I can't find anything that actually compiles it in the Makefile. Maybe it's just hidden in some of the variables defined by autotools? I tried to link in gthread in my application but it would still not use clock_gettime (no break in debugger). Maybe because I never called g_thread_init? I have to try that too later.

I really think glib should have an interface to monotonic time. But I think it's a bit weird if it's only available if you want to use threads (it makes no sense to me, at least). I mean, pulling in one or a few more dependencies that are system libraries anyway, what harm could it do? (That's a question, not a challenge)
But if that's how it has to be, fine with me. Better than nothing.

By the way, the offset function for GTimer that I wrote doesn't depend on the monotonic time patches.
Comment 8 Matthias Clasen 2008-07-02 16:17:00 UTC
I've committed the g_get_current_time fix, the rest will need some more time.
Comment 9 Ross Burton 2009-09-16 11:23:49 UTC
As a side note I see that Maemo is using monotonic timers for g_timeout_*, neatly solving the problem of the system time changing and upsetting the scheduling.

https://stage.maemo.org/svn/maemo/projects/haf/trunk/glib/debian/patches/70_use-monotonic-clock-for-timeouts.patch is their patch.  Yes, this adds -rt to libglib.
Comment 10 Christian Dywan 2009-10-08 11:06:01 UTC
Created attachment 145031 [details] [review]
Use librt regardless of threading

This changes configure.in to use librt independent from threading.
Comment 11 Christian Dywan 2009-10-08 11:33:32 UTC
Created attachment 145033 [details] [review]
get_monotonic_time, with Since

Updated patch with Since tag. I think it would be great to get this API. As mentioned, in Maemo it is used internally in Glib and proved very useful. Otherwise application code would have to be rewritten to not use Glib API for timing functions.

I wonder, is it useful to use a new GTimeSpec instead of GTimeVal?

The above configue.in change is require to be able to compile this.
Comment 12 Christian Dywan 2009-10-08 15:15:50 UTC
http://lanedo.com/~christian/monotonic-clocks-for-timeout.diff

This is an adapted version of the Maemo patch, based on the patches 145031 and 145033. I don't know if GTimeSpec should/ will be introduced so for now I left the code with GTimeVal with a conversion function.

For some reason bugzilla insists the file is empty, so I uploaded it elsewhere for now. :-/
Comment 13 Patrik Olsson 2009-10-08 21:16:28 UTC
(In reply to comment #11)
> 
> I wonder, is it useful to use a new GTimeSpec instead of GTimeVal?
> 

Well, the difference is that GTimeSpec allows 1000 times better precision (i.e. down to nanoseconds), as you probably know. Maybe an alternative is adding another field to GTimeVal for millionths of microseconds? But maybe that will be ABI/API incompatible, though? But if it is possible then g_get_current_time could also be changed to return with the higher precision.

New file systems (e.g. ext4) have nanosecond precision on timestamps. The librt API returns up to nanosecond precision (if hardware supports it). On the other hand, I think most applications that really need better than microsecond precision need it guaranteed, and thus would probably not use GLib anyway.

Oh, and another thing. Please note that the Windows code in my patch (which is also in your patch) is not tested.
Comment 14 Christian Dywan 2010-02-01 12:51:32 UTC
Created attachment 152724 [details] [review]
Implement g_get_monotonic_time/ g_has_monotonic_clock/ GTimeSpec

Picking up the original patch from Patrik again, with GTimeSpec, g_get_monotonic_time and g_has_monotonic_clock. I added an explicit comment that precision may only be milliseconds.
Comment 15 Christian Dywan 2010-02-01 12:57:37 UTC
Created attachment 152725 [details] [review]
Timeouts based on monotonic time 

This  is the patch from Maemo to make timeouts use monotonic time, but with GTimeSpec. You need to apply the previous patch for this one to work.
Comment 16 Christian Dywan 2010-04-15 23:39:00 UTC
*** Bug 615871 has been marked as a duplicate of this bug. ***
Comment 17 Christian Dywan 2010-08-24 15:52:02 UTC
*** Bug 627655 has been marked as a duplicate of this bug. ***
Comment 18 Christian Dywan 2010-10-27 16:48:05 UTC
Apparently the same is being implemented in a branch meanwhile:

http://git.gnome.org/browse/glib/log/?h=wip/monotonic
Comment 19 Allison Karlitskaya (desrt) 2010-10-27 19:17:05 UTC
I made that branch while at the hackfest.  I landed it all this morning.

I had no idea this bug was open.  Sorry for the duplicated effort.  I discussed it on the mailing list first and nobody mentioned this work:

http://mail.gnome.org/archives/gtk-devel-list/2010-October/msg00185.html


It seems that all that is left is the timer work.
Comment 20 Allison Karlitskaya (desrt) 2012-01-19 02:41:06 UTC
fixed long ago