From bb8f296d45721629c97f5283e08077829de6c206 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Mar 2009 11:37:12 +0100 Subject: [PATCH] clock: use seqlocks to parallellize readers --- docs/gst/gstreamer-sections.txt | 1 + gst/gstclock.c | 105 +++++++++++++++++++++++++++++----------- gst/gstclock.h | 5 +- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 1aacedf..e06b618 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -414,6 +414,7 @@ GST_TYPE_CLOCK_FLAGS GST_TYPE_CLOCK_RETURN GST_TYPE_CLOCK_TIME +GstClockPrivate GST_CLOCK_SLAVE_LOCK GST_CLOCK_SLAVE_UNLOCK gst_clock_get_type diff --git a/gst/gstclock.c b/gst/gstclock.c index afc3df8..8618f04 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -132,6 +132,41 @@ enum PROP_TIMEOUT }; +struct _GstClockPrivate +{ + gint pre_count; + gint post_count; +}; + +/* seqlocks */ +#define read_seqbegin(clock) \ + g_atomic_int_get (&clock->priv->post_count); + +static inline gboolean +read_seqretry (GstClock * clock, gint seq) +{ + /* no retry if the seqnum did not change */ + if (G_LIKELY (seq == g_atomic_int_get (&clock->priv->pre_count))) + return FALSE; + + /* wait for the writer to finish and retry */ + GST_OBJECT_LOCK (clock); + GST_OBJECT_UNLOCK (clock); + return TRUE; +} + +#define write_seqlock(clock) \ +G_STMT_START { \ + GST_OBJECT_LOCK (clock); \ + g_atomic_int_inc (&clock->priv->pre_count); \ +} G_STMT_END; + +#define write_sequnlock(clock) \ +G_STMT_START { \ + g_atomic_int_inc (&clock->priv->post_count); \ + GST_OBJECT_UNLOCK (clock); \ +} G_STMT_END; + static void gst_clock_class_init (GstClockClass * klass); static void gst_clock_init (GstClock * clock); static void gst_clock_dispose (GObject * object); @@ -404,7 +439,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter) if (entry->type == GST_CLOCK_ENTRY_PERIODIC) entry->time = requested + entry->interval; - if (clock->stats) + if (G_UNLIKELY (clock->stats)) gst_clock_update_stats (clock); return res; @@ -560,6 +595,8 @@ gst_clock_class_init (GstClockClass * klass) "The amount of time, in nanoseconds, to sample master and slave clocks", 0, G_MAXUINT64, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private (klass, sizeof (GstClockPrivate)); } static void @@ -570,6 +607,9 @@ gst_clock_init (GstClock * clock) clock->entries_changed = g_cond_new (); clock->stats = FALSE; + clock->priv = + G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate); + clock->internal_calibration = 0; clock->external_calibration = 0; clock->rate_numerator = 1; @@ -701,7 +741,7 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal) cdenom = clock->rate_denominator; /* avoid divide by 0 */ - if (cdenom == 0) + if (G_UNLIKELY (cdenom == 0)) cnum = cdenom = 1; /* The formula is (internal - cinternal) * cnum / cdenom + cexternal @@ -711,12 +751,14 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal) * though. */ if (G_LIKELY (internal >= cinternal)) { - ret = gst_util_uint64_scale (internal - cinternal, cnum, cdenom); + ret = internal - cinternal; + ret = gst_util_uint64_scale (ret, cnum, cdenom); ret += cexternal; } else { - ret = gst_util_uint64_scale (cinternal - internal, cnum, cdenom); + ret = cinternal - internal; + ret = gst_util_uint64_scale (ret, cnum, cdenom); /* clamp to 0 */ - if (cexternal > ret) + if (G_LIKELY (cexternal > ret)) ret = cexternal - ret; else ret = 0; @@ -756,16 +798,18 @@ gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external) cdenom = clock->rate_denominator; /* avoid divide by 0 */ - if (cnum == 0) + if (G_UNLIKELY (cnum == 0)) cnum = cdenom = 1; /* The formula is (external - cexternal) * cdenom / cnum + cinternal */ - if (external >= cexternal) { - ret = gst_util_uint64_scale (external - cexternal, cdenom, cnum); + if (G_LIKELY (external >= cexternal)) { + ret = external - cexternal; + ret = gst_util_uint64_scale (ret, cdenom, cnum); ret += cinternal; } else { - ret = gst_util_uint64_scale (cexternal - external, cdenom, cnum); - if (cinternal > ret) + ret = cexternal - external; + ret = gst_util_uint64_scale (ret, cdenom, cnum); + if (G_LIKELY (cinternal > ret)) ret = cinternal - ret; else ret = 0; @@ -831,15 +875,19 @@ GstClockTime gst_clock_get_time (GstClock * clock) { GstClockTime ret; + gint seq; g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE); - ret = gst_clock_get_internal_time (clock); + do { + /* reget the internal time when we retry to get the most current + * timevalue */ + ret = gst_clock_get_internal_time (clock); - GST_OBJECT_LOCK (clock); - /* this will scale for rate and offset */ - ret = gst_clock_adjust_unlocked (clock, ret); - GST_OBJECT_UNLOCK (clock); + seq = read_seqbegin (clock); + /* this will scale for rate and offset */ + ret = gst_clock_adjust_unlocked (clock, ret); + } while (read_seqretry (clock, seq)); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT, GST_TIME_ARGS (ret)); @@ -889,7 +937,7 @@ gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE); g_return_if_fail (internal <= gst_clock_get_internal_time (clock)); - GST_OBJECT_LOCK (clock); + write_seqlock (clock); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal), @@ -900,7 +948,7 @@ gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime clock->external_calibration = external; clock->rate_numerator = rate_num; clock->rate_denominator = rate_denom; - GST_OBJECT_UNLOCK (clock); + write_sequnlock (clock); } /** @@ -923,18 +971,21 @@ void gst_clock_get_calibration (GstClock * clock, GstClockTime * internal, GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom) { + gint seq; + g_return_if_fail (GST_IS_CLOCK (clock)); - GST_OBJECT_LOCK (clock); - if (rate_num) - *rate_num = clock->rate_numerator; - if (rate_denom) - *rate_denom = clock->rate_denominator; - if (external) - *external = clock->external_calibration; - if (internal) - *internal = clock->internal_calibration; - GST_OBJECT_UNLOCK (clock); + do { + seq = read_seqbegin (clock); + if (rate_num) + *rate_num = clock->rate_numerator; + if (rate_denom) + *rate_denom = clock->rate_denominator; + if (external) + *external = clock->external_calibration; + if (internal) + *internal = clock->internal_calibration; + } while (read_seqretry (clock, seq)); } /* will be called repeatedly to sample the master and slave clock diff --git a/gst/gstclock.h b/gst/gstclock.h index 4ce1bcd..637d351 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -235,6 +235,7 @@ G_STMT_START { \ typedef struct _GstClockEntry GstClockEntry; typedef struct _GstClock GstClock; typedef struct _GstClockClass GstClockClass; +typedef struct _GstClockPrivate GstClockPrivate; /* --- prototype for async callbacks --- */ /** @@ -447,7 +448,9 @@ struct _GstClock { GstClockID clockid; /*< private >*/ - GstClockTime _gst_reserved[GST_PADDING]; + GstClockPrivate *priv; + + GstClockTime _gst_reserved[GST_PADDING-1]; }; /** -- 2.7.4