}
Py_ssize_t
-_PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
+_PyDict_LookupIndexAndValue(PyDictObject *mp, PyObject *key, PyObject **value)
{
// TODO: Thread safety
- PyObject *value;
assert(PyDict_CheckExact((PyObject*)mp));
assert(PyUnicode_CheckExact(key));
return -1;
}
- return _Py_dict_lookup(mp, key, hash, &value);
+ return _Py_dict_lookup(mp, key, hash, value);
+}
+
+Py_ssize_t
+_PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
+{
+ PyObject *value; // discarded
+ return _PyDict_LookupIndexAndValue(mp, key, &value);
}
/* Same as PyDict_GetItemWithError() but with hash supplied by caller.
static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
static uint32_t function_get_version(PyObject *o, int opcode);
+#ifdef Py_GIL_DISABLED
+static void
+maybe_enable_deferred_ref_count(PyObject *op)
+{
+ if (!_Py_IsOwnedByCurrentThread(op)) {
+ // For module level variables that are heavily used from multiple
+ // threads, deferred reference counting provides good scaling
+ // benefits. The downside is that the object will only be deallocated
+ // by a GC run.
+ PyUnstable_Object_EnableDeferredRefcount(op);
+ }
+}
+#endif
+
+
static int
specialize_module_load_attr_lock_held(PyDictObject *dict, _Py_CODEUNIT *instr, PyObject *name)
{
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING);
return -1;
}
- Py_ssize_t index = _PyDict_LookupIndex(dict, name);
+ PyObject *value;
+ Py_ssize_t index = _PyDict_LookupIndexAndValue(dict, name, &value);
assert(index != DKIX_ERROR);
if (index != (uint16_t)index) {
SPECIALIZATION_FAIL(LOAD_ATTR,
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
return -1;
}
+#ifdef Py_GIL_DISABLED
+ maybe_enable_deferred_ref_count(value);
+#endif
write_u32(cache->version, keys_version);
cache->index = (uint16_t)index;
specialize(instr, LOAD_ATTR_MODULE);
return 1;
}
-
static void
specialize_load_global_lock_held(
PyObject *globals, PyObject *builtins,
SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
goto fail;
}
+#ifdef Py_GIL_DISABLED
+ PyObject *value;
+ Py_ssize_t index = _PyDict_LookupIndexAndValue((PyDictObject *)globals, name, &value);
+#else
Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name);
+#endif
if (index == DKIX_ERROR) {
SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
goto fail;
SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
goto fail;
}
+#ifdef Py_GIL_DISABLED
+ maybe_enable_deferred_ref_count(value);
+#endif
cache->index = (uint16_t)index;
cache->module_keys_version = (uint16_t)keys_version;
specialize(instr, LOAD_GLOBAL_MODULE);
# > echo "0" | sudo tee /sys/devices/system/cpu/cpufreq/boost
#
+import copy
import math
import os
import queue
for _ in range(1000 * WORK_SCALE):
obj = MyDataClass(x=1, y=2, z=3)
+
+@register_benchmark
+def deepcopy():
+ x = {'list': [1, 2], 'tuple': (1, None)}
+ for i in range(40 * WORK_SCALE):
+ copy.deepcopy(x)
+
+
def bench_one_thread(func):
t0 = time.perf_counter_ns()
func()