[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