Author: Remi Meier <remi.me...@gmail.com> Branch: Changeset: r1963:6397419657be Date: 2015-11-05 14:17 +0100 http://bitbucket.org/pypy/stmgc/changeset/6397419657be/
Log: emit DETACH/REATTACH events when detaching/reattaching an inevitable transaction diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -100,6 +100,8 @@ #define _stm_detach_inevitable_transaction(tl) do { \ write_fence(); \ assert(_stm_detached_inevitable_from_thread == 0); \ + if (stmcb_timing_event != NULL) \ + {stmcb_timing_event(tl, STM_TRANSACTION_DETACH, NULL);} \ _stm_detached_inevitable_from_thread = tl->self_or_0_if_atomic; \ } while (0) void _stm_reattach_transaction(intptr_t); @@ -416,69 +418,6 @@ #endif -/* Entering and leaving a "transactional code zone": a (typically very - large) section in the code where we are running a transaction. - This is the STM equivalent to "acquire the GIL" and "release the - GIL", respectively. stm_read(), stm_write(), stm_allocate(), and - other functions should only be called from within a transaction. - - Note that transactions, in the STM sense, cover _at least_ one - transactional code zone. They may be longer; for example, if one - thread does a lot of stm_enter_transactional_zone() + - stm_become_inevitable() + stm_leave_transactional_zone(), as is - typical in a thread that does a lot of C function calls, then we - get only a few bigger inevitable transactions that cover the many - short transactional zones. This is done by having - stm_leave_transactional_zone() turn the current transaction - inevitable and detach it from the running thread (if there is no - other inevitable transaction running so far). Then - stm_enter_transactional_zone() will try to reattach to it. This is - far more efficient than constantly starting and committing - transactions. - - stm_enter_transactional_zone() and stm_leave_transactional_zone() - preserve the value of errno. -*/ -#ifdef STM_DEBUGPRINT -#include <stdio.h> -#endif -static inline void stm_enter_transactional_zone(stm_thread_local_t *tl) { - intptr_t self = tl->self_or_0_if_atomic; - if (__sync_bool_compare_and_swap(&_stm_detached_inevitable_from_thread, - self, 0)) { -#ifdef STM_DEBUGPRINT - fprintf(stderr, "stm_enter_transactional_zone fast path\n"); -#endif - } - else { - _stm_reattach_transaction(self); - /* _stm_detached_inevitable_from_thread should be 0 here, but - it can already have been changed from a parallel thread - (assuming we're not inevitable ourselves) */ - } -} -static inline void stm_leave_transactional_zone(stm_thread_local_t *tl) { - assert(STM_SEGMENT->running_thread == tl); - if (stm_is_inevitable(tl)) { -#ifdef STM_DEBUGPRINT - fprintf(stderr, "stm_leave_transactional_zone fast path\n"); -#endif - _stm_detach_inevitable_transaction(tl); - } - else { - _stm_leave_noninevitable_transactional_zone(); - } -} - -/* stm_force_transaction_break() is in theory equivalent to - stm_leave_transactional_zone() immediately followed by - stm_enter_transactional_zone(); however, it is supposed to be - called in CPU-heavy threads that had a transaction run for a while, - and so it *always* forces a commit and starts the next transaction. - The new transaction is never inevitable. See also - stm_should_break_transaction(). */ -void stm_force_transaction_break(stm_thread_local_t *tl); - /* Abort the currently running transaction. This function never returns: it jumps back to the start of the transaction (which must not be inevitable). */ @@ -596,6 +535,10 @@ STM_TRANSACTION_COMMIT, STM_TRANSACTION_ABORT, + /* DETACH/REATTACH is used for leaving/reentering the transactional */ + STM_TRANSACTION_DETACH, + STM_TRANSACTION_REATTACH, + /* inevitable contention: all threads that try to become inevitable have a STM_BECOME_INEVITABLE event with a position marker. Then, if it waits it gets a STM_WAIT_OTHER_INEVITABLE. It is possible @@ -688,6 +631,75 @@ } while (0) + +/* Entering and leaving a "transactional code zone": a (typically very + large) section in the code where we are running a transaction. + This is the STM equivalent to "acquire the GIL" and "release the + GIL", respectively. stm_read(), stm_write(), stm_allocate(), and + other functions should only be called from within a transaction. + + Note that transactions, in the STM sense, cover _at least_ one + transactional code zone. They may be longer; for example, if one + thread does a lot of stm_enter_transactional_zone() + + stm_become_inevitable() + stm_leave_transactional_zone(), as is + typical in a thread that does a lot of C function calls, then we + get only a few bigger inevitable transactions that cover the many + short transactional zones. This is done by having + stm_leave_transactional_zone() turn the current transaction + inevitable and detach it from the running thread (if there is no + other inevitable transaction running so far). Then + stm_enter_transactional_zone() will try to reattach to it. This is + far more efficient than constantly starting and committing + transactions. + + stm_enter_transactional_zone() and stm_leave_transactional_zone() + preserve the value of errno. +*/ +#ifdef STM_DEBUGPRINT +#include <stdio.h> +#endif +static inline void stm_enter_transactional_zone(stm_thread_local_t *tl) { + intptr_t self = tl->self_or_0_if_atomic; + if (__sync_bool_compare_and_swap(&_stm_detached_inevitable_from_thread, + self, 0)) { + if (self != 0 && stmcb_timing_event != NULL) { + /* for atomic transactions, we don't emit DETACH/REATTACH */ + stmcb_timing_event(tl, STM_TRANSACTION_REATTACH, NULL); + } +#ifdef STM_DEBUGPRINT + fprintf(stderr, "stm_enter_transactional_zone fast path\n"); +#endif + } + else { + _stm_reattach_transaction(self); + /* _stm_detached_inevitable_from_thread should be 0 here, but + it can already have been changed from a parallel thread + (assuming we're not inevitable ourselves) */ + } +} +static inline void stm_leave_transactional_zone(stm_thread_local_t *tl) { + assert(STM_SEGMENT->running_thread == tl); + if (stm_is_inevitable(tl)) { +#ifdef STM_DEBUGPRINT + fprintf(stderr, "stm_leave_transactional_zone fast path\n"); +#endif + _stm_detach_inevitable_transaction(tl); + } + else { + _stm_leave_noninevitable_transactional_zone(); + } +} + +/* stm_force_transaction_break() is in theory equivalent to + stm_leave_transactional_zone() immediately followed by + stm_enter_transactional_zone(); however, it is supposed to be + called in CPU-heavy threads that had a transaction run for a while, + and so it *always* forces a commit and starts the next transaction. + The new transaction is never inevitable. See also + stm_should_break_transaction(). */ +void stm_force_transaction_break(stm_thread_local_t *tl); + + /* Support for light finalizers. This is a simple version of finalizers that guarantees not to do anything fancy, like not resurrecting objects. */ _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit