[Python-checkins] peps: Updated the PEP 447 text
ronald.oussoren
python-checkins at python.org
Mon Jul 29 16:37:13 CEST 2013
http://hg.python.org/peps/rev/5d573095266d
changeset: 5008:5d573095266d
user: Ronald Oussoren <ronaldoussoren at mac.com>
date: Mon Jul 29 14:42:49 2013 +0200
summary:
Updated the PEP 447 text
* __locallookup__ is now required for all metatypes and is therefore
defined on type.
The method was optional to make it easier to
detect if the attribute lookup cache can be used, but
the same idea can be used when "type" implements tp_locallookup.
* Added benchmarking results with PyBench.
files:
pep-0447.txt | 157 ++++++++++++++++++++++++++++++++++----
1 files changed, 137 insertions(+), 20 deletions(-)
diff --git a/pep-0447.txt b/pep-0447.txt
--- a/pep-0447.txt
+++ b/pep-0447.txt
@@ -7,7 +7,7 @@
Type: Standards Track
Content-Type: text/x-rst
Created: 12-Jun-2013
-Post-History: 2-Jul-2013, 15-Jul-2013
+Post-History: 2-Jul-2013, 15-Jul-2013, 29-Jul-2013
Abstract
@@ -64,7 +64,6 @@
attribute resolution by both ``super.__getattribute__`` and ``object.__getattribute``::
class MetaType(type):
-
def __locallookup__(cls, name):
try:
return cls.__dict__[name]
@@ -75,8 +74,8 @@
that is looked up. It should return the value of the attribute without invoking descriptors,
or raise `AttributeError`_ when the name cannot be found.
-The `type`_ class does not provide an implementation for ``__locallookup__``, primarily
-to enable some optimizations in the Python implementation.
+The `type`_ class provides a default implementation for ``__locallookup__``, that
+looks up the name in the class dictionary.
Example usage
.............
@@ -85,7 +84,6 @@
versions of names::
class UpperCaseAccess (type):
-
def __locallookup__(cls, name):
return cls.__dict__[name.upper()]
@@ -114,18 +112,16 @@
and should not invoke descriptors. The method returns ``NULL`` without setting an exception
when the *name* cannot be found, and returns a new reference otherwise (not a borrowed reference).
+Use of this hook by the interpreter
+-----------------------------------
-Usage of this hook
-------------------
-
-The new method is optional and will not be defined on `type`_. Both ``super.__getattribute__``
-and ``object.__getattribute__``/`PyObject_GenericGetAttr`_ (through ``_PyType_Lookup``) will use the
-the ``__locallookup__`` method when it is present in the meta type of a type on the MRO and will
-continue to peek in the type's ``__dict__`` when the meta type does not have a ``__locallookup``
-method.
+The new method is required for metatypes and as such is defined on `type_`. Both
+``super.__getattribute__`` and ``object.__getattribute__``/`PyObject_GenericGetAttr`_
+(through ``_PyType_Lookup``) use the this ``__locallookup__`` method when walking
+the MRO.
Other changes to the implementation
-...................................
+-----------------------------------
The change for `PyObject_GenericGetAttr`_ will be done by changing the private function
``_PyType_Lookup``. This currently returns a borrowed reference, but must return a new
@@ -133,12 +129,134 @@
will be renamed to ``_PyType_LookupName``, this will cause compile-time errors for all out-of-tree
users of this private API.
-By making ``__locallookup_`` optional the implementation can continue to use the type attribute
-lookup cache for types that don't have a metaclass with this new method, which should minimize the
-performance impact of the change.
+The attribute lookup cache in ``Objects/typeobject.c`` is disabled for classes that have a
+metaclass that overrides ``__locallookup__``, because using the cache might not be valid
+for such classes.
-**TODO**: run pybench, an possibly the full speedtest, with and without this change and insert
-the results.
+Performance impact
+------------------
+
+The pybench output below compares an implementation of this PEP with the regular
+source tree, both based on changeset a5681f50bae2, run on an idle machine an
+Core i7 processor running Centos 6.4.
+
+Even though the machine was idle there were clear differences between runs,
+I've seen difference in "minimum time" vary from -0.1% to +1.5%, with simular
+(but slightly smaller) differences in the "average time" difference.
+
+.. ::
+
+ -------------------------------------------------------------------------------
+ PYBENCH 2.1
+ -------------------------------------------------------------------------------
+ * using CPython 3.4.0a0 (default, Jul 29 2013, 13:01:34) [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)]
+ * disabled garbage collection
+ * system check interval set to maximum: 2147483647
+ * using timer: time.perf_counter
+ * timer: resolution=1e-09, implementation=clock_gettime(CLOCK_MONOTONIC)
+
+ -------------------------------------------------------------------------------
+ Benchmark: pep447.pybench
+ -------------------------------------------------------------------------------
+
+ Rounds: 10
+ Warp: 10
+ Timer: time.perf_counter
+
+ Machine Details:
+ Platform ID: Linux-2.6.32-358.114.1.openstack.el6.x86_64-x86_64-with-centos-6.4-Final
+ Processor: x86_64
+
+ Python:
+ Implementation: CPython
+ Executable: /tmp/default-pep447/bin/python3
+ Version: 3.4.0a0
+ Compiler: GCC 4.4.7 20120313 (Red Hat 4.4.7-3)
+ Bits: 64bit
+ Build: Jul 29 2013 14:09:12 (#default)
+ Unicode: UCS4
+
+
+ -------------------------------------------------------------------------------
+ Comparing with: default.pybench
+ -------------------------------------------------------------------------------
+
+ Rounds: 10
+ Warp: 10
+ Timer: time.perf_counter
+
+ Machine Details:
+ Platform ID: Linux-2.6.32-358.114.1.openstack.el6.x86_64-x86_64-with-centos-6.4-Final
+ Processor: x86_64
+
+ Python:
+ Implementation: CPython
+ Executable: /tmp/default/bin/python3
+ Version: 3.4.0a0
+ Compiler: GCC 4.4.7 20120313 (Red Hat 4.4.7-3)
+ Bits: 64bit
+ Build: Jul 29 2013 13:01:34 (#default)
+ Unicode: UCS4
+
+
+ Test minimum run-time average run-time
+ this other diff this other diff
+ -------------------------------------------------------------------------------
+ BuiltinFunctionCalls: 45ms 44ms +1.3% 45ms 44ms +1.3%
+ BuiltinMethodLookup: 26ms 27ms -2.4% 27ms 27ms -2.2%
+ CompareFloats: 33ms 34ms -0.7% 33ms 34ms -1.1%
+ CompareFloatsIntegers: 66ms 67ms -0.9% 66ms 67ms -0.8%
+ CompareIntegers: 51ms 50ms +0.9% 51ms 50ms +0.8%
+ CompareInternedStrings: 34ms 33ms +0.4% 34ms 34ms -0.4%
+ CompareLongs: 29ms 29ms -0.1% 29ms 29ms -0.0%
+ CompareStrings: 43ms 44ms -1.8% 44ms 44ms -1.8%
+ ComplexPythonFunctionCalls: 44ms 42ms +3.9% 44ms 42ms +4.1%
+ ConcatStrings: 33ms 33ms -0.4% 33ms 33ms -1.0%
+ CreateInstances: 47ms 48ms -2.9% 47ms 49ms -3.4%
+ CreateNewInstances: 35ms 36ms -2.5% 36ms 36ms -2.5%
+ CreateStringsWithConcat: 69ms 70ms -0.7% 69ms 70ms -0.9%
+ DictCreation: 52ms 50ms +3.1% 52ms 50ms +3.0%
+ DictWithFloatKeys: 40ms 44ms -10.1% 43ms 45ms -5.8%
+ DictWithIntegerKeys: 32ms 36ms -11.2% 35ms 37ms -4.6%
+ DictWithStringKeys: 29ms 34ms -15.7% 35ms 40ms -11.0%
+ ForLoops: 30ms 29ms +2.2% 30ms 29ms +2.2%
+ IfThenElse: 38ms 41ms -6.7% 38ms 41ms -6.9%
+ ListSlicing: 36ms 36ms -0.7% 36ms 37ms -1.3%
+ NestedForLoops: 43ms 45ms -3.1% 43ms 45ms -3.2%
+ NestedListComprehensions: 39ms 40ms -1.7% 39ms 40ms -2.1%
+ NormalClassAttribute: 86ms 82ms +5.1% 86ms 82ms +5.0%
+ NormalInstanceAttribute: 42ms 42ms +0.3% 42ms 42ms +0.0%
+ PythonFunctionCalls: 39ms 38ms +3.5% 39ms 38ms +2.8%
+ PythonMethodCalls: 51ms 49ms +3.0% 51ms 50ms +2.8%
+ Recursion: 67ms 68ms -1.4% 67ms 68ms -1.4%
+ SecondImport: 41ms 36ms +12.5% 41ms 36ms +12.6%
+ SecondPackageImport: 45ms 40ms +13.1% 45ms 40ms +13.2%
+ SecondSubmoduleImport: 92ms 95ms -2.4% 95ms 98ms -3.6%
+ SimpleComplexArithmetic: 28ms 28ms -0.1% 28ms 28ms -0.2%
+ SimpleDictManipulation: 57ms 57ms -1.0% 57ms 58ms -1.0%
+ SimpleFloatArithmetic: 29ms 28ms +4.7% 29ms 28ms +4.9%
+ SimpleIntFloatArithmetic: 37ms 41ms -8.5% 37ms 41ms -8.7%
+ SimpleIntegerArithmetic: 37ms 41ms -9.4% 37ms 42ms -10.2%
+ SimpleListComprehensions: 33ms 33ms -1.9% 33ms 34ms -2.9%
+ SimpleListManipulation: 28ms 30ms -4.3% 29ms 30ms -4.1%
+ SimpleLongArithmetic: 26ms 26ms +0.5% 26ms 26ms +0.5%
+ SmallLists: 40ms 40ms +0.1% 40ms 40ms +0.1%
+ SmallTuples: 46ms 47ms -2.4% 46ms 48ms -3.0%
+ SpecialClassAttribute: 126ms 120ms +4.7% 126ms 121ms +4.4%
+ SpecialInstanceAttribute: 42ms 42ms +0.6% 42ms 42ms +0.8%
+ StringMappings: 94ms 91ms +3.9% 94ms 91ms +3.8%
+ StringPredicates: 48ms 49ms -1.7% 48ms 49ms -2.1%
+ StringSlicing: 45ms 45ms +1.4% 46ms 45ms +1.5%
+ TryExcept: 23ms 22ms +4.9% 23ms 22ms +4.8%
+ TryFinally: 32ms 32ms -0.1% 32ms 32ms +0.1%
+ TryRaiseExcept: 17ms 17ms +0.9% 17ms 17ms +0.5%
+ TupleSlicing: 49ms 48ms +1.1% 49ms 49ms +1.0%
+ WithFinally: 48ms 47ms +2.3% 48ms 47ms +2.4%
+ WithRaiseExcept: 45ms 44ms +0.8% 45ms 45ms +0.5%
+ -------------------------------------------------------------------------------
+ Totals: 2284ms 2287ms -0.1% 2306ms 2308ms -0.1%
+
+ (this=pep447.pybench, other=default.pybench)
Alternative proposals
@@ -174,7 +292,6 @@
* `Issue 18181`_ contains a prototype implementation
-
Copyright
=========
--
Repository URL: http://hg.python.org/peps
More information about the Python-checkins
mailing list