[Mesa-dev] [RFC 1/3] mesa: Add new fast mtx_t mutex type for basic use cases

Nicolai Hähnle nhaehnle at gmail.com
Tue Oct 10 16:30:31 UTC 2017


On 10.10.2017 04:45, Timothy Arceri wrote:
> While modern pthread mutexes are very fast, they still incur a call to an
> external DSO and overhead of the generality and features of pthread mutexes.
> Most mutexes in mesa only needs lock/unlock, and the idea here is that we can
> inline the atomic operation and make the fast case just two intructions.
> Mutexes are subtle and finicky to implement, so we carefully copy the
> implementation from Ulrich Dreppers well-written and well-reviewed paper:
> 
>    "Futexes Are Tricky"
>    http://www.akkadia.org/drepper/futex.pdf
> 
> We implement "mutex3", which gives us a mutex that has no syscalls on
> uncontended lock or unlock.  Further, the uncontended case boils down to a
> cmpxchg and an untaken branch and the uncontended unlock is just a locked decr
> and an untaken branch.  We use __builtin_expect() to indicate that contention
> is unlikely so that gcc will put the contention code out of the main code
> flow.
> 
> A fast mutex only supports lock/unlock, can't be recursive or used with
> condition variables.  We keep the pthread mutex implementation around as
> full_mtx_t for the few places where we use condition variables or recursive
> locking.  For platforms or compilers where futex and atomics aren't available,
> mtx_t falls back to the pthread mutex.
> 
> The pthread mutex lock/unlock overhead shows up on benchmarks for CPU bound
> applications.  Most CPU bound cases are helped and some of our internal
> bind_buffer_object heavy benchmarks gain up to 10%.
> 
> Signed-off-by: Kristian Høgsberg <krh at bitplanet.net>
> Signed-off-by: Timothy Arceri <tarceri at itsqueeze.com>
> ---
>   configure.ac          |   3 ++
>   src/util/simple_mtx.h | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++

Add to util/Makefile.sources


[snip]
> +static inline void
> +simple_mtx_init(simple_mtx_t *mtx, int type)
> +{
> +   assert(type == mtx_plain);

mtx_plain is undefined here.

Cheers,
Nicolai

> +
> +   mtx->val = 0;
> +}
> +
> +static inline void
> +simple_mtx_destroy(simple_mtx_t *mtx)
> +{
> +}
> +
> +static inline void
> +simple_mtx_lock(simple_mtx_t *mtx)
> +{
> +   uint32_t c;
> +
> +   c = __sync_val_compare_and_swap(&mtx->val, 0, 1);
> +   if (__builtin_expect(c != 0, 0)) {
> +      if (c != 2)
> +         c = __sync_lock_test_and_set(&mtx->val, 2);
> +      while (c != 0) {
> +         futex_wait(&mtx->val, 2);
> +         c = __sync_lock_test_and_set(&mtx->val, 2);
> +      }
> +   }
> +}
> +
> +static inline void
> +simple_mtx_unlock(simple_mtx_t *mtx)
> +{
> +   uint32_t c;
> +
> +   c = __sync_fetch_and_sub(&mtx->val, 1);
> +   if (__builtin_expect(c != 1, 0)) {
> +      mtx->val = 0;
> +      futex_wake(&mtx->val);
> +   }
> +}
> +
> +#else
> +
> +typedef simple_mtx_t mtx_t;
> +
> +#define _SIMPLE_MTX_INITIALIZER_NP _MTX_INITIALIZER_NP
> +
> +static inline void
> +simple_mtx_init(simple_mtx_t *mtx, int type)
> +{
> +   mtx_init(mtx, type);
> +}
> +
> +static inline void
> +simple_mtx_destroy(simple_mtx_t *mtx)
> +{
> +   mtx_destroy(mtx);
> +}
> +
> +static inline void
> +simple_mtx_lock(simple_mtx_t *mtx)
> +{
> +   mtx_lock(mtx);
> +}
> +
> +static inline void
> +simple_mtx_unlock(simple_mtx_t *mtx)
> +{
> +   mtx_unlock(mtx);
> +}
> +
> +#endif
> 


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list