[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