gst: clock: Clean up code to get the monotonic / realtime clock a bit

On Windows and macOS always use the proper monotonic clock, including
for gst_util_get_timestamp(), and initialize its state only once.

Also on macOS use clock_gettime() for the realtime clock, if available
instead of always falling back to GLib.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4658>
This commit is contained in:
Sebastian Dröge 2023-05-17 14:44:24 +03:00 committed by GStreamer Marge Bot
parent a8bf19deda
commit c52212604e
4 changed files with 146 additions and 96 deletions

View file

@ -534,6 +534,8 @@ init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
return TRUE;
}
priv_gst_clock_init ();
find_executable_path ();
_priv_gst_start_time = gst_util_get_timestamp ();

View file

@ -522,5 +522,9 @@ struct _GstClockEntryImpl
char * priv_gst_get_relocated_libgstreamer (void);
gint priv_gst_count_directories (const char *filepath);
void priv_gst_clock_init (void);
GstClockTime priv_gst_get_monotonic_time (void);
GstClockTime priv_gst_get_real_time (void);
G_END_DECLS
#endif /* __GST_PRIVATE_H__ */

View file

@ -60,6 +60,108 @@
#include <mach/mach_time.h>
#endif
#if defined __APPLE__
static struct mach_timebase_info mach_timebase;
#endif
#if defined G_OS_WIN32
static LARGE_INTEGER performance_counter_frequency;
#endif
/* Small helper to make the atomics below cheaper.
*
* GLib always uses SEQ_CST atomic ops while here it's more than enough to use
* ACQUIRE/RELEASE atomic ops. On x86 / x86-64 the ACQUIRE load is compiling
* to a simple memory read.
*/
#if defined __APPLE__ || defined G_OS_WIN32
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS)
#include <stdatomic.h>
typedef atomic_int gst_atomic_int;
static inline int
gst_atomic_int_get_acquire (gst_atomic_int * x)
{
return atomic_load_explicit (x, memory_order_acquire);
}
static inline void
gst_atomic_int_set_release (gst_atomic_int * x, gint val)
{
atomic_store_explicit (x, val, memory_order_release);
}
#else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS) */
typedef int gst_atomic_int;
#define gst_atomic_int_get_acquire(x) g_atomic_int_get(x)
#define gst_atomic_int_set_release(x, val) g_atomic_int_set(x, val)
#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS) */
#endif /* defined __APPLE__ || defined G_OS_WIN32 */
/* priv_gst_clock_init:
*
* Initialize internal state of the clock. This is safe to call multiple
* times.
*/
void
priv_gst_clock_init (void)
{
#if defined __APPLE__
static gst_atomic_int inited = FALSE;
if (!gst_atomic_int_get_acquire (&inited)) {
mach_timebase_info (&mach_timebase);
gst_atomic_int_set_release (&inited, TRUE);
}
#endif
#if defined G_OS_WIN32
static gst_atomic_int inited = FALSE;
if (!gst_atomic_int_get_acquire (&inited)) {
QueryPerformanceFrequency (&performance_counter_frequency);
gst_atomic_int_set_release (&inited, TRUE);
}
#endif
}
GstClockTime
priv_gst_get_monotonic_time (void)
{
#if defined __APPLE__
guint64 mach_t = mach_absolute_time ();
return gst_util_uint64_scale (mach_t, mach_timebase.numer,
mach_timebase.denom);
#elif defined G_OS_WIN32
LARGE_INTEGER now;
QueryPerformanceCounter (&now);
return gst_util_uint64_scale (now.QuadPart, GST_SECOND,
performance_counter_frequency.QuadPart);
#elif defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
defined (HAVE_CLOCK_GETTIME)
struct timespec now;
clock_gettime (CLOCK_MONOTONIC, &now);
return GST_TIMESPEC_TO_TIME (now);
#else
return g_get_monotonic_time () * 1000;
#endif
}
GstClockTime
priv_gst_get_real_time (void)
{
#if defined (HAVE_POSIX_TIMERS) && defined (HAVE_CLOCK_GETTIME)
struct timespec now;
clock_gettime (CLOCK_REALTIME, &now);
return GST_TIMESPEC_TO_TIME (now);
#else
return g_get_real_time () * 1000;
#endif
}
/* Define this to get some extra debug about jitter from each clock_wait */
#undef WAIT_DEBUGGING
@ -300,7 +402,7 @@ gst_pthread_cond_wait_until (pthread_cond_t * cond, pthread_mutex_t * lock,
* Since this pthreads wants the relative time, convert it back again.
*/
{
gint64 now = g_get_monotonic_time () * 1000;
gint64 now = priv_gst_get_monotonic_time ();
gint64 relative;
if (end_time <= now)
@ -446,13 +548,6 @@ struct _GstSystemClockPrivate
GCond entries_changed;
GstClockType clock_type;
#ifdef G_OS_WIN32
LARGE_INTEGER frequency;
#endif /* G_OS_WIN32 */
#ifdef __APPLE__
struct mach_timebase_info mach_timebase;
#endif
};
#ifdef HAVE_POSIX_TIMERS
@ -483,10 +578,6 @@ static void gst_system_clock_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
static GstClockTime gst_system_clock_get_mono_time (GstSystemClock * clock);
static GstClockTime gst_system_clock_get_real_time ();
#endif
static guint64 gst_system_clock_get_resolution (GstClock * clock);
static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
GstClockEntry * entry, GstClockTimeDiff * jitter);
@ -551,14 +642,6 @@ gst_system_clock_init (GstSystemClock * clock)
priv->entries = NULL;
g_cond_init (&priv->entries_changed);
#ifdef G_OS_WIN32
QueryPerformanceFrequency (&priv->frequency);
#endif /* G_OS_WIN32 */
#ifdef __APPLE__
mach_timebase_info (&priv->mach_timebase);
#endif
#if 0
/* Uncomment this to start the async clock thread straight away */
GST_SYSTEM_CLOCK_LOCK (clock);
@ -909,7 +992,6 @@ clock_type_to_posix_id (GstClockType clock_type)
#ifdef HAVE_MONOTONIC_CLOCK
if (clock_type == GST_CLOCK_TYPE_MONOTONIC)
return CLOCK_MONOTONIC;
else
#endif
if (clock_type == GST_CLOCK_TYPE_TAI)
#ifdef CLOCK_TAI
@ -927,6 +1009,16 @@ static GstClockTime
gst_system_clock_get_internal_time (GstClock * clock)
{
GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
/* For the monotonic and realtime clock, always directly call the specific
* helper functions above */
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC)
return priv_gst_get_monotonic_time ();
else if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME)
return priv_gst_get_real_time ();
/* If POSIX timers are available, use those for any other clock,
* or otherwise return the monotonic time */
#if defined HAVE_POSIX_TIMERS && defined HAVE_CLOCK_GETTIME
// BSD and Linux' Posix timers and clock_gettime cover all of the different clock types
// without need for special handling so we'll use those.
@ -939,90 +1031,49 @@ gst_system_clock_get_internal_time (GstClock * clock)
return GST_CLOCK_TIME_NONE;
return GST_TIMESPEC_TO_TIME (ts);
#else
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
return gst_system_clock_get_real_time ();
} else {
return gst_system_clock_get_mono_time (sysclock);
}
#else /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
return priv_gst_get_monotonic_time ();
#endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
}
#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
static GstClockTime
gst_system_clock_get_real_time ()
{
gint64 rt_micros = g_get_real_time ();
// g_get_real_time returns microseconds but we need nanos, so we'll multiply by 1000
return ((guint64) rt_micros) * 1000;
}
static GstClockTime
gst_system_clock_get_mono_time (GstSystemClock * sysclock)
{
#if defined __APPLE__
uint64_t mach_t = mach_absolute_time ();
return gst_util_uint64_scale (mach_t, sysclock->priv->mach_timebase.numer,
sysclock->priv->mach_timebase.denom);
#else
#if defined G_OS_WIN32
if (sysclock->priv->frequency.QuadPart != 0) {
LARGE_INTEGER now;
/* we prefer the highly accurate performance counters on windows */
QueryPerformanceCounter (&now);
return gst_util_uint64_scale (now.QuadPart,
GST_SECOND, sysclock->priv->frequency.QuadPart);
} else
#endif /* G_OS_WIN32 */
{
gint64 monotime;
monotime = g_get_monotonic_time ();
return monotime * 1000;
}
#endif /* __APPLE__ */
}
#endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
static guint64
gst_system_clock_get_resolution (GstClock * clock)
{
GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
#if defined __APPLE__ || defined G_OS_WIN32
#if defined G_OS_WIN32
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
return 1 * GST_USECOND;
} else
} else {
return GST_SECOND / performance_counter_frequency.QuadPart;
}
#endif
#if defined __APPLE__
{
// On Apple platforms we want to use mach_absolute_time() unconditionally
// for the monotonic clock even if clock_gettime() support is available.
// Only use the latter for other clock types there.
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC) {
return gst_util_uint64_scale (GST_NSECOND,
sysclock->priv->mach_timebase.numer,
sysclock->priv->mach_timebase.denom);
mach_timebase.numer, mach_timebase.denom);
}
#elif defined G_OS_WIN32
#endif
#if defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
{
if (sysclock->priv->frequency.QuadPart != 0) {
return GST_SECOND / sysclock->priv->frequency.QuadPart;
} else {
return 1 * GST_USECOND;
}
}
#elif defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
clockid_t ptype;
struct timespec ts;
struct timespec ts;
ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
if (G_UNLIKELY (clock_getres (ptype, &ts)))
return GST_CLOCK_TIME_NONE;
if (G_UNLIKELY (clock_getres (ptype, &ts)))
return GST_CLOCK_TIME_NONE;
return GST_TIMESPEC_TO_TIME (ts);
#else
return 1 * GST_USECOND;
#endif /* __APPLE__ */
return GST_TIMESPEC_TO_TIME (ts);
}
#endif /* HAVE_POSIX_TIMERS && HAVE_CLOCK_GETTIME */
return 1 * GST_USECOND;
}
/* synchronously wait on the given GstClockEntry.

View file

@ -3528,15 +3528,8 @@ gst_parse_bin_from_description_full (const gchar * bin_description,
GstClockTime
gst_util_get_timestamp (void)
{
#if defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
defined (HAVE_CLOCK_GETTIME)
struct timespec now;
clock_gettime (CLOCK_MONOTONIC, &now);
return GST_TIMESPEC_TO_TIME (now);
#else
return g_get_monotonic_time () * 1000;
#endif
priv_gst_clock_init ();
return priv_gst_get_monotonic_time ();
}
/**