[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