[Python-checkins] cpython: Account for shared keys in type's __sizeof__ (#13903).

martin.v.loewis python-checkins at python.org
Tue Apr 24 19:14:38 CEST 2012


http://hg.python.org/cpython/rev/b044e0568be2
changeset:   76530:b044e0568be2
user:        Martin v. Loewis <martin at v.loewis.de>
date:        Tue Apr 24 19:13:57 2012 +0200
summary:
  Account for shared keys in type's __sizeof__ (#13903).

files:
  Include/dictobject.h |   1 +
  Lib/test/test_sys.py |  12 +++++++++---
  Objects/dictobject.c |  23 ++++++++++++-----------
  Objects/typeobject.c |  18 ++++++++++++++++++
  4 files changed, 40 insertions(+), 14 deletions(-)


diff --git a/Include/dictobject.h b/Include/dictobject.h
--- a/Include/dictobject.h
+++ b/Include/dictobject.h
@@ -75,6 +75,7 @@
 PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
 PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp);
 PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp);
+Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys);
 #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL)
 
 PyAPI_FUNC(int) PyDict_ClearFreeList(void);
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -829,13 +829,19 @@
         check((), size(vh))
         check((1,2,3), size(vh) + 3*self.P)
         # type
+        # static type: PyTypeObject
+        s = size(vh + 'P2P15Pl4PP9PP11PI')
+        check(int, s)
         # (PyTypeObject + PyNumberMethods + PyMappingMethods +
-        #  PySequenceMethods + PyBufferProcs)
-        s = size(vh + 'P2P15Pl4PP9PP11PIP') + size('16Pi17P 3P 10P 2P 3P')
-        check(int, s)
+        #  PySequenceMethods + PyBufferProcs + 4P)
+        s = size(vh + 'P2P15Pl4PP9PP11PI') + size('34P 3P 10P 2P 4P')
+        # Separate block for PyDictKeysObject with 4 entries
+        s += size("PPPP") + 4*size("PPP")
         # class
         class newstyleclass(object): pass
         check(newstyleclass, s)
+        # dict with shared keys
+        check(newstyleclass().__dict__, size(h+"PPP4P"))
         # unicode
         # each tuple contains a string and its expected character size
         # don't put any static strings here, as they may contain
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2398,22 +2398,23 @@
 static PyObject *
 dict_sizeof(PyDictObject *mp)
 {
-    Py_ssize_t size;
-    double res, keys_size;
+    Py_ssize_t size, res;
 
     size = DK_SIZE(mp->ma_keys);
     res = sizeof(PyDictObject);
     if (mp->ma_values)
         res += size * sizeof(PyObject*);
-    /* Count our share of the keys object -- with rounding errors. */
-    keys_size = sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry);
-    /* If refcnt > 1, then one count is (probably) held by a type */
-    /* XXX  This is somewhat approximate :) */
-    if (mp->ma_keys->dk_refcnt < 3)
-        res += keys_size;
-    else
-        res += keys_size / (mp->ma_keys->dk_refcnt - 1);
-    return PyFloat_FromDouble(res);
+    /* If the dictionary is split, the keys portion is accounted-for
+       in the type object. */
+    if (mp->ma_keys->dk_refcnt == 1)
+        res += sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry);
+    return PyLong_FromSsize_t(res);
+}
+
+Py_ssize_t
+_PyDict_KeysSize(PyDictKeysObject *keys)
+{
+    return sizeof(PyDictKeysObject) + (DK_SIZE(keys)-1) * sizeof(PyDictKeyEntry);
 }
 
 PyDoc_STRVAR(contains__doc__,
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2730,6 +2730,22 @@
     return result;
 }
 
+static PyObject*
+type_sizeof(PyObject *self, PyObject *args_unused)
+{
+    Py_ssize_t size;
+    PyTypeObject *type = (PyTypeObject*)self;
+    if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+        PyHeapTypeObject* et = (PyHeapTypeObject*)type;
+        size = sizeof(PyHeapTypeObject);
+        if (et->ht_cached_keys)
+            size += _PyDict_KeysSize(et->ht_cached_keys);
+    }
+    else
+        size = sizeof(PyTypeObject);
+    return PyLong_FromSsize_t(size);
+}
+
 static PyMethodDef type_methods[] = {
     {"mro", (PyCFunction)mro_external, METH_NOARGS,
      PyDoc_STR("mro() -> list\nreturn a type's method resolution order")},
@@ -2745,6 +2761,8 @@
      PyDoc_STR("__subclasscheck__() -> bool\ncheck if a class is a subclass")},
     {"__dir__", type_dir, METH_NOARGS,
      PyDoc_STR("__dir__() -> list\nspecialized __dir__ implementation for types")},
+    {"__sizeof__",      type_sizeof,       METH_NOARGS,
+     "__sizeof__() -> int\nreturn memory consumption of the type object"},
     {0}
 };
 

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


More information about the Python-checkins mailing list