1
2
3
4
5
6
7
8
9 '''This module exposes 10 functions and 2 classes to obtain lengths
10 and sizes of Python objects (for Python 2.2 or later [1]).
11
12 The main changes in this version are new function calcsize(),
13 use gc.get_objects() to get all objects and improvements in
14 this documentation.
15
16 Public Functions [2]
17
18 Function asizeof calculates the combined (approximate) size
19 in bytes of one or several Python objects.
20
21 Function asizesof returns a tuple containing the (approximate)
22 size in bytes for each given Python object separately.
23
24 Function asized returns for each object an instance of class
25 Asized containing all the size information of the object and a
26 tuple with the referents.
27
28 Functions basicsize and itemsize return the basic respectively
29 item size of the given object.
30
31 Function flatsize returns the flat size of a Python object in
32 bytes defined as the basic size plus the item size times the
33 length of the given object.
34
35 Function leng returns the length of an object, like standard
36 len but extended for several types, e.g. the leng of a multi-
37 precision int (or long) is the number of digits [3]. The length
38 of most mutable sequence objects includes an estimate of the
39 over-allocation and therefore, the leng value may differ from
40 the standard len result.
41
42 Function refs returns (a generator for) the referents of the
43 given object, i.e. the objects referenced by the given object.
44
45 Function calcsize is equivalent to standard struct.calcsize
46 but handles format characters 'z' for signed C type Py_ssize_t
47 and 'Z' for unsigned C type size_t.
48
49 Certain classes are known to be sub-classes of or to behave as
50 dict objects. Function adict can be used to install other
51 class objects to be treated like dict.
52
53 Public Classes [2]
54
55 An instance of class Asized is returned for each object sized
56 with the asized function or method.
57
58 Class Asizer can be used to accumulate the results of several
59 asizeof or asizesof calls. After creating an Asizer instance,
60 use methods asizeof and asizesof to size additional objects.
61
62 Call methods exclude_refs and/or exclude_types to exclude
63 references to or instances or types of certain objects.
64
65 Use one of the print\_... methods to report the statistics.
66
67 Duplicate Objects
68
69 Any duplicate, given objects are sized only once and the size
70 is included in the combined total only once. But functions
71 asizesof and asized do return a size value respectively an
72 Asized instance for each given object, the same for duplicates.
73
74 Definitions [4]
75
76 The size of an object is defined as the sum of the flat size
77 of the object plus the sizes of any referents. Referents are
78 visited recursively up to a given limit. However, the size
79 of objects referenced multiple times is included only once.
80
81 The flat size of an object is defined as the basic size of the
82 object plus the item size times the number of allocated items.
83 The flat size does include the size for the items (references
84 to the referents), but not the referents themselves.
85
86 The flat size returned by function flatsize equals the result
87 of the asizeof function with options code=True, ignored=False,
88 limit=0 and option align set to the same value.
89
90 The accurate flat size for an object is obtained from function
91 sys.getsizeof() where available. Otherwise, the length and
92 size of sequence objects as dicts, lists, sets, etc. is based
93 on an estimate for the number of allocated items. As a result,
94 the reported length and size may substantially differ from the
95 actual length and size.
96
97 The basic and item sizes are obtained from the __basicsize__
98 respectively __itemsize__ attribute of the (type of the) object.
99 Where necessary (e.g. sequence objects), a zero __itemsize__
100 is replaced by the size of a corresponding C type.
101
102 The basic size (of GC managed objects) objects includes the
103 overhead for Python's garbage collector (GC) as well as the
104 space needed for refcounts (only in certain Python builds).
105
106 Optionally, sizes can be aligned to any power of 2 multiple.
107
108 Size of (byte)code
109
110 The (byte)code size of objects as classes, functions, methods,
111 modules, etc. can be included by setting option code.
112
113 Iterators are handled similar to sequences: iterated object(s)
114 are sized like referents if the recursion limit permits. Also,
115 function gc.get_referents() must return the referent object
116 of iterators.
117
118 Generators are sized as (byte)code only, but generated objects
119 are never sized.
120
121 Old- and New-style Classes
122
123 All old- and new-style class, instance and type objects, are
124 handled uniformly such that (a) instance and class objects can
125 be distinguished and (b) instances of different old-style
126 classes can be dealt with separately.
127
128 Class and type objects are represented as <class ....* def>
129 respectively as <type ... def> where an '*' indicates an old-
130 style class and the def suffix marks the definition object.
131 Instances of old-style classes are shown as new-style ones but
132 with an '*' at the end of the name, like <class module.name*>.
133
134 Ignored Objects
135
136 To avoid excessive sizes, several object types are ignored [4]
137 by default, e.g. built-in functions, built-in types and classes
138 [5], function globals and module referents. However, any
139 instances thereof are sized and module objects will be sized
140 when passed as given objects. Ignored object types are included
141 if option ignored is set accordingly.
142
143 In addition, many __...__ attributes of callable objects are
144 ignored, except crucial ones, e.g. class attributes __dict__,
145 __doc__, __name__ and __slots__. For more details, see the
146 type-specific _..._refs() and _len_...() functions below.
147
148 Option all can be used to size all Python objects and/or get
149 the referents from gc.get_referents() and override the type-
150 specific __..._refs() functions.
151
152 Notes
153
154 [1] Tested with Python 2.2.3, 2.3.7, 2.4.5, 2.5.1, 2.5.2, 2.6.2,
155 3.0.1 or 3.1a2 on CentOS 4.6, SuSE 9.3, MacOS X 10.4.11 Tiger
156 (Intel) and 10.3.9 Panther (PPC), Solaris 10 (Opteron) and
157 Windows XP all 32-bit Python and on RHEL 3u7 and Solaris 10
158 (Opteron) both 64-bit Python.
159
160 [2] The functions and classes in this module are not thread-safe.
161
162 [3] See Python source file .../Include/longinterp.h for the
163 C typedef of digit used in multi-precision int (or long)
164 objects. The size of digit in bytes can be obtained in
165 Python from the int (or long) __itemsize__ attribute.
166 Function leng (rather _len_int) below deterimines the
167 number of digits from the int (or long) value.
168
169 [4] These definitions and other assumptions are rather arbitrary
170 and may need corrections or adjustments.
171
172 [5] Types and classes are considered built-in if the module of
173 the type or class is listed in _builtin_modules below.
174
175 '''
176
177 from __future__ import generators
178
179 from inspect import isbuiltin, isclass, iscode, isframe, \
180 isfunction, ismethod, ismodule, stack
181 from math import log
182 from os import linesep
183 from struct import calcsize as _calcsize
184 import sys
185 import types as Types
186 import weakref as Weakref
187
188 __version__ = '5.12 (Apr 27, 2009)'
189 __all__ = ['adict', 'asized', 'asizeof', 'asizesof',
190 'Asized', 'Asizer',
191 'basicsize', 'flatsize', 'itemsize', 'leng', 'refs',
192 'calcsize']
193
194
195
196 if __name__ == '__main__':
197 _builtin_modules = (int.__module__, 'types', Exception.__module__)
198 else:
199 _builtin_modules = (int.__module__, 'types', Exception.__module__, __name__)
200
201
202
203
204 _sizeof_Cbyte = _calcsize('c')
205 _sizeof_Clong = _calcsize('l')
206 _sizeof_Cvoidp = _calcsize('P')
207
208
209 if _sizeof_Clong < _sizeof_Cvoidp:
210 _Zz = 'PP'
211 else:
212 _Zz = 'Ll'
213
215 '''struct.calcsize() handling 'z' for signed Py_ssize_t and 'Z' for unsigned size_t.
216 '''
217 return _calcsize(fmt.replace('Z', _Zz[0]).replace('z', _Zz[1]))
218
219
220 _sizeof_CPyCodeObject = calcsize('Pz10P5i0P')
221 _sizeof_CPyFrameObject = calcsize('Pzz13P63i0P')
222 _sizeof_CPyModuleObject = calcsize('PzP0P')
223
224
225 _sizeof_CPyDictEntry = calcsize('z2P')
226 _sizeof_Csetentry = calcsize('lP')
227
228
229 try:
230 _sizeof_Cdigit = long.__itemsize__
231 except NameError:
232 _sizeof_Cdigit = int.__itemsize__
233 if _sizeof_Cdigit < 2:
234 raise AssertionError('sizeof(%s) bad: %d' % ('digit', _sizeof_Cdigit))
235
236 try:
237 u = unicode('\0')
238 except NameError:
239 u = '\0'
240 u = u.encode('unicode-internal')
241 _sizeof_Cunicode = len(u)
242 del u
243 if (1 << (_sizeof_Cunicode << 3)) <= sys.maxunicode:
244 raise AssertionError('sizeof(%s) bad: %d' % ('unicode', _sizeof_Cunicode))
245
246 if hasattr(sys, 'maxsize'):
247 Z = calcsize('Z')
248 if (1 << (Z << 3)) <= sys.maxsize:
249 raise AssertionError('sizeof(%s) bad: %d' % ('size_t', Z))
250 del Z
251
252 try:
253 import _testcapi as t
254 _sizeof_CPyGC_Head = t.SIZEOF_PYGC_HEAD
255 except (ImportError, AttributeError):
256
257
258 t = calcsize('2d') - 1
259 _sizeof_CPyGC_Head = (calcsize('2Pz') + t) & ~t
260 del t
261
262
263 if hasattr(sys, 'gettotalrefcount'):
264 _sizeof_Crefcounts = calcsize('2z')
265 else:
266 _sizeof_Crefcounts = 0
267
268
269 _Py_TPFLAGS_HEAPTYPE = 1 << 9
270 _Py_TPFLAGS_HAVE_GC = 1 << 14
271
272 _Type_type = type(type)
273
274
275
276
277
279 '''Return iter-/generator, preferably.
280 '''
281 return getattr(obj, 'iteritems', obj.items)()
282
284 '''Return iter-/generator, preferably.
285 '''
286 return getattr(obj, 'iterkeys', obj.keys)()
287
289 '''Use iter-/generator, preferably.
290 '''
291 return getattr(obj, 'itervalues', obj.values)()
292
293 try:
294 _callable = callable
295 except NameError:
297 '''Substitute for callable().'''
298 return hasattr(obj, '__call__')
299
300 try:
301 from gc import get_objects as _getobjects
302 except ImportError:
304
305
306 return tuple(_values(sys.modules)) + (
307 globals(), stack(sys.getrecursionlimit()))
308
309 try:
310
311
312 from gc import get_referents as _getreferents
313 except ImportError:
316
317
318 _getsizeof = getattr(sys, 'getsizeof', None)
319
320 try:
321 _intern = intern
322 except NameError:
325
327 '''Return name=value pairs as keywords dict.
328 '''
329 return kwds
330
331 try:
332 _sorted = sorted
333 except NameError:
335 '''Partial substitute for missing sorted().'''
336 vals.sort()
337 if reverse:
338 vals.reverse()
339 return vals
340
341 try:
342 _sum = sum
343 except NameError:
345 '''Partial substitute for missing sum().'''
346 s = 0
347 for v in vals:
348 s += v
349 return s
350
351
352
353
370
378
379 -def _dir2(obj, pref='', excl=(), slots=None, itor=''):
380 '''Return an attribute name, object 2-tuple for certain
381 attributes or for the '__slots__' attributes of the
382 given object, but not both. Any iterator referent
383 objects are returned with the given name if the
384 latter is non-empty.
385 '''
386 if slots:
387 if hasattr(obj, slots):
388
389
390
391 s = {}
392 for c in type(obj).mro():
393 for a in getattr(c, slots, ()):
394 if hasattr(obj, a):
395 s.setdefault(a, getattr(obj, a))
396
397
398 yield slots, _Slots(s)
399 for t in _items(s):
400 yield t
401 elif itor:
402 for o in obj:
403 yield itor, o
404 else:
405 for a in dir(obj):
406 if a.startswith(pref) and a not in excl and hasattr(obj, a):
407 yield a, getattr(obj, a)
408
410 '''Return True for likely dict object.
411 '''
412 for ats in (('__len__', 'get', 'has_key', 'items', 'keys', 'values'),
413 ('__len__', 'get', 'has_key', 'iteritems', 'iterkeys', 'itervalues')):
414 for a in ats:
415 if not _callable(getattr(obj, a, None)):
416 break
417 else:
418 return True
419 return False
420
422 '''Return True for known dict objects.
423 '''
424 c = getattr(obj, '__class__', None)
425 return c and c.__name__ in _dict_classes.get(c.__module__, ())
426
428 '''Safe issubclass().
429 '''
430 if sup is not object:
431 try:
432 return issubclass(sub, sup)
433 except TypeError:
434 pass
435 return False
436
438 '''Get non-zero itemsize of type.
439 '''
440
441 return getattr(t, '__itemsize__', 0) or item
442
444 '''Keyword arguments as a string.
445 '''
446 return ', '.join(_sorted(['%s=%r' % kv for kv in _items(kwds)]))
447
449 '''Object length as a string.
450 '''
451 n = leng(obj)
452 if n is None:
453 r = ''
454 elif n > _len(obj):
455 r = ' leng %d!' % n
456 else:
457 r = ' leng %d' % n
458 return r
459
461 '''Return the name of an object.
462 '''
463 return getattr(obj, '__name__', dflt)
464
465 -def _objs(objs, all=None, **unused):
466 '''Return the given or 'all' objects.
467 '''
468 if all in (False, None):
469 t = objs or ()
470 elif all is True:
471 t = objs or _getobjects()
472 else:
473 raise ValueError('invalid option: %s=%r' % ('all', all))
474 return t
475
476 -def _p100(part, total, prec=1):
477 '''Return percentage as string.
478 '''
479 r = float(total)
480 if r:
481 r = part * 100.0 / r
482 return '%.*f%%' % (prec, r)
483 return 'n/a'
484
486 '''Return 's' if plural.
487 '''
488 if num == 1:
489 s = ''
490 else:
491 s = 's'
492 return s
493
495 '''Find the next power of 2.
496 '''
497 p2 = 16
498 while n > p2:
499 p2 += p2
500 return p2
501
503 '''Prettify and clip long repr() string.
504 '''
505 return _repr(obj, clip=clip).strip('<>').replace("'", '')
506
507 -def _printf(fmt, *args, **print3opts):
508 '''Formatted print.
509 '''
510 if print3opts:
511 f = print3opts.get('file', None) or sys.stdout
512 if args:
513 f.write(fmt % args)
514 else:
515 f.write(fmt)
516 f.write(print3opts.get('end', linesep))
517 elif args:
518 print(fmt % args)
519 else:
520 print(fmt)
521
522 -def _refs(obj, named, *ats, **kwds):
523 '''Return specific attribute objects of an object.
524 '''
525 if named:
526 for a in ats:
527 if hasattr(obj, a):
528 yield _NamedRef(a, getattr(obj, a))
529 if kwds:
530 for a, o in _dir2(obj, **kwds):
531 yield _NamedRef(a, o)
532 else:
533 for a in ats:
534 if hasattr(obj, a):
535 yield getattr(obj, a)
536 if kwds:
537 for _, o in _dir2(obj, **kwds):
538 yield o
539
541 '''Clip long repr() string.
542 '''
543 try:
544 r = repr(obj)
545 except TypeError:
546 r = 'N/A'
547 if 0 < clip < len(r):
548 h = (clip // 2) - 2
549 if h > 0:
550 r = r[:h] + '....' + r[-h:]
551 return r
552
553 -def _SI(size, K=1024, i='i'):
554 '''Return size as SI string.
555 '''
556 if 1 < K < size:
557 f = float(size)
558 for si in iter('KMGPTE'):
559 f /= K
560 if f < K:
561 return ' or %.1f %s%sB' % (f, si, i)
562 return ''
563
564 -def _SI2(size, **kwds):
565 '''Return size as regular plus SI string.
566 '''
567 return str(size) + _SI(size, **kwds)
568
569
570
572 '''Return specific referents of a class object.
573 '''
574 return _refs(obj, named, '__class__', '__dict__', '__doc__', '__mro__',
575 '__name__', '__slots__', '__weakref__')
576
578 '''Return specific referents of a code object.
579 '''
580 return _refs(obj, named, pref='co_')
581
583 '''Return key and value objects of a dict/proxy.
584 '''
585 if named:
586 for k, v in _items(obj):
587 s = str(k)
588 yield _NamedRef(s, k, 1)
589 yield _NamedRef(s, v, 2)
590 else:
591 for k, v in _items(obj):
592 yield k
593 yield v
594
596 '''Return specific referents of an enumerate object.
597 '''
598 return _refs(obj, named, '__doc__')
599
601 '''Return specific referents of an Exception object.
602 '''
603
604 return _refs(obj, named, 'args', 'filename', 'lineno', 'msg', 'text')
605
607 '''Return specific referents of a file object.
608 '''
609 return _refs(obj, named, 'mode', 'name')
610
612 '''Return specific referents of a frame object.
613 '''
614 return _refs(obj, named, pref='f_')
615
617 '''Return specific referents of a function or lambda object.
618 '''
619 return _refs(obj, named, '__doc__', '__name__', '__code__',
620 pref='func_', excl=('func_globals',))
621
623 '''Return the referent(s) of a generator object.
624 '''
625
626 f = getattr(obj, 'gi_frame', None)
627 return _refs(f, named, 'f_locals', 'f_code')
628
630 '''Return specific referents of a method object.
631 '''
632 return _refs(obj, named, '__doc__', '__name__', '__code__',
633 pref='im_')
634
636 '''Return specific referents of a class instance.
637 '''
638 return _refs(obj, named, '__dict__', '__class__',
639 slots='__slots__')
640
642 '''Return the referent(s) of an iterator object.
643 '''
644 r = _getreferents(obj)
645 return _refs(r, named, itor=_nameof(obj) or 'iteref')
646
648 '''Return specific referents of a module object.
649 '''
650
651 if obj.__name__ == __name__:
652 return ()
653
654 return _dict_refs(obj.__dict__, named)
655
657 '''Return specific referents of a property object.
658 '''
659 return _refs(obj, named, '__doc__', pref='f')
660
662 '''Return specific referents of a frozen/set, list, tuple and xrange object.
663 '''
664 return obj
665
667 '''Return referents of a os.stat object.
668 '''
669 return _refs(obj, named, pref='st_')
670
672 '''Return referents of a os.statvfs object.
673 '''
674 return _refs(obj, named, pref='f_')
675
677 '''Return specific referents of a traceback object.
678 '''
679 return _refs(obj, named, pref='tb_')
680
682 '''Return specific referents of a type object.
683 '''
684 return _refs(obj, named, '__dict__', '__doc__', '__mro__',
685 '__name__', '__slots__', '__weakref__')
686
688 '''Return weakly referent object.
689 '''
690 try:
691 return (obj(),)
692 except:
693 return ()
694
695 _all_refs = (None, _class_refs, _co_refs, _dict_refs, _enum_refs,
696 _exc_refs, _file_refs, _frame_refs, _func_refs,
697 _gen_refs, _im_refs, _inst_refs, _iter_refs,
698 _module_refs, _prop_refs, _seq_refs, _stat_refs,
699 _statvfs_refs, _tb_refs, _type_refs, _weak_refs)
700
701
702
703
705 '''Safe len().
706 '''
707 try:
708 return len(obj)
709 except TypeError:
710 return 0
711
713 '''Array length in bytes.
714 '''
715 return len(obj) * obj.itemsize
716
718 '''Bytearray size.
719 '''
720 return obj.__alloc__()
721
723 '''Length of code object (stack and variables only).
724 '''
725 return obj.co_stacksize + obj.co_nlocals \
726 + _len(obj.co_freevars) \
727 + _len(obj.co_cellvars) - 1
728
730 '''Dict length in items (estimate).
731 '''
732 n = len(obj)
733 if n < 6:
734 n = 0
735 else:
736 n = _power2(n + 1)
737 return n
738
740 '''Length of a frame object.
741 '''
742 c = getattr(obj, 'f_code', None)
743 if c:
744 n = _len_code(c)
745 else:
746 n = 0
747 return n
748
749 _digit2p2 = 1 << (_sizeof_Cdigit << 3)
750 _digitmax = _digit2p2 - 1
751 _digitlog = 1.0 / log(_digit2p2)
752
754 '''Length of multi-precision int (aka long) in digits.
755 '''
756 if obj:
757 n, i = 1, abs(obj)
758 if i > _digitmax:
759
760 n += int(log(i) * _digitlog)
761 else:
762 n = 0
763 return n
764
766 '''Length (hint) of an iterator.
767 '''
768 n = getattr(obj, '__length_hint__', None)
769 if n:
770 n = n()
771 else:
772 n = _len(obj)
773 return n
774
776 '''Length of list (estimate).
777 '''
778 n = len(obj)
779
780 if n > 8:
781 n += 6 + (n >> 3)
782 elif n:
783 n += 4
784 return n
785
787 '''Module length.
788 '''
789 return _len(obj.__dict__)
790
792 '''Length of frozen/set (estimate).
793 '''
794 n = len(obj)
795 if n > 8:
796 n = _power2(n + n - 2)
797 elif n:
798 n = 8
799 return n
800
802 '''Slice length.
803 '''
804 try:
805 return ((obj.stop - obj.start + 1) // obj.step)
806 except (AttributeError, TypeError):
807 return 0
808
810 '''Slots length.
811 '''
812 return len(obj) - 1
813
815 '''Struct length in bytes.
816 '''
817 try:
818 return obj.size
819 except AttributeError:
820 return 0
821
823 '''Unicode size.
824 '''
825 return len(obj) + 1
826
827 _all_lengs = (None, _len, _len_array, _len_bytearray,
828 _len_code, _len_dict, _len_frame,
829 _len_int, _len_iter, _len_list,
830 _len_module, _len_set, _len_slice,
831 _len_slots, _len_struct, _len_unicode)
832
833
834
835
836 _old_style = '*'
837 _new_style = ''
838
840 '''Wrapper for class objects.
841 '''
842 __slots__ = ('_obj', '_sty')
843
845 self._obj = obj
846 self._sty = style
847
849 r = str(self._obj)
850 if r.endswith('>'):
851 r = '%s%s def>' % (r[:-1], self._sty)
852 elif self._sty is _old_style and not r.startswith('class '):
853 r = 'class %s%s def' % (r, self._sty)
854 else:
855 r = '%s%s def' % (r, self._sty)
856 return r
857 __repr__ = __str__
858
859
860
861
862
863
864
865
866
867
868
869 _claskeys = {}
870
872 '''Wrap an old- or new-style class object.
873 '''
874 i = id(obj)
875 k = _claskeys.get(i, None)
876 if not k:
877 _claskeys[i] = k = _Claskey(obj, style)
878 return k
879
880 try:
881 _Types_ClassType = Types.ClassType
882 _Types_InstanceType = Types.InstanceType
883
885 '''Wrapper for old-style class (instances).
886 '''
887 __slots__ = ('_obj',)
888
891
894 __repr__ = __str__
895
896 _instkeys = {}
897
906
919
931
932 except AttributeError:
933
935 '''Return class and instance keys for a class.
936 '''
937 if type(obj) is _Type_type:
938 return _claskey(obj, _new_style), obj
939 return None, None
940
942 '''Return the key for any object.
943 '''
944 k = type(obj)
945 if k is _Type_type:
946 k = _claskey(obj, _new_style)
947 return k
948
950 '''Store referred object along
951 with the name of the referent.
952 '''
953 __slots__ = ('name', 'ref', 'typ')
954
959
961 '''Wrapper class for __slots__ attribute at
962 class instances to account for the size
963 of the __slots__ tuple/list containing
964 references to the attribute values.
965 '''
966 pass
967
968
969 _i = _intern
970 _all_kinds = (_kind_static, _kind_dynamic, _kind_derived, _kind_ignored, _kind_inferred) = (
971 _i('static'), _i('dynamic'), _i('derived'), _i('ignored'), _i('inferred'))
972 del _i
973
975 '''Type definition class.
976 '''
977 __slots__ = {
978 'base': 0,
979 'item': 0,
980 'leng': None,
981 'refs': None,
982 'both': None,
983 'kind': None,
984 'type': None}
985
988
990 return True
991
993 return repr(self.args())
994
1005
1007 '''Return all attributes as arguments tuple.
1008 '''
1009 return (self.base, self.item, self.leng, self.refs,
1010 self.both, self.kind, self.type)
1011
1012 - def dup(self, other=None, **kwds):
1013 '''Duplicate attributes of dict or other typedef.
1014 '''
1015 if other is None:
1016 d = _dict_typedef.kwds()
1017 else:
1018 d = other.kwds()
1019 d.update(kwds)
1020 self.reset(**d)
1021
1022 - def flat(self, obj, mask=0):
1023 '''Return the aligned flat size.
1024 '''
1025 s = self.base
1026 if self.leng and self.item > 0:
1027 s += self.leng(obj) * self.item
1028 if _getsizeof:
1029 s = _getsizeof(obj, s)
1030 if mask:
1031 s = (s + mask) & ~mask
1032 return s
1033
1044
1052
1053 - def save(self, t, base=0, heap=False):
1054 '''Save this typedef plus its class typedef.
1055 '''
1056 c, k = _keytuple(t)
1057 if k and k not in _typedefs:
1058 _typedefs[k] = self
1059 if c and c not in _typedefs:
1060 if t.__module__ in _builtin_modules:
1061 k = _kind_ignored
1062 else:
1063 k = self.kind
1064 _typedefs[c] = _Typedef(base=_basicsize(type(t), base=base, heap=heap),
1065 refs=_type_refs,
1066 both=False, kind=k, type=t)
1067 elif isbuiltin(t) and t not in _typedefs:
1068 _typedefs[t] = _Typedef(base=_basicsize(t, base=base),
1069 both=False, kind=_kind_ignored, type=t)
1070 else:
1071 raise KeyError('asizeof typedef %r bad: %r %r' % (self, (c, k), self.both))
1072
1073 - def set(self, safe_len=False, **kwds):
1082
1083 - def reset(self, base=0, item=0, leng=None, refs=None,
1084 both=True, kind=None, type=None):
1085 '''Reset all specified attributes.
1086 '''
1087 if base < 0:
1088 raise ValueError('invalid option: %s=%r' % ('base', base))
1089 else:
1090 self.base = base
1091 if item < 0:
1092 raise ValueError('invalid option: %s=%r' % ('item', item))
1093 else:
1094 self.item = item
1095 if leng in _all_lengs:
1096 self.leng = leng
1097 else:
1098 raise ValueError('invalid option: %s=%r' % ('leng', leng))
1099 if refs in _all_refs:
1100 self.refs = refs
1101 else:
1102 raise ValueError('invalid option: %s=%r' % ('refs', refs))
1103 if both in (False, True):
1104 self.both = both
1105 else:
1106 raise ValueError('invalid option: %s=%r' % ('both', both))
1107 if kind in _all_kinds:
1108 self.kind = kind
1109 else:
1110 raise ValueError('invalid option: %s=%r' % ('kind', kind))
1111 self.type = type
1112
1113 _typedefs = {}
1114
1116 '''Add new typedef for both data and code.
1117 '''
1118 v = _Typedef(base=_basicsize(t, base=base), item=_itemsize(t, item),
1119 refs=refs, leng=leng,
1120 both=True, kind=kind, type=t)
1121 v.save(t, base=base, heap=heap)
1122 return v
1123
1132
1133
1134 _typedef_both(complex)
1135 _typedef_both(float)
1136 _typedef_both(list, refs=_seq_refs, leng=_len_list, item=_sizeof_Cvoidp)
1137 _typedef_both(tuple, refs=_seq_refs, leng=_len, item=_sizeof_Cvoidp)
1138 _typedef_both(property, refs=_prop_refs)
1139 _typedef_both(type(Ellipsis))
1140 _typedef_both(type(None))
1141
1142
1143 _typedef_both(_Slots, item=_sizeof_Cvoidp,
1144 leng=_len_slots,
1145 refs=None,
1146 heap=True)
1147
1148
1149 _dict_typedef = _typedef_both(dict, item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs)
1150 try:
1151 _typedef_both(Types.DictProxyType, item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs)
1152 except AttributeError:
1153 _typedef_both(type(_Typedef.__dict__), item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs)
1154
1155
1156
1157 _dict_classes = {'UserDict': ('IterableUserDict', 'UserDict'),
1158 'weakref' : ('WeakKeyDictionary', 'WeakValueDictionary')}
1159 try:
1160 _typedef_both(Types.ModuleType, base=_dict_typedef.base,
1161 item=_dict_typedef.item + _sizeof_CPyModuleObject,
1162 leng=_len_module, refs=_module_refs)
1163 except AttributeError:
1164 pass
1165
1166
1167 try:
1168 from array import array
1169 _typedef_both(array, leng=_len_array, item=_sizeof_Cbyte)
1170 except ImportError:
1171 pass
1172
1173 try:
1174 _typedef_both(bool)
1175 except NameError:
1176 pass
1177
1178 try:
1179 _typedef_both(basestring, leng=None)
1180 except NameError:
1181 pass
1182
1183 try:
1184 if isbuiltin(buffer):
1185 _typedef_both(type(buffer('')), item=_sizeof_Cbyte, leng=_len)
1186 else:
1187 _typedef_both(buffer, item=_sizeof_Cbyte, leng=_len)
1188 except NameError:
1189 pass
1190
1191 try:
1192 _typedef_both(bytearray, item=_sizeof_Cbyte, leng=_len_bytearray)
1193 except NameError:
1194 pass
1195 try:
1196 if type(bytes) is not type(str):
1197 _typedef_both(bytes, item=_sizeof_Cbyte, leng=_len)
1198 except NameError:
1199 pass
1200 try:
1201 _typedef_both(str8, item=_sizeof_Cbyte, leng=_len)
1202 except NameError:
1203 pass
1204
1205 try:
1206 _typedef_both(enumerate, refs=_enum_refs)
1207 except NameError:
1208 pass
1209
1210 try:
1211 _typedef_both(Exception, refs=_exc_refs)
1212 except:
1213 pass
1214
1215 try:
1216 _typedef_both(file, refs=_file_refs)
1217 except NameError:
1218 pass
1219
1220 try:
1221 _typedef_both(frozenset, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs)
1222 except NameError:
1223 pass
1224 try:
1225 _typedef_both(set, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs)
1226 except NameError:
1227 pass
1228
1229 try:
1230 _typedef_both(Types.GetSetDescriptorType)
1231 except AttributeError:
1232 pass
1233
1234 try:
1235 _typedef_both(long, item=_sizeof_Cdigit, leng=_len_int)
1236 _typedef_both(int)
1237 except NameError:
1238 _typedef_both(int, item=_sizeof_Cdigit, leng=_len_int)
1239
1240 try:
1241 _typedef_both(Types.MemberDescriptorType)
1242 except AttributeError:
1243 pass
1244
1245 try:
1246 _typedef_both(type(NotImplemented))
1247 except NameError:
1248 pass
1249
1250 try:
1251 _typedef_both(range)
1252 except NameError:
1253 pass
1254 try:
1255 _typedef_both(xrange)
1256 except NameError:
1257 pass
1258
1259 try:
1260 _typedef_both(reversed, refs=_enum_refs)
1261 except NameError:
1262 pass
1263
1264 try:
1265 _typedef_both(slice, item=_sizeof_Cvoidp, leng=_len_slice)
1266 except NameError:
1267 pass
1268
1269 try:
1270 from os import curdir, stat, statvfs
1271 _typedef_both(type(stat( curdir)), refs=_stat_refs)
1272 _typedef_both(type(statvfs(curdir)), refs=_statvfs_refs,
1273 item=_sizeof_Cvoidp, leng=_len)
1274 except ImportError:
1275 pass
1276
1277 try:
1278 from struct import Struct
1279 _typedef_both(Struct, item=_sizeof_Cbyte, leng=_len_struct)
1280 except ImportError:
1281 pass
1282
1283 try:
1284 _typedef_both(Types.TracebackType, refs=_tb_refs)
1285 except AttributeError:
1286 pass
1287
1288 try:
1289 _typedef_both(unicode, leng=_len_unicode, item=_sizeof_Cunicode)
1290 _typedef_both(str, leng=_len, item=_sizeof_Cbyte)
1291 except NameError:
1292 _typedef_both(str, leng=_len_unicode, item=_sizeof_Cunicode)
1293
1294 try:
1295 _typedef_both(Weakref.KeyedRef, refs=_weak_refs, heap=True)
1296 except AttributeError:
1297 pass
1298
1299 try:
1300 _typedef_both(Weakref.ProxyType)
1301 except AttributeError:
1302 pass
1303
1304 try:
1305 _typedef_both(Weakref.ReferenceType, refs=_weak_refs)
1306 except AttributeError:
1307 pass
1308
1309
1310 _typedef_code(object, kind=_kind_ignored)
1311 _typedef_code(super, kind=_kind_ignored)
1312 _typedef_code(_Type_type, kind=_kind_ignored)
1313
1314 try:
1315 _typedef_code(classmethod, refs=_im_refs)
1316 except NameError:
1317 pass
1318 try:
1319 _typedef_code(staticmethod, refs=_im_refs)
1320 except NameError:
1321 pass
1322 try:
1323 _typedef_code(Types.MethodType, refs=_im_refs)
1324 except NameError:
1325 pass
1326
1327 try:
1328 _typedef_code(Types.GeneratorType, refs=_gen_refs)
1329 except AttributeError:
1330 pass
1331
1332 try:
1333 _typedef_code(Weakref.CallableProxyType, refs=_weak_refs)
1334 except AttributeError:
1335 pass
1336
1337
1338 s = [_items({}), _keys({}), _values({})]
1339 try:
1340 s.extend([reversed([]), reversed(())])
1341 except NameError:
1342 pass
1343 try:
1344 s.append(xrange(1))
1345 except NameError:
1346 pass
1347 try:
1348 from re import finditer
1349 s.append(finditer('', ''))
1350 except ImportError:
1351 pass
1352 for t in _values(_typedefs):
1353 if t.type and t.leng:
1354 try:
1355 s.append(t.type())
1356 except TypeError:
1357 pass
1358 for t in s:
1359 try:
1360 i = iter(t)
1361 _typedef_both(type(i), leng=_len_iter, refs=_iter_refs, item=0)
1362 except (KeyError, TypeError):
1363 pass
1364 del i, s, t
1365
1366
1367 -def _typedef(obj, derive=False, infer=False):
1368 '''Create a new typedef for an object.
1369 '''
1370 t = type(obj)
1371 v = _Typedef(base=_basicsize(t, obj=obj),
1372 kind=_kind_dynamic, type=t)
1373
1374 if ismodule(obj):
1375 v.dup(item=_dict_typedef.item + _sizeof_CPyModuleObject,
1376 leng=_len_module,
1377 refs=_module_refs)
1378 elif isframe(obj):
1379 v.set(base=_basicsize(t, base=_sizeof_CPyFrameObject, obj=obj),
1380 item=_itemsize(t),
1381 leng=_len_frame,
1382 refs=_frame_refs)
1383 elif iscode(obj):
1384 v.set(base=_basicsize(t, base=_sizeof_CPyCodeObject, obj=obj),
1385 item=_sizeof_Cvoidp,
1386 leng=_len_code,
1387 refs=_co_refs,
1388 both=False)
1389 elif _callable(obj):
1390 if isclass(obj):
1391 v.set(refs=_class_refs,
1392 both=False)
1393 if obj.__module__ in _builtin_modules:
1394 v.set(kind=_kind_ignored)
1395 elif isbuiltin(obj):
1396 v.set(both=False,
1397 kind=_kind_ignored)
1398 elif isfunction(obj):
1399 v.set(refs=_func_refs,
1400 both=False)
1401 elif ismethod(obj):
1402 v.set(refs=_im_refs,
1403 both=False)
1404 elif isclass(t):
1405
1406 v.set(item=_itemsize(t), safe_len=True,
1407 refs=_inst_refs)
1408 else:
1409 v.set(both=False)
1410 elif _issubclass(t, dict):
1411 v.dup(kind=_kind_derived)
1412 elif _isdictclass(obj) or (infer and _infer_dict(obj)):
1413 v.dup(kind=_kind_inferred)
1414 elif getattr(obj, '__module__', None) in _builtin_modules:
1415 v.set(kind=_kind_ignored)
1416 else:
1417 if derive:
1418 p = _derive_typedef(t)
1419 if p:
1420 v.dup(other=p, kind=_kind_derived)
1421 return v
1422 if _issubclass(t, Exception):
1423 v.set(item=_itemsize(t), safe_len=True,
1424 refs=_exc_refs,
1425 kind=_kind_derived)
1426 elif isinstance(obj, Exception):
1427 v.set(item=_itemsize(t), safe_len=True,
1428 refs=_exc_refs)
1429 else:
1430 v.set(item=_itemsize(t), safe_len=True,
1431 refs=_inst_refs)
1432 return v
1433
1434
1436 '''Internal type profile class.
1437 '''
1438 total = 0
1439 high = 0
1440 number = 0
1441 objref = None
1442 weak = False
1443
1454
1456 return self.__cmp__(other) < 0
1457
1474
1475 - def update(self, obj, size):
1486
1487
1488
1489
1491 '''Store the results of an asized object
1492 in these 4 attributes:
1493
1494 size - total size of the object
1495 flat - flat size of the object
1496 name - name or repr of the object
1497 refs - tuple containing an instance
1498 of Asized for each referent
1499 '''
1500 strf = ( '%s',
1501 '[K] %s',
1502 '[V] %s')
1503
1504 - def __init__(self, size, flat, refs=(), name=None):
1509
1511 return 'size %r, flat %r, refs[%d], name %r' % (
1512 self.size, self.flat, len(self.refs), self.name)
1513
1518
1520 '''Sizer state and options.
1521 '''
1522 _align_ = 8
1523 _all_ = False
1524 _clip_ = 80
1525 _code_ = False
1526 _derive_ = False
1527 _detail_ = 0
1528 _infer_ = False
1529 _limit_ = 100
1530 _stats_ = 0
1531
1532 _cutoff = 0
1533 _depth = 0
1534 _duplicate = 0
1535 _excl_d = None
1536 _ign_d = _kind_ignored
1537 _incl = ''
1538 _mask = 7
1539 _missed = 0
1540 _profile = False
1541 _profs = None
1542 _seen = None
1543 _total = 0
1544
1546 '''See method reset for the available options.
1547 '''
1548 self._excl_d = {}
1549 self.reset(**opts)
1550
1565
1567 '''Return the object's name.
1568 '''
1569 return _nameof(obj, '') or self._repr(obj)
1570
1572 '''Like prepr().
1573 '''
1574 return _prepr(obj, clip=self._clip_)
1575
1577 '''Get _Prof object.
1578 '''
1579 p = self._profs.get(key, None)
1580 if not p:
1581 self._profs[key] = p = _Prof()
1582 return p
1583
1585 '''Like repr().
1586 '''
1587 return _repr(obj, clip=self._clip_)
1588
1589 - def _sizer(self, obj, deep, sized):
1590 '''Size an object, recursively.
1591 '''
1592 s, f, i = 0, 0, id(obj)
1593
1594
1595 if i in self._seen:
1596 if deep:
1597 self._seen[i] += 1
1598 if sized:
1599 s = sized(s, f, name=self._nameof(obj))
1600 return s
1601 else:
1602 self._seen[i] = 0
1603 try:
1604 k, rs = _objkey(obj), []
1605 if k in self._excl_d:
1606 self._excl_d[k] += 1
1607 else:
1608 v = _typedefs.get(k, None)
1609 if not v:
1610 _typedefs[k] = v = _typedef(obj, derive=self._derive_,
1611 infer=self._infer_)
1612 if (v.both or self._code_) and v.kind is not self._ign_d:
1613 s = f = v.flat(obj, self._mask)
1614 if self._profile:
1615 self._prof(k).update(obj, s)
1616
1617 if deep < self._limit_ and not (deep and ismodule(obj)):
1618
1619 r, z, d = v.refs, self._sizer, deep + 1
1620 if self._all_:
1621 r = _getreferents(obj)
1622 if r:
1623 t = id(r)
1624 if t in self._seen:
1625 for o in r:
1626 s += z(o, d, None)
1627 else:
1628 self._seen[t] = 0
1629 for o in r:
1630 s += z(o, d, None)
1631 del self._seen[t]
1632 elif r:
1633 if sized and deep < self._detail_:
1634
1635 for o in r(obj, True):
1636 if isinstance(o, _NamedRef):
1637 t = z(o.ref, d, sized)
1638 t.name = t.format(o)
1639 else:
1640 t = z(o, d, sized)
1641 t.name = self._nameof(o)
1642 rs.append(t)
1643 s += t.size
1644 else:
1645 for o in r(obj, False):
1646 s += z(o, d, None)
1647
1648 if self._depth < d:
1649 self._depth = d
1650 self._seen[i] += 1
1651 except RuntimeError:
1652 self._missed += 1
1653 if sized:
1654 s = sized(s, f, name=self._nameof(obj), refs=rs)
1655 return s
1656
1657 - def _sizes(self, objs, sized=None):
1658 '''Return the size or an Asized instance for each
1659 given object and the total size. The total
1660 includes the size of duplicates only once.
1661 '''
1662 self.exclude_refs(*objs)
1663 s, t = {}, []
1664 for o in objs:
1665 i = id(o)
1666 if i in s:
1667 self._seen[i] += 1
1668 self._duplicate += 1
1669 else:
1670 s[i] = self._sizer(o, 0, sized)
1671 t.append(s[i])
1672 if sized:
1673 s = _sum([i.size for i in _values(s)])
1674 else:
1675 s = _sum(_values(s))
1676 self._total += s
1677 return s, tuple(t)
1678
1679 - def asized(self, *objs, **opts):
1680 '''Size each object and return an Asized instance with
1681 size information and referents up to the given detail
1682 level (and with modified options, see method set).
1683
1684 If only one object is given, the return value is the
1685 Asized instance for that object.
1686 '''
1687 if opts:
1688 self.set(**opts)
1689 if self._all_:
1690 raise KeyError('invalid option: %s=%r' % ('all', self._all_))
1691 _, t = self._sizes(objs, Asized)
1692 if len(t) == 1:
1693 t = t[0]
1694 return t
1695
1696 - def asizeof(self, *objs, **opts):
1697 '''Return the combined size of the given objects
1698 (with modified options, see also method set).
1699 '''
1700 if opts:
1701 self.set(**opts)
1702 s, _ = self._sizes(objs, None)
1703 return s
1704
1706 '''Return the individual sizes of the given objects
1707 (with modified options, see also method set).
1708 '''
1709 if opts:
1710 self.set(**opts)
1711 _, t = self._sizes(objs, None)
1712 return t
1713
1715 '''Exclude any references to the specified objects from sizing.
1716
1717 While any references to the given objects are excluded, the
1718 objects will be sized if specified as positional arguments
1719 in subsequent calls to methods asizeof and asizesof.
1720 '''
1721 for o in objs:
1722 self._seen.setdefault(id(o), 0)
1723
1725 '''Exclude the specified object instances and types from sizing.
1726
1727 All instances and types of the given objects are excluded,
1728 even objects specified as positional arguments in subsequent
1729 calls to methods asizeof and asizesof.
1730 '''
1731 for o in objs:
1732 for t in _keytuple(o):
1733 if t and t not in self._excl_d:
1734 self._excl_d[t] = 0
1735
1737 '''Print the profiles above cutoff percentage.
1738
1739 w=0 -- indentation for each line
1740 cutoff=0 -- minimum percentage printed
1741 print3options -- print options, as in Python 3.0
1742 '''
1743
1744 t = [(v, k) for k, v in _items(self._profs) if v.total > 0 or v.number > 1]
1745 if (len(self._profs) - len(t)) < 9:
1746 t = [(v, k) for k, v in _items(self._profs)]
1747 if t:
1748 s = ''
1749 if self._total:
1750 s = ' (% of grand total)'
1751 c = max(cutoff, self._cutoff)
1752 c = int(c * 0.01 * self._total)
1753 else:
1754 c = 0
1755 _printf('%s%*d profile%s: total%s, average, and largest flat size%s: largest object',
1756 linesep, w, len(t), _plural(len(t)), s, self._incl, **print3opts)
1757 r = len(t)
1758 for v, k in _sorted(t, reverse=True):
1759 s = 'object%(plural)s: %(total)s, %(avg)s, %(high)s: %(obj)s%(lengstr)s' % v.format(self._clip_, self._total)
1760 _printf('%*d %s %s', w, v.number, self._prepr(k), s, **print3opts)
1761 r -= 1
1762 if r > 1 and v.total < c:
1763 c = max(cutoff, self._cutoff)
1764 _printf('%+*d profiles below cutoff (%.0f%%)', w, r, c)
1765 break
1766 z = len(self._profs) - len(t)
1767 if z > 0:
1768 _printf('%+*d %r object%s', w, z, 'zero', _plural(z), **print3opts)
1769
1770 - def print_stats(self, objs=(), opts={}, sized=(), sizes=(), stats=3.0, **print3opts):
1771 '''Print the statistics.
1772
1773 w=0 -- indentation for each line
1774 objs=() -- optional, list of objects
1775 opts={} -- optional, dict of options used
1776 sized=() -- optional, tuple of Asized instances returned
1777 sizes=() -- optional, tuple of sizes returned
1778 stats=3.0 -- print statistics and cutoff percentage
1779 print3options -- print options, as in Python 3.0
1780 '''
1781 s = min(opts.get('stats', stats) or 0, self._stats_)
1782 if s > 0:
1783 t = self._total + self._missed + _sum(_values(self._seen))
1784 w = len(str(t)) + 1
1785 t = c = ''
1786 o = _kwdstr(**opts)
1787 if o and objs:
1788 c = ', '
1789
1790 if sized and objs:
1791 n = len(objs)
1792 if n > 1:
1793 _printf('%sasized(...%s%s) ...', linesep, c, o, **print3opts)
1794 for i in range(n):
1795 _printf('%*d: %s', w-1, i, sized[i], **print3opts)
1796 else:
1797 _printf('%sasized(%s): %s', linesep, o, sized, **print3opts)
1798 elif sizes and objs:
1799 _printf('%sasizesof(...%s%s) ...', linesep, c, o, **print3opts)
1800 for z, o in zip(sizes, objs):
1801 _printf('%*d bytes%s%s: %s', w, z, _SI(z), self._incl, self._repr(o), **print3opts)
1802 else:
1803 if objs:
1804 t = self._repr(objs)
1805 _printf('%sasizeof(%s%s%s) ...', linesep, t, c, o, **print3opts)
1806
1807 self.print_summary(w=w, objs=objs, **print3opts)
1808 if s > 1:
1809 c = int(s - int(s)) * 100
1810 self.print_profiles(w=w, cutoff=c, **print3opts)
1811 if s > 2:
1812 self.print_typedefs(w=w, **print3opts)
1813
1815 '''Print the summary statistics.
1816
1817 w=0 -- indentation for each line
1818 objs=() -- optional, list of objects
1819 print3options -- print options, as in Python 3.0
1820 '''
1821 _printf('%*d bytes%s%s', w, self._total, _SI(self._total), self._incl, **print3opts)
1822 if self._mask:
1823 _printf('%*d byte aligned', w, self._mask + 1, **print3opts)
1824 _printf('%*d byte sizeof(void*)', w, _sizeof_Cvoidp, **print3opts)
1825 n = len(objs or ())
1826 if n > 0:
1827 d = self._duplicate or ''
1828 if d:
1829 d = ', %d duplicate' % self._duplicate
1830 _printf('%*d object%s given%s', w, n, _plural(n), d, **print3opts)
1831 t = _sum([1 for t in _values(self._seen) if t != 0])
1832 _printf('%*d object%s sized', w, t, _plural(t), **print3opts)
1833 if self._excl_d:
1834 t = _sum(_values(self._excl_d))
1835 _printf('%*d object%s excluded', w, t, _plural(t), **print3opts)
1836 t = _sum(_values(self._seen))
1837 _printf('%*d object%s seen', w, t, _plural(t), **print3opts)
1838 if self._missed > 0:
1839 _printf('%*d object%s missed', w, self._missed, _plural(self._missed), **print3opts)
1840 if self._depth > 0:
1841 _printf('%*d recursion depth', w, self._depth, **print3opts)
1842
1844 '''Print the types and dict tables.
1845
1846 w=0 -- indentation for each line
1847 print3options -- print options, as in Python 3.0
1848 '''
1849 for k in _all_kinds:
1850
1851 t = [(self._prepr(a), v) for a, v in _items(_typedefs) if v.kind == k and (v.both or self._code_)]
1852 if t:
1853 _printf('%s%*d %s type%s: basicsize, itemsize, _len_(), _refs()',
1854 linesep, w, len(t), k, _plural(len(t)), **print3opts)
1855 for a, v in _sorted(t):
1856 _printf('%*s %s: %s', w, '', a, v, **print3opts)
1857
1858 t = _sum([len(v) for v in _values(_dict_classes)])
1859 if t:
1860 _printf('%s%*d dict/-like classes:', linesep, w, t, **print3opts)
1861 for m, v in _items(_dict_classes):
1862 _printf('%*s %s: %s', w, '', m, self._prepr(v), **print3opts)
1863
1864 - def set(self, align=None, code=None, detail=None, limit=None, stats=None):
1865 '''Set some options. Any options not set
1866 remain the same as the previous setting.
1867
1868 align=8 -- size alignment
1869 code=False -- incl. (byte)code size
1870 detail=0 -- Asized refs level
1871 limit=100 -- recursion limit
1872 stats=0.0 -- print statistics and cutoff percentage
1873 '''
1874
1875 if align is not None:
1876 self._align_ = align
1877 if align > 1:
1878 self._mask = align - 1
1879 if (self._mask & align) != 0:
1880 raise ValueError('invalid option: %s=%r' % ('align', align))
1881 else:
1882 self._mask = 0
1883 if code is not None:
1884 self._code_ = code
1885 if code:
1886 self._incl = ' (incl. code)'
1887 if detail is not None:
1888 self._detail_ = detail
1889 if limit is not None:
1890 self._limit_ = limit
1891 if stats is not None:
1892 self._stats_ = s = int(stats)
1893 self._cutoff = (stats - s) * 100
1894 if s > 1:
1895 self._profile = True
1896 else:
1897 self._profile = False
1898
1900 '''Number of duplicate objects.
1901 '''
1902 return self._duplicate
1903 duplicate = property(_get_duplicate, doc=_get_duplicate.__doc__)
1904
1906 '''Number of objects missed due to errors.
1907 '''
1908 return self._missed
1909 missed = property(_get_missed, doc=_get_missed.__doc__)
1910
1912 '''Total size accumulated so far.
1913 '''
1914 return self._total
1915 total = property(_get_total, doc=_get_total.__doc__)
1916
1917 - def reset(self, align=8, all=False, clip=80, code=False, derive=False,
1918 detail=0, ignored=True, infer=False, limit=100, stats=0):
1919 '''Reset options, state, etc.
1920
1921 The available options and default values are:
1922
1923 align=8 -- size alignment
1924 all=False -- all current GC objects and referents
1925 clip=80 -- clip repr() strings
1926 code=False -- incl. (byte)code size
1927 derive=False -- derive from super type
1928 detail=0 -- Asized refs level
1929 ignored=True -- ignore certain types
1930 infer=False -- try to infer types
1931 limit=100 -- recursion limit
1932 stats=0.0 -- print statistics and cutoff percentage
1933
1934 See function asizeof for a description of the options.
1935 '''
1936
1937 self._align_ = align
1938 self._all_ = all
1939 self._clip_ = clip
1940 self._code_ = code
1941 self._derive_ = derive
1942 self._detail_ = detail
1943 self._infer_ = infer
1944 self._limit_ = limit
1945 self._stats_ = stats
1946 if ignored:
1947 self._ign_d = _kind_ignored
1948 else:
1949 self._ign_d = None
1950
1951 self._clear()
1952 self.set(align=align, code=code, stats=stats)
1953
1954
1955
1956
1958 '''Install one or more classes to be handled as dict.
1959 '''
1960 a = True
1961 for c in classes:
1962
1963
1964 if isclass(c) and _infer_dict(c):
1965 t = _dict_classes.get(c.__module__, ())
1966 if c.__name__ not in t:
1967 _dict_classes[c.__module__] = t + (c.__name__,)
1968 else:
1969 a = False
1970 return a
1971
1972 _asizer = Asizer()
1973
1975 '''Return a tuple containing an Asized instance for each
1976 object passed as positional argment using the following
1977 options.
1978
1979 align=8 -- size alignment
1980 all=False -- all current GC objects and referents
1981 clip=80 -- clip repr() strings
1982 code=False -- incl. (byte)code size
1983 derive=False -- derive from super type
1984 detail=0 -- Asized refs level
1985 ignored=True -- ignore certain types
1986 infer=False -- try to infer types
1987 limit=100 -- recursion limit
1988 stats=0.0 -- print statistics and cutoff percentage
1989
1990 If only one object is given, the return value is the Asized
1991 instance for that object.
1992
1993 Set detail to the desired referents level (recursion depth).
1994
1995 See function asizeof for descriptions of the other options.
1996
1997 The length of the returned tuple matches the number of given
1998 objects, if more than one object is given.
1999 '''
2000 t = _objs(objs, **opts)
2001 if t:
2002 _asizer.reset(**opts)
2003 s = _asizer.asized(*t)
2004 _asizer.print_stats(objs=t, opts=opts, sized=s)
2005 _asizer._clear()
2006 else:
2007 s = ()
2008 return s
2009
2011 '''Return the combined size in bytes of all objects passed
2012 as positional argments.
2013
2014 The available options and defaults are the following.
2015
2016 align=8 -- size alignment
2017 all=False -- all current GC objects and referents
2018 clip=80 -- clip ``repr()`` strings
2019 code=False -- incl. (byte)code size
2020 derive=False -- derive from super type
2021 ignored=True -- ignore certain types
2022 infer=False -- try to infer types
2023 limit=100 -- recursion limit
2024 stats=0.0 -- print statistics and cutoff percentage
2025
2026 Set align to a power of 2 to align sizes. Any value less
2027 than 2 avoids size alignment.
2028
2029 All current GC objects are sized if all is True and if no
2030 positional arguments are supplied. Also, if all is True
2031 the GC referents are used instead of the limited ones.
2032
2033 A positive clip value truncates all repr() strings to at
2034 most clip characters.
2035
2036 The (byte)code size of callable objects like functions,
2037 methods, classes, etc. is included only if code is True.
2038
2039 If derive is True, new types are handled like an existing
2040 (super) type provided there is one and only of those.
2041
2042 By default, certain base types like object are ignored for
2043 sizing. Set ignored to False to force all ignored types
2044 in the size of objects.
2045
2046 By default certain base types like object, super, etc. are
2047 ignored. Set ignored to False to include those.
2048
2049 If infer is True, new types are inferred from attributes
2050 (only implemented for dict types on callable attributes
2051 as get, has_key, items, keys and values).
2052
2053 Set limit to a positive value to accumulate the sizes of
2054 the referents of each object, recursively up to the limit.
2055 Using limit zero returns the sum of the flat [1] sizes of
2056 the given objects. High limit values may cause runtime
2057 errors and miss objects for sizing.
2058
2059 A positive value for stats prints up to 8 statistics, (1)
2060 a summary of the number of objects sized and seen, (2) a
2061 simple profile of the sized objects by type and (3+) up to
2062 6 tables showing the static, dynamic, derived, ignored,
2063 inferred and dict types used, found respectively installed.
2064
2065 The fractional part of the stats value (x 100) is the cutoff
2066 percentage for simple profiles. Objects below the cutoff
2067 value are not reported.
2068
2069 [1] See the documentation of this module for the definition
2070 of flat size.
2071 '''
2072 t = _objs(objs, **opts)
2073 if t:
2074 _asizer.reset(**opts)
2075 s = _asizer.asizeof(*t)
2076 _asizer.print_stats(objs=t, opts=opts)
2077 _asizer._clear()
2078 else:
2079 s = 0
2080 return s
2081
2083 '''Return a tuple containing the size in bytes of all objects
2084 passed as positional argments using the following options.
2085
2086 align=8 -- size alignment
2087 all=False -- use GC objects and referents
2088 clip=80 -- clip ``repr()`` strings
2089 code=False -- incl. (byte)code size
2090 derive=False -- derive from super type
2091 ignored=True -- ignore certain types
2092 infer=False -- try to infer types
2093 limit=100 -- recursion limit
2094 stats=0.0 -- print statistics and cutoff percentage
2095
2096 See function asizeof for a description of the options.
2097
2098 The length of the returned tuple equals the number of given
2099 objects.
2100 '''
2101 t = _objs(objs, **opts)
2102 if t:
2103 _asizer.reset(**opts)
2104 s = _asizer.asizesof(*t)
2105 _asizer.print_stats(objs=t, opts=opts, sizes=s)
2106 _asizer._clear()
2107 else:
2108 s = ()
2109 return s
2110
2121
2123 '''Return the basic size of an object (in bytes).
2124
2125 Valid options and defaults are
2126 derive=False -- derive type from super type
2127 infer=False -- try to infer types
2128 save=False -- save typedef if new
2129 '''
2130 v = _typedefof(obj, **opts)
2131 if v:
2132 v = v.base
2133 return v
2134
2136 '''Return the flat size of an object (in bytes),
2137 optionally aligned to a given power of 2.
2138
2139 See function basicsize for a description of
2140 the other options. See the documentation of
2141 this module for the definition of flat size.
2142 '''
2143 v = _typedefof(obj, **opts)
2144 if v:
2145 if align > 1:
2146 m = align - 1
2147 if (align & m) != 0:
2148 raise ValueError('invalid option: %s=%r' % ('align', align))
2149 else:
2150 m = 0
2151 v = v.flat(obj, m)
2152 return v
2153
2155 '''Return the item size of an object (in bytes).
2156
2157 See function basicsize for a description of
2158 the options.
2159 '''
2160 v = _typedefof(obj, **opts)
2161 if v:
2162 v = v.item
2163 return v
2164
2165 -def leng(obj, **opts):
2166 '''Return the length of an object (in items).
2167
2168 See function basicsize for a description
2169 of the options.
2170 '''
2171 v = _typedefof(obj, **opts)
2172 if v:
2173 v = v.leng
2174 if v and _callable(v):
2175 v = v(obj)
2176 return v
2177
2178 -def refs(obj, all=False, **opts):
2179 '''Return (a generator for) specific referents of an
2180 object.
2181
2182 If all is True return the GC referents.
2183
2184 See function basicsize for a description of the
2185 options.
2186 '''
2187 v = _typedefof(obj, **opts)
2188 if v:
2189 if all:
2190 v = _getreferents(obj)
2191 else:
2192 v = v.refs
2193 if v and _callable(v):
2194 v = v(obj, False)
2195 return v
2196
2197
2198 if __name__ == '__main__':
2199
2200 argv, MAX = sys.argv, sys.getrecursionlimit()
2201
2203 a = [_repr(obj),]
2204 for d, c in ((0, False), (MAX, False), (MAX, True)):
2205 a.append(asizeof(obj, limit=d, code=c, infer=infer, stats=stats))
2206 _printf(" asizeof(%s) is %d, %d, %d", *a)
2207
2208 - def _print_functions(obj, name=None, align=8, detail=MAX, code=False, limit=MAX,
2209 opt='', **unused):
2210 if name:
2211 _printf('%sasizeof functions for %s ... %s', linesep, name, opt)
2212 _printf('%s(): %s', ' basicsize', basicsize(obj))
2213 _printf('%s(): %s', ' itemsize', itemsize(obj))
2214 _printf('%s(): %r', ' leng', leng(obj))
2215 _printf('%s(): %s', ' refs', _repr(refs(obj)))
2216 _printf('%s(): %s', ' flatsize', flatsize(obj, align=align))
2217 _printf('%s(): %s', ' asized', asized(obj, align=align, detail=detail, code=code, limit=limit))
2218
2219
2221 a = arg.lower()
2222 if a in ('1', 't', 'y', 'true', 'yes', 'on'):
2223 return True
2224 elif a in ('0', 'f', 'n', 'false', 'no', 'off'):
2225 return False
2226 else:
2227 raise ValueError('bool option expected: %r' % arg)
2228
2230 '''Return True if any oof the given options
2231 was present in the command line arguments.
2232 '''
2233 for o in opts + ('-', '--'):
2234 if o in argv:
2235 return True
2236 return False
2237
2238 if '-im' in argv or '-import' in argv:
2239
2240
2242 '''Get argv options as typed values.
2243 '''
2244 i = 1
2245 while argv[i].startswith('-'):
2246 k = argv[i].lstrip('-')
2247 if 'import'.startswith(k):
2248 i += 1
2249 elif k in opts:
2250 t = type(opts[k])
2251 if t is bool:
2252 t = _bool
2253 i += 1
2254 opts[k] = t(argv[i])
2255 i += 1
2256 else:
2257 raise NameError('invalid option: %s' % argv[i])
2258 return opts, i
2259
2260 opts, i = _aopts(argv, align=8, clip=80, code=False, derive=False, detail=MAX, limit=MAX, stats=0)
2261 while i < len(argv):
2262 m, i = argv[i], i + 1
2263 if m == 'eval' and i < len(argv):
2264 o, i = eval(argv[i]), i + 1
2265 else:
2266 o = __import__(m)
2267 s = asizeof(o, **opts)
2268 _printf("%sasizeof(%s) is %d", linesep, _repr(o, opts['clip']), s)
2269 _print_functions(o, **opts)
2270 argv = []
2271
2272 elif len(argv) < 2 or _opts('-h', '-help'):
2273 d = {'-all': 'all=True example',
2274 '-basic': 'basic examples',
2275 '-C': 'Csizeof values',
2276 '-class': 'class and instance examples',
2277 '-code': 'code examples',
2278 '-dict': 'dict and UserDict examples',
2279
2280 '-gen[erator]': 'generator examples',
2281 '-glob[als]': 'globals examples, incl. asized()',
2282 '-h[elp]': 'print this information',
2283 '-im[port] <module>': 'imported module example',
2284 '-int | -long': 'int and long examples',
2285 '-iter[ator]': 'iterator examples',
2286 '-loc[als]': 'locals examples',
2287 '-pair[s]': 'key pair examples',
2288 '-slots': 'slots examples',
2289 '-stack': 'stack examples',
2290 '-sys': 'sys.modules examples',
2291 '-test': 'test flatsize() vs sys.getsizeof()',
2292 '-type[def]s': 'type definitions',
2293 '- | --': 'all examples'}
2294 w = -max([len(o) for o in _keys(d)])
2295 t = _sorted(['%*s -- %s' % (w, o, t) for o, t in _items(d)])
2296 t = '\n '.join([''] + t)
2297 _printf('usage: %s <option> ...\n%s\n', argv[0], t)
2298
2300
2302 _attr1 = None
2303 _attr2 = None
2304
2307 self._attr1 = a1
2308 self._attr2 = a2
2309
2315
2317 a = None
2318 b = None
2319
2321 __slots__ = ('a', 'b')
2322
2324 __slots__ = ('a', 'b')
2327
2328 if _opts('-all'):
2329 _printf('%sasizeof(limit=%s, code=%s, %s) ... %s', linesep, 'MAX', True, 'all=True', '-all')
2330 asizeof(limit=MAX, code=True, stats=MAX, all=True)
2331
2332 if _opts('-basic'):
2333 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<basic_objects>', '((0, False), (MAX, False), (MAX, True))', '-basic')
2334 for o in (None, True, False,
2335 1.0, 1.0e100, 1024, 1000000000,
2336 '', 'a', 'abcdefg',
2337 {}, (), []):
2338 _print_asizeof(o, infer=True)
2339
2340 if _opts('-C'):
2341 _sizeof_Cdouble = calcsize('d')
2342 _sizeof_Csize_t = calcsize('Z')
2343 _sizeof_Cssize_t = calcsize('z')
2344 t = [t for t in locals().items() if t[0].startswith('_sizeof_')]
2345 _printf('%s%d C sizes: (bytes) ... -C', linesep, len(t))
2346 for n, v in _sorted(t):
2347 _printf(' sizeof(%s): %r', n[len('_sizeof_'):], v)
2348
2349 if _opts('-class'):
2350 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<non-callable>', '((0, False), (MAX, False), (MAX, True))', '-class')
2351 for o in (C(), C.__dict__,
2352 D(), D.__dict__,
2353 E(), E.__dict__,
2354 P(), P.__dict__, P.p,
2355 O(), O.__dict__,
2356 S(), S.__dict__,
2357 S(), S.__dict__,
2358 T(), T.__dict__):
2359 _print_asizeof(o, infer=True)
2360
2361 if _opts('-code'):
2362 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<callable>', '((0, False), (MAX, False), (MAX, True))', '-code')
2363 for o in (C, D, E, P, S, T,
2364 type,
2365 _co_refs, _dict_refs, _inst_refs, _len_int, _seq_refs, lambda x: x,
2366 (_co_refs, _dict_refs, _inst_refs, _len_int, _seq_refs),
2367 _typedefs):
2368 _print_asizeof(o)
2369
2370 if _opts('-dict'):
2371 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<Dicts>', '((0, False), (MAX, False), (MAX, True))', '-dict')
2372 try:
2373 import UserDict
2374 for o in (UserDict.IterableUserDict(), UserDict.UserDict()):
2375 _print_asizeof(o)
2376 except ImportError:
2377 pass
2378
2381
2382 for o in (dict(), _Dict(),
2383 P.__dict__,
2384 Weakref.WeakKeyDictionary(), Weakref.WeakValueDictionary(),
2385 _typedefs):
2386 _print_asizeof(o, infer=True)
2387
2388
2389
2390
2391
2392
2393
2394
2395 if _opts('-gen', '-generator'):
2396 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<generator>', True, '-gen[erator]')
2398 i = 0
2399 while i < x:
2400 yield i
2401 i += 1
2402 a = gen(5)
2403 b = gen(50)
2404 asizeof(a, code=True, stats=1)
2405 asizeof(b, code=True, stats=1)
2406 asizeof(a, code=True, stats=1)
2407
2408 if _opts('-glob', '-globals'):
2409 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'globals()', 'MAX', False, '-glob[als]')
2410 asizeof(globals(), limit=MAX, code=False, stats=1)
2411 _print_functions(globals(), 'globals()', opt='-glob[als]')
2412
2413 _printf('%sasizesof(%s, limit=%s, code=%s) ... %s', linesep, 'globals(), locals()', 'MAX', False, '-glob[als]')
2414 asizesof(globals(), locals(), limit=MAX, code=False, stats=1)
2415 asized(globals(), align=0, detail=MAX, limit=MAX, code=False, stats=1)
2416
2417 if _opts('-int', '-long'):
2418 try:
2419 _L5d = long(1) << 64
2420 _L17d = long(1) << 256
2421 t = '<int>/<long>'
2422 except NameError:
2423 _L5d = 1 << 64
2424 _L17d = 1 << 256
2425 t = '<int>'
2426
2427 _printf('%sasizeof(%s, align=%s, limit=%s) ... %s', linesep, t, 0, 0, '-int')
2428 for o in (1024, 1000000000,
2429 1.0, 1.0e100, 1024, 1000000000,
2430 MAX, 1 << 32, _L5d, -_L5d, _L17d, -_L17d):
2431 _printf(" asizeof(%s) is %s (%s + %s * %s)", _repr(o), asizeof(o, align=0, limit=0),
2432 basicsize(o), leng(o), itemsize(o))
2433
2434 if _opts('-iter', '-iterator'):
2435 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<iterator>', False, '-iter[ator]')
2436 o = iter('0123456789')
2437 e = iter('')
2438 d = iter({})
2439 i = iter(_items({1:1}))
2440 k = iter(_keys({2:2, 3:3}))
2441 v = iter(_values({4:4, 5:5, 6:6}))
2442 l = iter([])
2443 t = iter(())
2444 asizesof(o, e, d, i, k, v, l, t, limit=0, code=False, stats=1)
2445 asizesof(o, e, d, i, k, v, l, t, limit=9, code=False, stats=1)
2446
2447 if _opts('-loc', '-locals'):
2448 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'locals()', 'MAX', False, '-loc[als]')
2449 asizeof(locals(), limit=MAX, code=False, stats=1)
2450 _print_functions(locals(), 'locals()', opt='-loc[als]')
2451
2452 if _opts('-pair', '-pairs'):
2453
2454 _printf('%sasizeof(%s) vs asizeof(%s) ... %s', linesep, 'dict[i][j]', 'dict[(i,j)]', '-pair[s]')
2455 n = m = 200
2456
2457 p = {}
2458 for i in range(n):
2459 q = {}
2460 for j in range(m):
2461 q[j] = None
2462 p[i] = q
2463 p = asizeof(p, stats=1)
2464
2465 t = {}
2466 for i in range(n):
2467 for j in range(m):
2468 t[(i,j)] = None
2469 t = asizeof(t, stats=1)
2470
2471 _printf('%sasizeof(dict[i][j]) is %s of asizeof(dict[(i,j)])', linesep, _p100(p, t))
2472
2473 if _opts('-slots'):
2474 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<__slots__>', False, '-slots')
2477 - class New(object):
2480 __slots__ = {'s': ''}
2482 New.__init__(self)
2483
2484 o, n, s = Old(), New(), Sub()
2485 asizesof(o, n, s, limit=MAX, code=False, stats=1)
2486
2487 o.o = 'o'
2488 n.n = 'n'
2489 s.n = 'S'
2490 s.s = 's'
2491 asizesof(o, n, s, limit=MAX, code=False, stats=1)
2492
2493 o.o = 'x'
2494 n.n = 'x'
2495 s.n = 'x'
2496 s.s = 'x'
2497 asizesof(o, n, s, 'x', limit=MAX, code=False, stats=1)
2498
2499 o.o = 'o'*1000
2500 n.n = 'n'*1000
2501 s.n = 'n'*1000
2502 s.s = 's'*1000
2503 asizesof(o, n, s, 'x'*1000, limit=MAX, code=False, stats=1)
2504
2505 if _opts('-stack'):
2506 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'stack(MAX)', 'MAX', False, '')
2507 asizeof(stack(MAX), limit=MAX, code=False, stats=1)
2508 _print_functions(stack(MAX), 'stack(MAX)', opt='-stack')
2509
2510 if _opts('-sys'):
2511 _printf('%sasizeof(limit=%s, code=%s, *%s) ... %s', linesep, 'MAX', False, 'sys.modules.values()', '-sys')
2512 asizeof(limit=MAX, code=False, stats=1, *sys.modules.values())
2513 _print_functions(sys.modules, 'sys.modules', opt='-sys')
2514
2515 if _opts('-type', '-types', '-typedefs'):
2516 t = len(_typedefs)
2517 w = len(str(t)) * ' '
2518 _printf('%s%d type definitions: basic- and itemsize (leng), kind ... %s', linesep, t, '-type[def]s')
2519 for k, v in _sorted([(_prepr(k), v) for k, v in _items(_typedefs)]):
2520 s = '%(base)s and %(item)s%(leng)s, %(kind)s%(code)s' % v.format()
2521 _printf('%s %s: %s', w, k, s)
2522
2523 if _opts('-test'):
2524
2525
2526
2527
2528
2529
2530 _printf('%sflatsize() vs sys.getsizeof() ... %s', linesep, '-test')
2531 t, g, e = [], _getsizeof, 0
2532 if g:
2533 for v in _values(_typedefs):
2534 t.append(v.type)
2535 try:
2536 if v.type.__module__ not in ('io',):
2537 t.append(v.type())
2538 except (AttributeError, SystemError, TypeError, ValueError):
2539 pass
2540 t.extend(({1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8},
2541 [1,2,3,4,5,6,7,8], ['1', '2', '3'], [0] * 100,
2542 '12345678', 'x' * 1001,
2543 (1,2,3,4,5,6,7,8), ('1', '2', '3'), (0,) * 100,
2544 _Slots((1,2,3,4,5,6,7,8)), _Slots(('1', '2', '3')), _Slots((0,) * 100),
2545 0, 1 << 8, 1 << 16, 1 << 32, 1 << 64, 1 << 128,
2546 complex(0, 1), True, False))
2547 _getsizeof = None
2548 for o in t:
2549 a = flatsize(o)
2550 s = sys.getsizeof(o, 0)
2551 if a != s:
2552
2553
2554 if type(o) in (dict, list, set, frozenset, tuple) or (
2555 type(o) in (bool,) and sys.version_info[0] == 3):
2556 x = 'expected failure'
2557 else:
2558 x = '%r' % _typedefof(o)
2559 e += 1
2560 _printf('flatsize() %s vs sys.getsizeof() %s for %s: %s, %s',
2561 a, s, _nameof(type(o)), _repr(o), x)
2562 _getsizeof = g
2563 n, p = len(t), 'python %s' % sys.version.split()[0]
2564 if e:
2565 _printf('%s%d of %d tests failed or %s on %s', linesep, e, n, _p100(e, n), p)
2566 elif g:
2567 _printf('no unexpected failures in %d tests on %s', n, p)
2568 else:
2569 _printf('no sys.%s() in this %s', 'getsizeof', p)
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608