# HG changeset patch # User Gregory Szorc <gregory.sz...@gmail.com> # Date 1471227612 25200 # Sun Aug 14 19:20:12 2016 -0700 # Node ID 5fced4748aeb241c3f6eac4b3e28baf8ae6632a1 # Parent f125cafb95bdc382d3b17b2c2e422b3cf8a08252 statprof: use print function
diff --git a/mercurial/statprof.py b/mercurial/statprof.py --- a/mercurial/statprof.py +++ b/mercurial/statprof.py @@ -97,17 +97,17 @@ Threading Because signals only get delivered to the main thread in Python, statprof only profiles the main thread. However because the time reporting function uses per-process timers, the results can be significantly off if other threads' work patterns are not similar to the main thread's work patterns. """ # no-check-code -from __future__ import absolute_import, division +from __future__ import absolute_import, division, print_function import collections import contextlib import getopt import inspect import json import os import signal @@ -427,17 +427,17 @@ class DisplayFormats: def display(fp=None, format=3, **kwargs): '''Print statistics, either to stdout or the given file object.''' if fp is None: import sys fp = sys.stdout if len(state.samples) == 0: - print >> fp, ('No samples recorded.') + print('No samples recorded.', file=fp) return if format == DisplayFormats.ByLine: display_by_line(fp) elif format == DisplayFormats.ByMethod: display_by_method(fp) elif format == DisplayFormats.AboutMethod: display_about_method(fp, **kwargs) @@ -446,47 +446,48 @@ def display(fp=None, format=3, **kwargs) elif format == DisplayFormats.FlameGraph: write_to_flame(fp) elif format == DisplayFormats.Json: write_to_json(fp) else: raise Exception("Invalid display format") if format != DisplayFormats.Json: - print >> fp, ('---') - print >> fp, ('Sample count: %d' % len(state.samples)) - print >> fp, ('Total time: %f seconds' % state.accumulated_time) + print('---', file=fp) + print('Sample count: %d' % len(state.samples), file=fp) + print('Total time: %f seconds' % state.accumulated_time, file=fp) def display_by_line(fp): '''Print the profiler data with each sample line represented as one row in a table. Sorted by self-time per line.''' stats = SiteStats.buildstats(state.samples) stats.sort(reverse=True, key=lambda x: x.selfseconds()) - print >> fp, ('%5.5s %10.10s %7.7s %-8.8s' % - ('% ', 'cumulative', 'self', '')) - print >> fp, ('%5.5s %9.9s %8.8s %-8.8s' % - ("time", "seconds", "seconds", "name")) + print('%5.5s %10.10s %7.7s %-8.8s' % + ('% ', 'cumulative', 'self', ''), file=fp) + print('%5.5s %9.9s %8.8s %-8.8s' % + ("time", "seconds", "seconds", "name"), file=fp) for stat in stats: site = stat.site sitelabel = '%s:%d:%s' % (site.filename(), site.lineno, site.function) - print >> fp, ('%6.2f %9.2f %9.2f %s' % (stat.selfpercent(), - stat.totalseconds(), - stat.selfseconds(), - sitelabel)) + print('%6.2f %9.2f %9.2f %s' % (stat.selfpercent(), + stat.totalseconds(), + stat.selfseconds(), + sitelabel), + file=fp) def display_by_method(fp): '''Print the profiler data with each sample function represented as one row in a table. Important lines within that function are output as nested rows. Sorted by self-time per line.''' - print >> fp, ('%5.5s %10.10s %7.7s %-8.8s' % - ('% ', 'cumulative', 'self', '')) - print >> fp, ('%5.5s %9.9s %8.8s %-8.8s' % - ("time", "seconds", "seconds", "name")) + print('%5.5s %10.10s %7.7s %-8.8s' % + ('% ', 'cumulative', 'self', ''), file=fp) + print('%5.5s %9.9s %8.8s %-8.8s' % + ("time", "seconds", "seconds", "name"), file=fp) stats = SiteStats.buildstats(state.samples) grouped = defaultdict(list) for stat in stats: grouped[stat.site.filename() + ":" + stat.site.function].append(stat) # compute sums for each function @@ -507,29 +508,30 @@ def display_by_method(fp): sitestats)) # sort by total self sec functiondata.sort(reverse=True, key=lambda x: x[2]) for function in functiondata: if function[3] < 0.05: continue - print >> fp, ('%6.2f %9.2f %9.2f %s' % (function[3], # total percent - function[1], # total cum sec - function[2], # total self sec - function[0])) # file:function + print('%6.2f %9.2f %9.2f %s' % (function[3], # total percent + function[1], # total cum sec + function[2], # total self sec + function[0]), # file:function + file=fp) function[4].sort(reverse=True, key=lambda i: i.selfseconds()) for stat in function[4]: # only show line numbers for significant locations (>1% time spent) if stat.selfpercent() > 1: source = stat.site.getsource(25) stattuple = (stat.selfpercent(), stat.selfseconds(), stat.site.lineno, source) - print >> fp, ('%33.0f%% %6.2f line %s: %s' % (stattuple)) + print('%33.0f%% %6.2f line %s: %s' % (stattuple), file=fp) def display_about_method(fp, function=None, **kwargs): if function is None: raise Exception("Invalid function") filename = None if ':' in function: filename, function = function.split(':') @@ -553,51 +555,52 @@ def display_about_method(fp, function=No if site in children: children[site] = children[site] + 1 else: children[site] = 1 parents = [(parent, count) for parent, count in parents.iteritems()] parents.sort(reverse=True, key=lambda x: x[1]) for parent, count in parents: - print >> fp, ('%6.2f%% %s:%s line %s: %s' % + print('%6.2f%% %s:%s line %s: %s' % (count / relevant_samples * 100, parent.filename(), - parent.function, parent.lineno, parent.getsource(50))) + parent.function, parent.lineno, parent.getsource(50)), file=fp) stats = SiteStats.buildstats(state.samples) stats = [s for s in stats if s.site.function == function and (not filename or s.site.filename() == filename)] total_cum_sec = 0 total_self_sec = 0 total_self_percent = 0 total_cum_percent = 0 for stat in stats: total_cum_sec += stat.totalseconds() total_self_sec += stat.selfseconds() total_self_percent += stat.selfpercent() total_cum_percent += stat.totalpercent() - print >> fp, ( + print( '\n %s:%s Total: %0.2fs (%0.2f%%) Self: %0.2fs (%0.2f%%)\n' % ( filename or '___', function, total_cum_sec, total_cum_percent, total_self_sec, total_self_percent - )) + ), file=fp) children = [(child, count) for child, count in children.iteritems()] children.sort(reverse=True, key=lambda x: x[1]) for child, count in children: - print >> fp, (' %6.2f%% line %s: %s' % - (count / relevant_samples * 100, child.lineno, child.getsource(50))) + print(' %6.2f%% line %s: %s' % + (count / relevant_samples * 100, child.lineno, + child.getsource(50)), file=fp) def display_hotpath(fp, limit=0.05, **kwargs): class HotNode(object): def __init__(self, site): self.site = site self.count = 0 self.children = {} @@ -648,34 +651,35 @@ def display_hotpath(fp, limit=0.05, **kw finalstring = liststring + codestring childrensamples = sum([c.count for c in node.children.itervalues()]) # Make frames that performed more than 10% of the operation red if node.count - childrensamples > (0.1 * root.count): finalstring = '\033[91m' + finalstring + '\033[0m' # Make frames that didn't actually perform work dark grey elif node.count - childrensamples == 0: finalstring = '\033[90m' + finalstring + '\033[0m' - print >> fp, finalstring + print(finalstring, file=fp) newdepth = depth if len(visiblechildren) > 1 or multiple_siblings: newdepth += 1 visiblechildren.sort(reverse=True, key=lambda x: x.count) for child in visiblechildren: _write(child, newdepth, len(visiblechildren) > 1) if root.count > 0: _write(root, 0, False) def write_to_flame(fp): scriptpath = os.environ['HOME'] + '/flamegraph.pl' if not os.path.exists(scriptpath): - print >> fp, "error: missing ~/flamegraph.pl" - print >> fp, "get it here: https://github.com/brendangregg/FlameGraph" + print("error: missing ~/flamegraph.pl", file=fp) + print("get it here: https://github.com/brendangregg/FlameGraph", + file=fp) return fd, path = tempfile.mkstemp() file = open(path, "w+") lines = {} for sample in state.samples: @@ -688,49 +692,49 @@ def write_to_flame(fp): lines[line] = 1 for line, count in lines.iteritems(): file.write("%s %s\n" % (line, count)) file.close() os.system("perl ~/flamegraph.pl %s > ~/flamegraph.svg" % path) - print "Written to ~/flamegraph.svg" + print("Written to ~/flamegraph.svg", file=fp) def write_to_json(fp): samples = [] for sample in state.samples: stack = [] for frame in sample.stack: stack.append((frame.path, frame.lineno, frame.function)) samples.append((sample.time, stack)) - print >> fp, json.dumps(samples) + print(json.dumps(samples), file=fp) def printusage(): - print """ + print(""" The statprof command line allows you to inspect the last profile's results in the following forms: usage: hotpath [-l --limit percent] Shows a graph of calls with the percent of time each takes. Red calls take over 10%% of the total time themselves. lines Shows the actual sampled lines. functions Shows the samples grouped by function. function [filename:]functionname Shows the callers and callees of a particular function. flame Writes out a flamegraph to ~/flamegraph.svg - Requires that ~/flamegraph.pl exist.""" + Requires that ~/flamegraph.pl exist.""") def main(argv=None): if argv is None: argv = sys.argv if len(argv) == 1: printusage() return 0 @@ -753,17 +757,17 @@ def main(argv=None): printusage() return 0 # process options try: opts, args = getopt.getopt(sys.argv[optstart:], "hl:", ["help", "limit="]) except getopt.error as msg: - print msg + print(msg) printusage() return 2 limit = 0.05 for o, value in opts: if o in ("-l", "--limit"): limit = float(value) elif o in ("-h", "help"): diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t --- a/tests/test-check-py3-compat.t +++ b/tests/test-check-py3-compat.t @@ -4,17 +4,16 @@ $ cd "$TESTDIR"/.. $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py hgext/fsmonitor/pywatchman/__init__.py not using absolute_import hgext/fsmonitor/pywatchman/__init__.py requires print_function hgext/fsmonitor/pywatchman/capabilities.py not using absolute_import hgext/fsmonitor/pywatchman/pybser.py not using absolute_import i18n/check-translation.py not using absolute_import - mercurial/statprof.py requires print_function setup.py not using absolute_import tests/test-demandimport.py not using absolute_import #if py3exe $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *) (glob) hgext/acl.py: error importing: <TypeError> str expected, not bytes (error at encoding.py:*) (glob) hgext/automv.py: error importing: <TypeError> str expected, not bytes (error at encoding.py:*) (glob) _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel