%PDF- %PDF-
Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/heapy/ |
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/heapy/Part.py |
class Format(object): __slots__ = 'impl', 'mod' def __init__(self, impl): self.impl = impl self.mod = impl.mod def get_formatted_row(self, row): fr = self.get_stat_data(row) rows = [] rs = row.name.split('\n') subsequent_indent = len(fr)*' ' rows.extend(self.mod.wrap( fr+rs[0], width=self.mod.line_length, subsequent_indent=subsequent_indent)) for r in rs[1:]: rows.extend(self.mod.wrap( r, width=self.mod.line_length, initial_indent=subsequent_indent, subsequent_indent=subsequent_indent)) return '\n'.join(rows) def load_statrow_csk(self, r): impl = self.impl count, size, kind = r.split(' ', 2) count = int(count) size = int(size) impl.cum_size += size return StatRow(count, size, kind, impl.cur_index, impl.cum_size) def load_statrow_sk(self, r): impl = self.impl size, kind = r.split(' ', 1) size = int(size) impl.cum_size += size return StatRow(1, size, kind, impl.cur_index, impl.cum_size) def _oh_get_num_lines(self): return self.impl.numrows def _oh_get_label(self): return self.get_label() def _oh_get_row_header(self): impl = self.impl if not (impl.count or impl.size): return '' sh = self.get_stat_header() return self.mod.fill( sh + self.impl.kindheader, width=self.mod.line_length, subsequent_indent=' '*len(sh)) def _oh_get_more_msg(self, start_lineno, end_lineno): nummore = self.impl.numrows-(end_lineno+1) return "<%d more rows. Type e.g. '_.more' to view.>" % nummore def _oh_get_line_iter(self): for numrows, row in enumerate(self.impl.get_rows()): yield self.get_formatted_row(row) class SetFormat(Format): __slots__ = () def get_label(self): impl = self.impl if impl.count != 1: s = 's' else: s = '' return 'Partition of a set of %d object%s. Total size = %d bytes.' % ( impl.count, s, impl.size) def get_rowdata(self, row): return '%d %d %s' % (row.count, row.size, row.name) def get_stat_header(self): return ( ' Index Count % Size % Cumulative % ') def get_stat_data(self, row): format = '%6d %6d %3d %8d %3d %9d %3d ' impl = self.impl fr = format % ( row.index, row.count, int('%.0f' % (row.count * 100.0/impl.count)), row.size, int('%.0f' % (row.size * 100.0/impl.size)), row.cumulsize, int('%.0f' % (row.cumulsize * 100.0/impl.size)), ) return fr def load_statrow(self, r): return self.load_statrow_csk(r) class IdFormat(Format): __slots__ = () def get_label(self): impl = self.impl if impl.count != 1: s = 's' else: s = '' return ( 'Set of %d %s object%s. Total size = %d bytes.' % ( impl.count, impl.kindname, s, impl.size)) return part def get_rowdata(self, row): return '%d %s' % (row.size, row.name) def get_stat_header(self): return ( ' Index Size % Cumulative % ') def get_stat_data(self, row): impl = self.impl format = '%6d %8d %5.1f %9d %5.1f ' fr = format % ( row.index, row.size, (row.size * 100.0/impl.size), row.cumulsize, row.cumulsize * 100.0/impl.size, ) return fr def load_statrow(self, r): return self.load_statrow_sk(r) class DiffFormat(Format): __slots__ = () def _percent_of_b(self, size): if self.impl.b_size != 0: return '%9.3g' % (size*100.0/self.impl.b_size,) else: return ' (n.a.)' def get_label(self): impl = self.impl x = ( 'Summary of difference operation (A-B).\n' + ' Count Size\n' + ' A %6d %8d\n' % (impl.count+impl.b_count, impl.size+impl.b_size) + ' B %6d %8d\n' % (impl.b_count, impl.b_size) + ' A-B %6d %8d = %s %% of B\n' % (impl.count, impl.size, self._percent_of_b(impl.size))) if impl.count or impl.size: x += '\nDifferences by kind, largest absolute size diffs first.' return x def get_rowdata(self, row): return '%d %d %s' % (row.count, row.size, row.name) def get_stat_header(self): return ( ' Index Count Size Cumulative % of B ') def get_stat_data(self, row): impl = self.impl format = '%6d %6d %8d %9d %s ' fr = format % ( row.index, row.count, row.size, row.cumulsize, self._percent_of_b(row.cumulsize), ) return fr def load_statrow(self, r): return self.load_statrow_csk(r) class StatRow(object): __slots__ = 'count', 'size', 'name', 'index', 'cumulsize' def __init__(self, count, size, name, index=None, cumulsize=None): self.count = count self.size = size self.name = name self.index = index self.cumulsize = cumulsize class PartRow(StatRow): __slots__ = 'set', 'kind' def __init__(self, count, size, name, index, cumulsize, set, kind): self.count = count self.size = size self.name = name self.index = index self.cumulsize = cumulsize self.set = set self.kind = kind class Stat: def __init__(self, mod, get_trows, firstheader=''): self.mod = mod self._hiding_tag_ = mod._hiding_tag_ self.get_trows = get_trows self.firstheader = firstheader self.it = iter(get_trows()) self.cur_index = 0 self.cum_size = 0 self.rows = [] r = self.get_next() while r and not r.startswith('.r:'): name = r[1:r.index(':')] value = r[r.index(':')+1:].strip() try: value = int(value) except ValueError: pass setattr(self, name, value) r = self.get_next() self.format_name = self.format self.format_class = getattr(self.mod, self.format) self.format = self.format_class(self) self.timemade = float(self.timemade) self.mod.OutputHandling.setup_printing(self, self.format) def __getitem__(self, idx): if isinstance(idx, int): if idx < 0: idx = self.numrows + idx if not (0 <= idx < self.numrows): raise IndexError('Stat index out of range.') rows = [self.get_row(idx)] elif isinstance(idx, slice): start, stop, step = idx.indices(self.numrows) rows = [self.get_row(idx) for idx in range(start, stop, step)] else: raise IndexError('Stat indices must be integers or slices.') count = 0 size = 0 for r in rows: count += r.count size += r.size trows = [ '.loader: _load_stat', '.format: %s' % self.format_name, '.timemade: %f' % self.timemade, '.count: %d' % count, '.size: %d' % size, '.kindheader: %s' % self.kindheader, '.kindname: %s' % self.kindname, '.numrows: %d' % len(rows), ] if getattr(self, 'b_count', None) is not None: trows.append('.b_count: %d' % self.b_count) trows.append('.b_size: %d' % self.b_size) for r in rows: trows.append('.r: %s' % self.format.get_rowdata(r)) return self.mod.load(trows) def __len__(self): return self.numrows def __sub__(self, other): if not isinstance(other, Stat): raise TypeError( 'Can only take difference with other Stat instance.') if self.kindheader != other.kindheader: raise ValueError('Mismatching table kind header, %r vs %r.' % ( self.kindheader, other.kindheader)) rows = [] otab = {} stab = {} for r in other.get_rows(): o = otab.get(r.name) if o: otab[r.name] = StatRow( r.count+o.count, r.size+o.size, r.name, o.index, None) else: otab[r.name] = r for r in self.get_rows(): o = otab.get(r.name) if o: del otab[r.name] count = r.count - o.count size = r.size - o.size else: count = r.count size = r.size if count == 0 and size == 0: continue sr = stab.get(r.name) if sr: sr.count += count sr.size += size else: sr = StatRow(count, size, r.name) stab[sr.name] = sr rows.append(sr) rs = list(otab.values()) rs.sort(key=lambda x: x.index) # Preserve orig. order for r in rs: sr = StatRow(-r.count, -r.size, r.name) assert sr.name not in stab rows.append(sr) rows.sort(key=lambda x: abs(x.size), reverse=True) cumulcount = 0 cumulsize = 0 for r in rows: cumulcount += r.count cumulsize += r.size r.cumulsize = cumulsize trows = [ '.loader: _load_stat', '.format: DiffFormat', '.timemade: %f' % self.mod.time.time(), '.b_count: %d' % other.count, '.b_size: %d' % other.size, '.count: %d' % cumulcount, '.size: %d' % cumulsize, '.kindheader: %s' % self.kindheader, '.kindname: %s' % self.kindname, '.numrows: %d' % len(rows), ] for r in rows: trows.append('.r: %d %d %s' % (r.count, r.size, r.name)) return self.mod.load(trows) def dump(self, fn, mode='a'): if not hasattr(fn, 'write'): f = open(fn, mode) else: f = fn try: for r in self.get_trows(): if not r[-1:] == '\n': r += '\n' f.write(r) end = '.end: .loader: %s\n' % self.loader if r != end: f.write(end) finally: if f is not fn: f.close() def get_next(self): try: r = next(self.it) except StopIteration: r = None else: r = r.rstrip('\n') self.last = r return r def get_row(self, idx): while idx >= len(self.rows): self.parse_next_row() return self.rows[idx] def get_rows(self, idx=0): while idx < self.numrows: try: row = self.get_row(idx) except IndexError: return else: yield row idx += 1 def get_rows_of_kinds(self, kinds): # Return the rows with names in sequence kinds of unique names # in that order. None if no such kind. kindtab = {} N = len(kinds) res = [None] * len(kinds) for i, kind in enumerate(kinds): kindtab[kind] = i assert len(kindtab) == N n = 0 for row in self.get_rows(): idx = kindtab.get(row.name) if idx is not None: res[idx] = row n += 1 if n >= N: break return res def get_rows_n_and_other(self, N, sortby='Size'): # Get N rows, the largest first # mix in an '<Other>' row at a sorted position # Size is either size if sortby = 'Size', # or count if sortby = 'Count'. # Returns a NEW LIST (caller may modify/sort it) if sortby not in ('Size', 'Count'): raise ValueError("Argument 'sortby' must be 'Size' or 'Count'.") # Rows are already sorted by Size, largest first. # If they want by Count, we need to resort them. rows = self.get_rows() if sortby == 'Count': rows = list(rows) rows.sort(key=lambda x: x.count, reverse=True) retrows = [] cumulcount = 0 cumulsize = 0 for (i, r) in enumerate(rows): if i >= N: othercount = self.count - cumulcount othersize = self.size - cumulsize other = StatRow(othercount, othersize, '<Other>') if sortby == 'Size': for (i, r) in enumerate(retrows): if r.size < othersize: retrows[i:i] = [other] break else: retrows.append(other) elif sortby == 'Count': for (i, r) in enumerate(retrows): if r.count < othercount: retrows[i:i] = [other] break else: retrows.append(other) else: assert 0 break cumulcount += r.count cumulsize += r.size retrows.append(r) else: assert cumulcount == self.count assert cumulsize == self.size return retrows def parse_next_row(self): r = self.last if not r: raise IndexError('Row index out of range.') if r.startswith('.r: '): r = r[4:] sr = self.format.load_statrow(r) self.cur_index += 1 self.rows.append(sr) self.get_next() return elif r.startswith('.end'): raise IndexError('Row index out of range.') else: raise SyntaxError class Partition: def __init__(self, mod, set, er): self.mod = mod self.set = set self.er = er self._hiding_tag_ = mod._hiding_tag_ self.timemade = mod.time.time() def __iter__(self): # The default iteration is over the sets # To iterate over rows (if more info is needed), get_rows() is available. return self.get_sets() def get_rows(self, rowindex=None): # Iterator over rows if rowindex is None: rowindex = 0 while 1: try: row = self.get_row(rowindex) except IndexError: return else: yield row rowindex += 1 def get_set(self, index): if isinstance(index, slice): start, stop, step = index.indices(self.numrows) ns = self.get_nodeset(start, stop, step) return self.mod.idset(ns, er=self.er) else: if index < 0: index += self.numrows return self.get_rowset(index) def get_sets(self, index=None): for idx in range(self.numrows): yield self.get_rowset(idx) def get_stat(self): # Avoid any references into the set! trows = list(self.get_trows()) def get_trows(): return trows return self.mod._load_stat(get_trows) def get_trows(self): yield '.loader: _load_stat' yield '.format: %s' % self.format.__class__.__name__ yield '.timemade: %f' % self.timemade yield '.count: %d' % self.count yield '.size: %d' % self.size yield '.kindname: %s' % self.kindname yield '.kindheader: %s' % self.kindheader yield '.numrows: %d' % self.numrows for row in self.get_rows(): yield '.r: %s' % self.format.get_rowdata(row) def init_format(self, FormatClass): self.format = FormatClass(self) self.mod.OutputHandling.setup_printing(self, self.format) class IdentityPartitionCluster(object): # Contains objects of same size. # to speed up management of identity partition # - since otherwise we'd have to sort all the objects, # on their string representation in worst case. __slots__ = 'objects', 'locount', 'hicount', 'losize', 'obsize', 'issorted' def __init__(self, objects, locount, count, losize, obsize): self.objects = objects # tuple of objects in this segment self.locount = locount # count BEFORE objects in this cluster self.hicount = locount+count # count AFTER these objects self.losize = losize # size BEFORE objects in this cluster self.obsize = obsize # size of EACH object in this segment self.issorted = False # indicates if .objects is sorted class IdentityPartition(Partition): def __init__(self, mod, set, er): Partition.__init__(self, mod, set, er) clusters = [] sizeclasses = mod.Size.classifier.partition_cli(set.nodes) sizeclasses.sort() sizeclasses.reverse() totcount = 0 totsize = 0 for size, v in sizeclasses: count = len(v) clusters.append(IdentityPartitionCluster( self.mod.observation_list(v), totcount, count, totsize, size)) totsize += size * count totcount += count assert totcount == set.count self.cluidx = 0 self.clusters = clusters self.count = totcount self.kind = kind = set.byclodo.kind self.kindheader = kind.fam.c_get_idpart_header(kind) self.kindname = kind.fam.c_get_idpart_label(kind) self.numrows = totcount self.render = kind.fam.c_get_idpart_render(kind) self.size = totsize self.sortrender = kind.fam.c_get_idpart_sortrender(kind) self.init_format(IdFormat) def get_nodeset(self, start, stop, step): return self.get_nodeset_cluster(start, stop, step)[0] def get_nodeset_cluster(self, start, stop, step): if step <= 0: raise ValueError('Step must be positive.') ns = self.mod.mutnodeset() if start >= stop: return (ns, None) clusters = self.clusters lo = 0 hi = len(clusters) cluidx = self.cluidx while lo < hi: clu = clusters[cluidx] if clu.locount <= start: if start < clu.hicount: break else: lo = cluidx + 1 else: hi = cluidx cluidx = (lo + hi) // 2 else: return (ns, None) clu_to_return = clu while 1: objects = clu.objects if start != clu.locount or stop < clu.hicount or step != 1: if not clu.issorted: sortrender = self.sortrender if sortrender == 'IDENTITY': ks = objects else: ks = [sortrender(x) for x in objects] ks = [(kind, i) for i, kind in enumerate(ks)] ks.sort() clu.objects = objects = self.mod.observation_list( [objects[i] for (kind, i) in ks]) clu.issorted = True objects = objects[start-clu.locount:stop-clu.locount:step] ns |= objects self.cluidx = cluidx # memo till next call start += len(objects)*step if start >= stop: break for cluidx in range(cluidx + 1, len(clusters)): clu = clusters[cluidx] if clu.locount <= start < clu.hicount: break else: break return (ns, clu_to_return) def get_row(self, rowidx): ns, clu = self.get_nodeset_cluster(rowidx, rowidx+1, 1) if not ns: raise IndexError('Partition index out of range.') vi = self.mod.idset(ns, er=self.er) row = PartRow(1, clu.obsize, self.render(vi.theone), rowidx, (rowidx+1-clu.locount)*clu.obsize + clu.losize, vi, vi.kind) return row def get_rowset(self, rowidx): ns = self.get_nodeset(rowidx, rowidx+1, 1) if not ns: raise IndexError('Partition index out of range.') return self.mod.idset(ns, er=self.er) class SetPartition(Partition): def __init__(self, mod, set, er): Partition.__init__(self, mod, set, er) classifier = er.classifier tosort = [(-part.size, classifier.get_tabrendering(kind, ''), kind, part) for (kind, part) in classifier.partition(set.nodes)] tosort.sort() cumulsize = 0 rows = [] for (minusize, name, kind, part) in tosort: size = -minusize cumulsize += size rows.append(PartRow( part.count, size, name, len(rows), cumulsize, part, kind)) self.count = set.count self.kindheader = classifier.get_tabheader('') self.kindname = '' self.numrows = len(rows) self.rows = rows self.size = cumulsize self.init_format(SetFormat) def get_nodeset(self, start, stop, step): if step <= 0: raise ValueError('Step must be positive.') ns = self.mod.mutnodeset() while start < stop: ns |= self.rows[start].set.nodes start += step return ns def get_row(self, idx): try: return self.rows[idx] except IndexError: raise IndexError('Partition index out of range.') def get_rowset(self, idx): row = self.get_row(idx) set = row.set try: set._partition except AttributeError: set._partition = self.mod._fast_partition(self, row) return set class FastPartition(SetPartition): def __init__(self, mod, parent, row): Partition.__init__(self, mod, parent.set, parent.er) self.count = row.count self.kindheader = parent.kindheader self.kindname = '' self.numrows = 1 self.rows = [row] self.size = row.size self.init_format(SetFormat) class _GLUECLAMP_: _preload_ = ('_hiding_tag_',) _chgable_ = ('line_length', 'backup_suffix') _imports_ = ( '_parent.ImpSet:mutnodeset', '_parent:OutputHandling', '_parent.Use:Id', '_parent.Use:Size', '_parent.Use:idset', '_parent.Use:load', '_parent.View:_hiding_tag_', '_parent.View:observation_list', '_root.os:rename', '_root.textwrap:fill', '_root.textwrap:wrap', '_root.textwrap:wrap', '_root:time', ) # 'Config' line_length = 100 backup_suffix = '.old' # Factory method def partition(self, set, er): if er.classifier is self.Id.classifier: return IdentityPartition(self, set, er) else: return SetPartition(self, set, er) # Private - Use.load is intended to be used directly. def _load_stat(self, get_trows): return Stat(self, get_trows) def _fast_partition(self, parent, row): return FastPartition(self, parent, row)