mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Test recursive mutex code more
This commit is contained in:
parent
d50d954a3c
commit
95fee8614d
4 changed files with 95 additions and 11 deletions
|
@ -2,17 +2,33 @@
|
||||||
#define COSMOPOLITAN_LIBC_THREAD_LOCK_H_
|
#define COSMOPOLITAN_LIBC_THREAD_LOCK_H_
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
#define MUTEX_DEPTH_MIN 0x00000010ull
|
//
|
||||||
#define MUTEX_DEPTH_MAX 0x000003f0ull
|
// ┌depth
|
||||||
|
// │
|
||||||
|
// COSMOPOLITAN MUTEXES │ ┌waited
|
||||||
|
// │ │
|
||||||
|
// │ │┌locked
|
||||||
|
// │ ││
|
||||||
|
// │ ││┌pshared
|
||||||
|
// owner │ │││
|
||||||
|
// tid │ │││┌type
|
||||||
|
// │ │ ││││
|
||||||
|
// ┌──────────────┴───────────────┐ ┌─┴──┐│││├┐
|
||||||
|
// 0b0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
|
||||||
|
#define MUTEX_DEPTH_MIN 0x00000020ull
|
||||||
|
#define MUTEX_DEPTH_MAX 0x000007e0ull
|
||||||
|
|
||||||
#define MUTEX_TYPE(word) ((word) & 3)
|
#define MUTEX_TYPE(word) ((word) & 3)
|
||||||
#define MUTEX_PSHARED(word) ((word) & 4)
|
#define MUTEX_PSHARED(word) ((word) & 4)
|
||||||
#define MUTEX_LOCKED(word) ((word) & 8)
|
#define MUTEX_LOCKED(word) ((word) & 8)
|
||||||
|
#define MUTEX_WAITED(word) ((word) & 16)
|
||||||
#define MUTEX_DEPTH(word) ((word) & MUTEX_DEPTH_MAX)
|
#define MUTEX_DEPTH(word) ((word) & MUTEX_DEPTH_MAX)
|
||||||
#define MUTEX_OWNER(word) ((word) >> 32)
|
#define MUTEX_OWNER(word) ((word) >> 32)
|
||||||
|
|
||||||
#define MUTEX_LOCK(word) (((word) & 7) | 8)
|
#define MUTEX_LOCK(word) (((word) & 7) | 8)
|
||||||
#define MUTEX_UNLOCK(word) ((word) & 7)
|
#define MUTEX_UNLOCK(word) ((word) & 7)
|
||||||
|
#define MUTEX_SET_WAITED(word) ((word) | 16)
|
||||||
#define MUTEX_SET_TYPE(word, type) (((word) & ~3ull) | (type))
|
#define MUTEX_SET_TYPE(word, type) (((word) & ~3ull) | (type))
|
||||||
#define MUTEX_SET_PSHARED(word, pshared) (((word) & ~4ull) | (pshared))
|
#define MUTEX_SET_PSHARED(word, pshared) (((word) & ~4ull) | (pshared))
|
||||||
#define MUTEX_INC_DEPTH(word) ((word) + MUTEX_DEPTH_MIN)
|
#define MUTEX_INC_DEPTH(word) ((word) + MUTEX_DEPTH_MIN)
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct pthread_mutex_s {
|
||||||
int32_t _pid;
|
int32_t _pid;
|
||||||
_PTHREAD_ATOMIC(int32_t) _futex;
|
_PTHREAD_ATOMIC(int32_t) _futex;
|
||||||
};
|
};
|
||||||
|
/* this cleverly overlaps with NSYNC struct Dll *waiters; */
|
||||||
_PTHREAD_ATOMIC(uint64_t) _word;
|
_PTHREAD_ATOMIC(uint64_t) _word;
|
||||||
} pthread_mutex_t;
|
} pthread_mutex_t;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#define USE POSIX
|
#define USE POSIX
|
||||||
#define ITERATIONS 50000
|
#define ITERATIONS 100000
|
||||||
#define THREADS 10
|
#define THREADS 30
|
||||||
// #define ITERATIONS 100000
|
|
||||||
// #define THREADS 30
|
|
||||||
|
|
||||||
#define SPIN 1
|
#define SPIN 1
|
||||||
#define FUTEX 2
|
#define FUTEX 2
|
||||||
#define POSIX 3
|
#define POSIX 3
|
||||||
|
#define POSIX_RECURSIVE 4
|
||||||
|
|
||||||
#ifdef __COSMOPOLITAN__
|
#ifdef __COSMOPOLITAN__
|
||||||
#include <cosmo.h>
|
#include <cosmo.h>
|
||||||
|
#include "libc/thread/thread.h"
|
||||||
#include "third_party/nsync/futex.internal.h"
|
#include "third_party/nsync/futex.internal.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -278,6 +278,8 @@ void lock(atomic_int *futex) {
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||||
#if USE == FUTEX
|
#if USE == FUTEX
|
||||||
nsync_futex_wait_(futex, 2, 0, 0, 0);
|
nsync_futex_wait_(futex, 2, 0, 0, 0);
|
||||||
|
#else
|
||||||
|
pthread_yield_np();
|
||||||
#endif
|
#endif
|
||||||
pthread_setcancelstate(cs, 0);
|
pthread_setcancelstate(cs, 0);
|
||||||
word = atomic_exchange_explicit(futex, 2, memory_order_acquire);
|
word = atomic_exchange_explicit(futex, 2, memory_order_acquire);
|
||||||
|
@ -296,11 +298,11 @@ void unlock(atomic_int *futex) {
|
||||||
|
|
||||||
int g_chores;
|
int g_chores;
|
||||||
atomic_int g_lock;
|
atomic_int g_lock;
|
||||||
pthread_mutex_t g_locker = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t g_locker;
|
||||||
|
|
||||||
void *worker(void *arg) {
|
void *worker(void *arg) {
|
||||||
for (int i = 0; i < ITERATIONS; ++i) {
|
for (int i = 0; i < ITERATIONS; ++i) {
|
||||||
#if USE == POSIX
|
#if USE == POSIX || USE == POSIX_RECURSIVE
|
||||||
pthread_mutex_lock(&g_locker);
|
pthread_mutex_lock(&g_locker);
|
||||||
++g_chores;
|
++g_chores;
|
||||||
pthread_mutex_unlock(&g_locker);
|
pthread_mutex_unlock(&g_locker);
|
||||||
|
@ -331,6 +333,17 @@ int main() {
|
||||||
struct timeval start;
|
struct timeval start;
|
||||||
gettimeofday(&start, 0);
|
gettimeofday(&start, 0);
|
||||||
|
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
#if USE == POSIX_RECURSIVE
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
#else
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||||
|
#endif
|
||||||
|
pthread_mutex_init(&g_locker, &attr);
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
|
||||||
pthread_t th[THREADS];
|
pthread_t th[THREADS];
|
||||||
for (int i = 0; i < THREADS; ++i)
|
for (int i = 0; i < THREADS; ++i)
|
||||||
pthread_create(&th[i], 0, worker, 0);
|
pthread_create(&th[i], 0, worker, 0);
|
||||||
|
@ -349,6 +362,8 @@ int main() {
|
||||||
tomicros(ru.ru_utime), //
|
tomicros(ru.ru_utime), //
|
||||||
tomicros(ru.ru_stime));
|
tomicros(ru.ru_stime));
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&lock);
|
||||||
|
|
||||||
#ifdef __COSMOPOLITAN__
|
#ifdef __COSMOPOLITAN__
|
||||||
CheckForMemoryLeaks();
|
CheckForMemoryLeaks();
|
||||||
#endif
|
#endif
|
||||||
|
|
52
third_party/nsync/testing/mu_test.c
vendored
52
third_party/nsync/testing/mu_test.c
vendored
|
@ -177,6 +177,41 @@ static void test_mutex_nthread (testing t) {
|
||||||
} while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0);
|
} while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a few threads, each of which increments an integer a fixed
|
||||||
|
number of times, using a recursive pthread_mutex_t for mutual exclusion.
|
||||||
|
It checks that the integer is incremented the correct number of times. */
|
||||||
|
static void test_xmutex_nthread (testing t) {
|
||||||
|
int loop_count = 100000;
|
||||||
|
nsync_time deadline;
|
||||||
|
deadline = nsync_time_add (nsync_time_now (NSYNC_CLOCK), nsync_time_ms (1500));
|
||||||
|
do {
|
||||||
|
int i;
|
||||||
|
test_data td;
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
bzero ((void *) &td, sizeof (td));
|
||||||
|
td.t = t;
|
||||||
|
td.n_threads = 5;
|
||||||
|
td.loop_count = loop_count;
|
||||||
|
td.mu_in_use = &td.mutex;
|
||||||
|
td.lock = &void_pthread_mutex_lock;
|
||||||
|
td.unlock = &void_pthread_mutex_unlock;
|
||||||
|
pthread_mutexattr_init (&attr);
|
||||||
|
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init (&td.mutex, &attr);
|
||||||
|
pthread_mutexattr_destroy (&attr);
|
||||||
|
for (i = 0; i != td.n_threads; i++) {
|
||||||
|
closure_fork (closure_counting (&counting_loop, &td, i));
|
||||||
|
}
|
||||||
|
test_data_wait_for_all_threads (&td);
|
||||||
|
if (td.i != td.n_threads*td.loop_count) {
|
||||||
|
TEST_FATAL (t, ("test_mutex_nthread final count inconsistent: want %d, got %d",
|
||||||
|
td.n_threads*td.loop_count, td.i));
|
||||||
|
}
|
||||||
|
pthread_mutex_destroy (&td.mutex);
|
||||||
|
loop_count *= 2;
|
||||||
|
} while (nsync_time_cmp (nsync_time_now (NSYNC_CLOCK), deadline) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* void pthread_rwlock_wrlock */
|
/* void pthread_rwlock_wrlock */
|
||||||
static void void_pthread_rwlock_wrlock (void *mu) {
|
static void void_pthread_rwlock_wrlock (void *mu) {
|
||||||
pthread_rwlock_wrlock ((pthread_rwlock_t *) mu);
|
pthread_rwlock_wrlock ((pthread_rwlock_t *) mu);
|
||||||
|
@ -1040,6 +1075,21 @@ static void benchmark_mutex_contended (testing t) {
|
||||||
pthread_mutex_destroy (&cs.mutex);
|
pthread_mutex_destroy (&cs.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Measure the performance of highly contended recursive
|
||||||
|
pthread_mutex_t locks, with small critical sections. */
|
||||||
|
static void benchmark_xmutex_contended (testing t) {
|
||||||
|
contended_state cs;
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
bzero ((void *) &cs, sizeof (cs));
|
||||||
|
pthread_mutexattr_init (&attr);
|
||||||
|
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init (&cs.mutex, &attr);
|
||||||
|
pthread_mutexattr_destroy (&attr);
|
||||||
|
contended_state_run_test (&cs, t, &cs.mutex, &void_pthread_mutex_lock,
|
||||||
|
&void_pthread_mutex_unlock);
|
||||||
|
pthread_mutex_destroy (&cs.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/* Measure the performance of highly contended
|
/* Measure the performance of highly contended
|
||||||
pthread_rwlock_t locks, with small critical sections. */
|
pthread_rwlock_t locks, with small critical sections. */
|
||||||
static void benchmark_wmutex_contended (testing t) {
|
static void benchmark_wmutex_contended (testing t) {
|
||||||
|
@ -1057,11 +1107,13 @@ int main (int argc, char *argv[]) {
|
||||||
TEST_RUN (tb, test_rlock);
|
TEST_RUN (tb, test_rlock);
|
||||||
TEST_RUN (tb, test_mu_nthread);
|
TEST_RUN (tb, test_mu_nthread);
|
||||||
TEST_RUN (tb, test_mutex_nthread);
|
TEST_RUN (tb, test_mutex_nthread);
|
||||||
|
TEST_RUN (tb, test_xmutex_nthread);
|
||||||
TEST_RUN (tb, test_rwmutex_nthread);
|
TEST_RUN (tb, test_rwmutex_nthread);
|
||||||
TEST_RUN (tb, test_try_mu_nthread);
|
TEST_RUN (tb, test_try_mu_nthread);
|
||||||
|
|
||||||
BENCHMARK_RUN (tb, benchmark_mu_contended);
|
BENCHMARK_RUN (tb, benchmark_mu_contended);
|
||||||
BENCHMARK_RUN (tb, benchmark_mutex_contended);
|
BENCHMARK_RUN (tb, benchmark_mutex_contended);
|
||||||
|
BENCHMARK_RUN (tb, benchmark_xmutex_contended);
|
||||||
BENCHMARK_RUN (tb, benchmark_wmutex_contended);
|
BENCHMARK_RUN (tb, benchmark_wmutex_contended);
|
||||||
|
|
||||||
BENCHMARK_RUN (tb, benchmark_mu_uncontended);
|
BENCHMARK_RUN (tb, benchmark_mu_uncontended);
|
||||||
|
|
Loading…
Reference in a new issue