[PATCH 5 of 9 RFC] statprof: use print function
Gregory Szorc
gregory.szorc at gmail.com
Tue Aug 16 01:25:12 EDT 2016
# HG changeset patch
# User Gregory Szorc <gregory.szorc at 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)
More information about the Mercurial-devel
mailing list