diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-08-31 21:33:58 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-09-27 11:57:30 +0200 |
commit | c265e976f4669fd65f5b47e6865f50d1cb66bd02 (patch) | |
tree | b80f5c8500bd6ad92ee0474bce2b4186dd2540c5 /docs | |
parent | 3359baad36889b83df40b637ed993a4b816c4906 (diff) |
cpus-common: lock-free fast path for cpu_exec_start/end
Set cpu->running without taking the cpu_list lock, only requiring it if
there is a concurrent exclusive section. This requires adding a new
field to CPUState, which records whether a running CPU is being counted
in pending_cpus.
When an exclusive section is started concurrently with cpu_exec_start,
cpu_exec_start can use the new field to determine if it has to wait for
the end of the exclusive section. Likewise, cpu_exec_end can use it to
see if start_exclusive is waiting for that CPU.
This a separate patch for easier bisection of issues.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'docs')
-rw-r--r-- | docs/tcg-exclusive.promela | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/docs/tcg-exclusive.promela b/docs/tcg-exclusive.promela index feac679b9a..c91cfca9f7 100644 --- a/docs/tcg-exclusive.promela +++ b/docs/tcg-exclusive.promela @@ -13,7 +13,8 @@ * gcc pan.c -O2 * ./a.out -a * - * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, TEST_EXPENSIVE. + * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, USE_MUTEX, + * TEST_EXPENSIVE. */ // Define the missing parameters for the model @@ -22,8 +23,10 @@ #warning defaulting to 2 CPU processes #endif -// the expensive test is not so expensive for <= 3 CPUs -#if N_CPUS <= 3 +// the expensive test is not so expensive for <= 2 CPUs +// If the mutex is used, it's also cheap (300 MB / 4 seconds) for 3 CPUs +// For 3 CPUs and the lock-free option it needs 1.5 GB of RAM +#if N_CPUS <= 2 || (N_CPUS <= 3 && defined USE_MUTEX) #define TEST_EXPENSIVE #endif @@ -107,6 +110,8 @@ byte has_waiter[N_CPUS]; COND_BROADCAST(exclusive_resume); \ MUTEX_UNLOCK(mutex); +#ifdef USE_MUTEX +// Simple version using mutexes #define cpu_exec_start(id) \ MUTEX_LOCK(mutex); \ exclusive_idle(); \ @@ -127,6 +132,48 @@ byte has_waiter[N_CPUS]; :: else -> skip; \ fi; \ MUTEX_UNLOCK(mutex); +#else +// Wait-free fast path, only needs mutex when concurrent with +// an exclusive section +#define cpu_exec_start(id) \ + running[id] = 1; \ + if \ + :: pending_cpus -> { \ + MUTEX_LOCK(mutex); \ + if \ + :: !has_waiter[id] -> { \ + running[id] = 0; \ + exclusive_idle(); \ + running[id] = 1; \ + } \ + :: else -> skip; \ + fi; \ + MUTEX_UNLOCK(mutex); \ + } \ + :: else -> skip; \ + fi; + +#define cpu_exec_end(id) \ + running[id] = 0; \ + if \ + :: pending_cpus -> { \ + MUTEX_LOCK(mutex); \ + if \ + :: has_waiter[id] -> { \ + has_waiter[id] = 0; \ + pending_cpus--; \ + if \ + :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \ + :: else -> skip; \ + fi; \ + } \ + :: else -> skip; \ + fi; \ + MUTEX_UNLOCK(mutex); \ + } \ + :: else -> skip; \ + fi +#endif // Promela processes |