[Python-checkins] r63520 - in python/branches/okkoto-sizeof: Doc/c-api/object.rst Doc/c-api/typeobj.rst Doc/includes/typestruct.h Doc/library/functions.rst Include/abstract.h Include/object.h Lib/test/test_builtin.py Objects/abstract.c Objects/dictobject.c Python/bltinmodule.c
robert.schuppenies
python-checkins at python.org
Wed May 21 17:01:21 CEST 2008
Author: robert.schuppenies
Date: Wed May 21 17:01:20 2008
New Revision: 63520
Log:
first patch proposed
Modified:
python/branches/okkoto-sizeof/Doc/c-api/object.rst
python/branches/okkoto-sizeof/Doc/c-api/typeobj.rst
python/branches/okkoto-sizeof/Doc/includes/typestruct.h
python/branches/okkoto-sizeof/Doc/library/functions.rst
python/branches/okkoto-sizeof/Include/abstract.h
python/branches/okkoto-sizeof/Include/object.h
python/branches/okkoto-sizeof/Lib/test/test_builtin.py
python/branches/okkoto-sizeof/Objects/abstract.c
python/branches/okkoto-sizeof/Objects/dictobject.c
python/branches/okkoto-sizeof/Python/bltinmodule.c
Modified: python/branches/okkoto-sizeof/Doc/c-api/object.rst
==============================================================================
--- python/branches/okkoto-sizeof/Doc/c-api/object.rst (original)
+++ python/branches/okkoto-sizeof/Doc/c-api/object.rst Wed May 21 17:01:20 2008
@@ -304,6 +304,13 @@
.. versionadded:: 2.2
+.. cfunction:: int PyObject_Footprint(PyObject *o)
+
+ Return the memory footprint (i.e. size in bytes) of object o or NULL on failure.
+
+ .. versionadded:: 2.6
+
+
.. cfunction:: Py_ssize_t PyObject_Length(PyObject *o)
Py_ssize_t PyObject_Size(PyObject *o)
Modified: python/branches/okkoto-sizeof/Doc/c-api/typeobj.rst
==============================================================================
--- python/branches/okkoto-sizeof/Doc/c-api/typeobj.rst (original)
+++ python/branches/okkoto-sizeof/Doc/c-api/typeobj.rst Wed May 21 17:01:20 2008
@@ -1092,6 +1092,21 @@
Weak reference list head, for weak references to this type object. Not
inherited. Internal use only.
+
+.. cmember:: footprintfunc PyTypeObject.tp_footprint
+
+ An optional function pointer that returns the memory footprint of the
+ object. This function should be used if the memory usage of the object
+ cannot be determined with tp_basicsize plus, if applicable,
+ tp_itemsize * length of the object. If the field is not set, the memory
+ footprint is computed as described. Note that this formula does not
+ include any referenced objects, e.g. attributes.
+
+ The value -1 should not be returned as a normal return value; when an
+ error occurs during the computation of the hash value, the function
+ should set an exception and return -1.
+
+
The remaining fields are only defined if the feature test macro
:const:`COUNT_ALLOCS` is defined, and are for internal use only. They are
documented here for completeness. None of these fields are inherited by
Modified: python/branches/okkoto-sizeof/Doc/includes/typestruct.h
==============================================================================
--- python/branches/okkoto-sizeof/Doc/includes/typestruct.h (original)
+++ python/branches/okkoto-sizeof/Doc/includes/typestruct.h Wed May 21 17:01:20 2008
@@ -72,5 +72,12 @@
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
+ destructor tp_del;
+
+ /* Type attribute cache version tag. Added in version 2.6 */
+ unsigned int tp_version_tag;
+
+ /* Memory usage. Added in version 2.6 */
+ footprintfunc tp_footprint;
} PyTypeObject;
Modified: python/branches/okkoto-sizeof/Doc/library/functions.rst
==============================================================================
--- python/branches/okkoto-sizeof/Doc/library/functions.rst (original)
+++ python/branches/okkoto-sizeof/Doc/library/functions.rst Wed May 21 17:01:20 2008
@@ -472,6 +472,16 @@
The float type is described in :ref:`typesnumeric`.
+
+.. function:: footprint(x)
+
+ Return the size of an object in bytes. The object can be any type of
+ object. All built-in objects will return correct results, but this
+ must not hold true for third-party extensions.
+
+ .. versionadded:: 2.6
+
+
.. function:: frozenset([iterable])
:noindex:
Modified: python/branches/okkoto-sizeof/Include/abstract.h
==============================================================================
--- python/branches/okkoto-sizeof/Include/abstract.h (original)
+++ python/branches/okkoto-sizeof/Include/abstract.h Wed May 21 17:01:20 2008
@@ -418,6 +418,13 @@
equivalent to the Python expression: type(o).
*/
+ PyAPI_FUNC(Py_ssize_t) PyObject_Footprint(PyObject *o);
+
+ /*
+ Return the memory footprint (i.e. size in bytes) of object o or NULL
+ on failure.
+ */
+
PyAPI_FUNC(Py_ssize_t) PyObject_Size(PyObject *o);
/*
Modified: python/branches/okkoto-sizeof/Include/object.h
==============================================================================
--- python/branches/okkoto-sizeof/Include/object.h (original)
+++ python/branches/okkoto-sizeof/Include/object.h Wed May 21 17:01:20 2008
@@ -328,6 +328,7 @@
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t);
+typedef Py_ssize_t (*footprintfunc)(PyObject *);
typedef struct _typeobject {
PyObject_VAR_HEAD
@@ -408,6 +409,9 @@
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
+ /* Memory footprint. Added in version 2.6 */
+ footprintfunc tp_footprint;
+
#ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */
Py_ssize_t tp_allocs;
Modified: python/branches/okkoto-sizeof/Lib/test/test_builtin.py
==============================================================================
--- python/branches/okkoto-sizeof/Lib/test/test_builtin.py (original)
+++ python/branches/okkoto-sizeof/Lib/test/test_builtin.py Wed May 21 17:01:20 2008
@@ -1467,6 +1467,135 @@
self.assertEqual(bin(-(2**65)), '-0b1' + '0' * 65)
self.assertEqual(bin(-(2**65-1)), '-0b' + '1' * 65)
+class FootprintTest(unittest.TestCase):
+
+
+ def setUp(self):
+ import struct
+ self.i = len(struct.pack('i', 0))
+ self.l = len(struct.pack('l', 0))
+ self.p = len(struct.pack('P', 0))
+ self.headersize = self.l + self.p
+ if hasattr(sys, "gettotalrefcount"):
+ self.headersize += 2 * self.p
+ self.f = open(TESTFN, 'wb')
+
+ def tearDown(self):
+ import os
+ if self.f:
+ self.f.close()
+ os.remove(TESTFN)
+
+ def check_footprint(self, o, size, ):
+ size += self.headersize
+ msg = 'wrong size for ' + str(type(o)) + ': '+\
+ str(footprint(o)) + ' != ' + str(size)
+ self.assertEqual(footprint(o), size, msg)
+
+ def align(self, value):
+ mod = value % self.p
+ if mod != 0:
+ return value - mod + self.p
+ else:
+ return value
+
+ def test_align(self):
+ self.assertTrue( (self.align(0) % self.p) == 0 )
+ self.assertTrue( (self.align(1) % self.p) == 0 )
+ self.assertTrue( (self.align(3) % self.p) == 0 )
+ self.assertTrue( (self.align(4) % self.p) == 0 )
+ self.assertTrue( (self.align(7) % self.p) == 0 )
+ self.assertTrue( (self.align(8) % self.p) == 0 )
+ self.assertTrue( (self.align(9) % self.p) == 0 )
+
+ def test_standardobjects(self):
+ import inspect
+ i = self.i
+ l = self.l
+ p = self.p
+ # bool
+ self.check_footprint(True, self.l)
+ # buffer
+ self.check_footprint(buffer(''), 2*p + 2*l + self.align(i) +l)
+ # bytearray
+ self.check_footprint(bytes(), self.align(i) + l + p)
+ # cell
+ def get_cell():
+ x = 42
+ def inner():
+ return x
+ return inner
+ self.check_footprint(get_cell().func_closure[0], p)
+ # class
+ class clazz():
+ def method():
+ pass
+ self.check_footprint(clazz, 6*p)
+ # instance
+ self.check_footprint(clazz(), 3*p)
+ # method
+ self.check_footprint(clazz().method, 4*p)
+ # code
+ self.check_footprint(get_cell().func_code, self.align(4*i) + 8*p +\
+ self.align(i) + 2*p)
+ # complex
+ self.check_footprint(complex(0,1), 2*8)
+ # enumerate
+ self.check_footprint(enumerate([]), l + 3*p)
+ # reverse
+ self.check_footprint(reversed(''), l + p )
+ # file
+ self.check_footprint(self.f, 4*p + self.align(2*i) + 4*p +\
+ self.align(3*i) + 2*p + self.align(i))
+ # float
+ self.check_footprint(float(0), 8)
+ # function
+ def func(): pass
+ self.check_footprint(func, 9 * l)
+ class c():
+ @staticmethod
+ def foo():
+ pass
+ @classmethod
+ def bar(cls):
+ pass
+ # staticmethod
+ self.check_footprint(foo, l)
+ # classmethod
+ self.check_footprint(bar, l)
+ # generator
+ def get_gen(): yield 1
+ self.check_footprint(get_gen(), p + self.align(i) + 2*p)
+ # integer
+ self.check_footprint(1, l)
+ # builtin_function_or_method
+ self.check_footprint(abs, 3*p)
+ # module
+ self.check_footprint(unittest, p)
+ # xange
+ self.check_footprint(xrange(1), 3*p)
+ # slice
+ self.check_footprint(slice(0), 3*p)
+
+ def test_variable_size(self):
+ i = self.i
+ l = self.l
+ p = self.p
+ self.headersize += l
+ # list
+ self.check_footprint([], p + l)
+ self.check_footprint([1, 2, 3], p + l)
+ # string
+ self.check_footprint('', l + self.align(i + 1))
+ self.check_footprint('abc', l + self.align(i + 1) + 3)
+
+ def test_special_types(self):
+ i = self.i
+ l = self.l
+ p = self.p
+ # dict
+ self.check_footprint({}, 3*l + 3*p + 8*(l + 2*p))
+
class TestSorted(unittest.TestCase):
def test_basic(self):
@@ -1507,7 +1636,7 @@
self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0)
def test_main(verbose=None):
- test_classes = (BuiltinTest, TestSorted)
+ test_classes = (BuiltinTest, TestSorted, FootprintTest)
run_unittest(*test_classes)
Modified: python/branches/okkoto-sizeof/Objects/abstract.c
==============================================================================
--- python/branches/okkoto-sizeof/Objects/abstract.c (original)
+++ python/branches/okkoto-sizeof/Objects/abstract.c Wed May 21 17:01:20 2008
@@ -58,6 +58,36 @@
}
Py_ssize_t
+PyObject_Footprint(PyObject *o)
+{
+ Py_ssize_t res;
+ Py_ssize_t size;
+ footprintfunc m;
+
+ if (o == NULL) {
+ null_error();
+ return -1;
+ }
+
+ m = o->ob_type->tp_footprint;
+ if (m)
+ return o->ob_type->tp_footprint(o);
+
+ res = 0;
+ size = o->ob_type->tp_itemsize;
+ if (size > 0) {
+ Py_ssize_t len;
+ len = PyObject_Size(o);
+ if (len == -1 && PyErr_Occurred())
+ return -1;
+ if (len)
+ res += len * size;
+ }
+ res += o->ob_type->tp_basicsize;
+ return res;
+}
+
+Py_ssize_t
PyObject_Size(PyObject *o)
{
PySequenceMethods *m;
Modified: python/branches/okkoto-sizeof/Objects/dictobject.c
==============================================================================
--- python/branches/okkoto-sizeof/Objects/dictobject.c (original)
+++ python/branches/okkoto-sizeof/Objects/dictobject.c Wed May 21 17:01:20 2008
@@ -2194,6 +2194,18 @@
return dict_update_common(self, args, kwds, "dict");
}
+static Py_ssize_t
+dict_footprint(PyDictObject *mp)
+{
+ Py_ssize_t res;
+
+ res = sizeof(PyDictObject) + sizeof(mp->ma_table);
+ if (mp->ma_table == mp->ma_smalltable)
+ return res;
+ else
+ return res + (mp->ma_mask + 1) * sizeof(PyDictEntry);
+}
+
static PyObject *
dict_iter(PyDictObject *dict)
{
@@ -2252,6 +2264,15 @@
PyType_GenericAlloc, /* tp_alloc */
dict_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ 0, /* tp_del */
+ 0, /* tp_version_tag */
+ (footprintfunc)dict_footprint, /* tp_footprint */
};
/* For backward compatibility with old dictionary interface */
Modified: python/branches/okkoto-sizeof/Python/bltinmodule.c
==============================================================================
--- python/branches/okkoto-sizeof/Python/bltinmodule.c (original)
+++ python/branches/okkoto-sizeof/Python/bltinmodule.c Wed May 21 17:01:20 2008
@@ -1310,6 +1310,21 @@
\n\
Return the number of items of a sequence or mapping.");
+static PyObject *
+builtin_footprint(PyObject *self, PyObject *o)
+{
+ Py_ssize_t res;
+
+ res = PyObject_Footprint(o);
+ if (res < 0 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromSsize_t(res);
+}
+
+PyDoc_STRVAR(footprint_doc,
+"footprint(object) -> integer\n\
+\n\
+Return the memory footprint an object in bytes.");
static PyObject *
builtin_locals(PyObject *self)
@@ -2550,6 +2565,7 @@
{"issubclass", builtin_issubclass, METH_VARARGS, issubclass_doc},
{"iter", builtin_iter, METH_VARARGS, iter_doc},
{"len", builtin_len, METH_O, len_doc},
+ {"footprint", builtin_footprint, METH_O, footprint_doc},
{"locals", (PyCFunction)builtin_locals, METH_NOARGS, locals_doc},
{"map", builtin_map, METH_VARARGS, map_doc},
{"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
More information about the Python-checkins
mailing list