clock: use seqlocks to parallellize readers

This commit is contained in:
Wim Taymans 2009-03-19 11:37:12 +01:00
parent f83809cf37
commit bb8f296d45
3 changed files with 83 additions and 28 deletions

View file

@ -414,6 +414,7 @@ GST_TYPE_CLOCK_FLAGS
GST_TYPE_CLOCK_RETURN
GST_TYPE_CLOCK_TIME
<SUBSECTION Private>
GstClockPrivate
GST_CLOCK_SLAVE_LOCK
GST_CLOCK_SLAVE_UNLOCK
gst_clock_get_type

View file

@ -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

View file

@ -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];
};
/**