Skip to content

Commit

Permalink
specialize: optimize for single-threaded programs
Browse files Browse the repository at this point in the history
  • Loading branch information
colesbury committed Apr 23, 2023
1 parent 7e75686 commit 90d34f0
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 107 deletions.
60 changes: 20 additions & 40 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,18 +342,16 @@ dummy_func(
};

inst(BINARY_SUBSCR, (unused/4, container, sub -- unused)) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinarySubscr(container, sub, next_instr);
_PyMutex_unlock(&_PyRuntime.mutex);
DISPATCH_SAME_OPARG();
}
STAT_INC(BINARY_SUBSCR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(BINARY_SUBSCR_GENERIC);
}

Expand Down Expand Up @@ -490,18 +488,16 @@ dummy_func(
};

inst(STORE_SUBSCR, (unused/1, unused, container, sub -- )) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_StoreSubscr(container, sub, next_instr);
_PyMutex_unlock(&_PyRuntime.mutex);
DISPATCH_SAME_OPARG();
}
STAT_INC(STORE_SUBSCR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(STORE_SUBSCR_GENERIC);
}

Expand Down Expand Up @@ -928,9 +924,9 @@ dummy_func(

// stack effect: (__0 -- __array[oparg])
inst(UNPACK_SEQUENCE) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
PyObject *seq = TOP();
next_instr--;
Expand All @@ -939,8 +935,6 @@ dummy_func(
DISPATCH_SAME_OPARG();
}
STAT_INC(UNPACK_SEQUENCE, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(UNPACK_SEQUENCE_GENERIC);
}

Expand Down Expand Up @@ -1021,9 +1015,9 @@ dummy_func(
};

inst(STORE_ATTR, (unused/1, unused/3, unused, owner --)) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(names, oparg);
next_instr--;
Expand All @@ -1032,8 +1026,6 @@ dummy_func(
DISPATCH_SAME_OPARG();
}
STAT_INC(STORE_ATTR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(STORE_ATTR_GENERIC);
}

Expand Down Expand Up @@ -1136,9 +1128,9 @@ dummy_func(

// error: LOAD_GLOBAL has irregular stack effect
inst(LOAD_GLOBAL) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(names, oparg>>1);
next_instr--;
Expand All @@ -1147,8 +1139,6 @@ dummy_func(
DISPATCH_SAME_OPARG();
}
STAT_INC(LOAD_GLOBAL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(LOAD_GLOBAL_GENERIC);
}

Expand Down Expand Up @@ -1537,9 +1527,9 @@ dummy_func(

// error: LOAD_ATTR has irregular stack effect
inst(LOAD_ATTR) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
PyObject *owner = TOP();
PyObject *name = GETITEM(names, oparg>>1);
Expand All @@ -1549,8 +1539,6 @@ dummy_func(
DISPATCH_SAME_OPARG();
}
STAT_INC(LOAD_ATTR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(LOAD_ATTR_GENERIC);
}

Expand Down Expand Up @@ -1885,18 +1873,16 @@ dummy_func(
};

inst(COMPARE_OP, (unused/2, left, right -- unused)) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_CompareOp(left, right, next_instr, oparg);
_PyMutex_unlock(&_PyRuntime.mutex);
DISPATCH_SAME_OPARG();
}
STAT_INC(COMPARE_OP, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(COMPARE_OP_GENERIC);
}

Expand Down Expand Up @@ -2301,18 +2287,16 @@ dummy_func(

// stack effect: ( -- __0)
inst(FOR_ITER) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyForIterCache *cache = (_PyForIterCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_ForIter(TOP(), next_instr, oparg);
_PyMutex_unlock(&_PyRuntime.mutex);
DISPATCH_SAME_OPARG();
}
STAT_INC(FOR_ITER, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(FOR_ITER_GENERIC);
}

Expand Down Expand Up @@ -2636,9 +2620,9 @@ dummy_func(

// stack effect: (__0, __array[oparg] -- )
inst(CALL) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyCallCache *cache = (_PyCallCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
int is_meth = is_method(stack_pointer, oparg);
int nargs = oparg + is_meth;
Expand All @@ -2649,8 +2633,6 @@ dummy_func(
DISPATCH_SAME_OPARG();
}
STAT_INC(CALL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(CALL_GENERIC);
}

Expand Down Expand Up @@ -3393,18 +3375,16 @@ dummy_func(
}

inst(BINARY_OP, (unused/1, lhs, rhs -- unused)) {
_PyMutex_lock(&_PyRuntime.mutex);
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
if (DECREMENT_ADAPTIVE_COUNTER(&cache->counter)) {
_PyMutex_lock(&_PyRuntime.mutex);
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0));
_PyMutex_unlock(&_PyRuntime.mutex);
DISPATCH_SAME_OPARG();
}
STAT_INC(BINARY_OP, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
_PyMutex_unlock(&_PyRuntime.mutex);
GO_TO_INSTRUCTION(BINARY_OP_GENERIC);
}

Expand Down
71 changes: 64 additions & 7 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
/* This is only a single jump on release builds! */ \
UPDATE_MISS_STATS((INSTNAME)); \
assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \
GO_TO_INSTRUCTION(INSTNAME ## _GENERIC); \
goto INSTNAME ## _DEOPT; \
}

#define DEOPT_UNLOCK_IF(COND, INSTNAME) \
Expand All @@ -896,7 +896,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
UPDATE_MISS_STATS((INSTNAME)); \
assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \
_Py_critical_section_end(&_cs); \
GO_TO_INSTRUCTION(INSTNAME ## _GENERIC); \
goto INSTNAME ## _DEOPT; \
}


Expand Down Expand Up @@ -955,11 +955,17 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define ADAPTIVE_COUNTER_IS_MAX(COUNTER) \
(((COUNTER) >> ADAPTIVE_BACKOFF_BITS) == ((1 << MAX_BACKOFF_VALUE) - 1))

#define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \
do { \
assert(!ADAPTIVE_COUNTER_IS_ZERO((COUNTER))); \
(COUNTER) -= (1 << ADAPTIVE_BACKOFF_BITS); \
} while (0);
static _Py_ALWAYS_INLINE int
DECREMENT_ADAPTIVE_COUNTER(uint16_t *ptr)
{
uint16_t counter = _Py_atomic_load_uint16_relaxed(ptr);
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
return 1;
}
counter -= (1 << ADAPTIVE_BACKOFF_BITS);
_Py_atomic_store_uint16_relaxed(ptr, counter);
return 0;
}

#define INCREMENT_ADAPTIVE_COUNTER(COUNTER) \
do { \
Expand Down Expand Up @@ -1334,6 +1340,57 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
or goto error. */
Py_UNREACHABLE();

BINARY_OP_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(BINARY_OP);
}
GO_TO_INSTRUCTION(BINARY_OP_GENERIC);
BINARY_SUBSCR_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(BINARY_SUBSCR);
}
GO_TO_INSTRUCTION(BINARY_SUBSCR_GENERIC);
CALL_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(CALL);
}
GO_TO_INSTRUCTION(CALL_GENERIC);
COMPARE_OP_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(COMPARE_OP);
}
GO_TO_INSTRUCTION(COMPARE_OP_GENERIC);
FOR_ITER_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(FOR_ITER);
}
GO_TO_INSTRUCTION(FOR_ITER_GENERIC);
LOAD_ATTR_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(LOAD_ATTR);
}
GO_TO_INSTRUCTION(LOAD_ATTR_GENERIC);
LOAD_GLOBAL_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(LOAD_GLOBAL);
}
GO_TO_INSTRUCTION(LOAD_GLOBAL_GENERIC);
STORE_ATTR_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(STORE_ATTR);
}
GO_TO_INSTRUCTION(STORE_ATTR_GENERIC);
STORE_SUBSCR_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(STORE_SUBSCR);
}
GO_TO_INSTRUCTION(STORE_SUBSCR_GENERIC);
UNPACK_SEQUENCE_DEOPT:
if (!_PyRuntime.multithreaded) {
GO_TO_INSTRUCTION(UNPACK_SEQUENCE);
}
GO_TO_INSTRUCTION(UNPACK_SEQUENCE_GENERIC);

unbound_local_error:
{
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
Expand Down
Loading

0 comments on commit 90d34f0

Please sign in to comment.