[Python-checkins] cpython (3.6): Issue #28731: Optimize _PyDict_NewPresized() to create correct size dict.

inada.naoki python-checkins at python.org
Wed Dec 7 04:39:34 EST 2016


https://hg.python.org/cpython/rev/d03562dcbb82
changeset:   105508:d03562dcbb82
branch:      3.6
parent:      105506:747de8acb7e4
user:        INADA Naoki <songofacandy at gmail.com>
date:        Wed Dec 07 18:34:44 2016 +0900
summary:
  Issue #28731: Optimize _PyDict_NewPresized() to create correct size dict.

Improve speed of dict literal with constant keys up to 30%.

files:
  Misc/NEWS            |   3 +++
  Objects/dictobject.c |  24 +++++++++++++++++++-----
  2 files changed, 22 insertions(+), 5 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #28731: Optimize _PyDict_NewPresized() to create correct size dict.
+  Improve speed of dict literal with constant keys up to 30%.
+
 - Issue #5322: Fixed setting __new__ to a PyCFunction inside Python code.
   Original patch by Andreas Stührk.
 
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -388,7 +388,7 @@
  * This can be used to reserve enough size to insert n entries without
  * resizing.
  */
-#define ESTIMATE_SIZE(n)  (((n)*3) >> 1)
+#define ESTIMATE_SIZE(n)  (((n)*3+1) >> 1)
 
 /* Alternative fraction that is otherwise close enough to 2n/3 to make
  * little difference. 8 * 2/3 == 8 * 5/8 == 5. 16 * 2/3 == 16 * 5/8 == 10.
@@ -1357,12 +1357,26 @@
 PyObject *
 _PyDict_NewPresized(Py_ssize_t minused)
 {
+    const Py_ssize_t max_presize = 128 * 1024;
     Py_ssize_t newsize;
     PyDictKeysObject *new_keys;
-    for (newsize = PyDict_MINSIZE;
-         newsize <= minused && newsize > 0;
-         newsize <<= 1)
-        ;
+
+    /* There are no strict guarantee that returned dict can contain minused
+     * items without resize.  So we create medium size dict instead of very
+     * large dict or MemoryError.
+     */
+    if (minused > USABLE_FRACTION(max_presize)) {
+        newsize = max_presize;
+    }
+    else {
+        Py_ssize_t minsize = ESTIMATE_SIZE(minused);
+        newsize = PyDict_MINSIZE;
+        while (newsize < minsize) {
+            newsize <<= 1;
+        }
+    }
+    assert(IS_POWER_OF_2(newsize));
+
     new_keys = new_keys_object(newsize);
     if (new_keys == NULL)
         return NULL;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list