[PATCH] dispatch: add support for python-flamegraph[0] profiling

Augie Fackler raf at durin42.com
Mon May 18 20:56:06 UTC 2015


# HG changeset patch
# User Augie Fackler <augie at google.com>
# Date 1429218753 14400
#      Thu Apr 16 17:12:33 2015 -0400
# Node ID 7da27ede4a97de8e8f0f4138381b9d4594e0d3d2
# Parent  f8b602fd4643f86336c373f12d0e9d012a617602
dispatch: add support for python-flamegraph[0] profiling

This gives us nicer svg flame graphs for output, which can make
understanding some types of performance problems significantly easier.

0: https://github.com/evanhempel/python-flamegraph/

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -921,6 +921,30 @@ def lsprofile(ui, func, fp):
             stats.sort(field)
             stats.pprint(limit=limit, file=fp, climit=climit)
 
+def flameprofile(ui, func, fp):
+    try:
+        from flamegraph import flamegraph
+    except ImportError:
+        raise util.Abort(_(
+            'flamegraph not available - install from '
+            'https://github.com/evanhempel/python-flamegraph'))
+    freq = ui.configint('profiling', 'freq', default=1000)
+    filter_ = None
+    collapse_recursion = True
+    thread = flamegraph.ProfileThread(fp, 1.0/freq,
+                                      filter_, collapse_recursion)
+    start_time = time.clock()
+    try:
+        thread.start()
+        func()
+    finally:
+        thread.stop()
+        thread.join()
+        print 'Collected %d stack frames (%d unique) in %2.2f seconds.' % (
+            time.clock() - start_time, thread.num_frames(),
+            thread.num_frames(unique=True))
+
+
 def statprofile(ui, func, fp):
     try:
         import statprof
@@ -952,7 +976,7 @@ def _runcommand(ui, options, cmd, cmdfun
         profiler = os.getenv('HGPROF')
         if profiler is None:
             profiler = ui.config('profiling', 'type', default='ls')
-        if profiler not in ('ls', 'stat'):
+        if profiler not in ('ls', 'stat', 'flame'):
             ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
             profiler = 'ls'
 
@@ -967,6 +991,8 @@ def _runcommand(ui, options, cmd, cmdfun
         try:
             if profiler == 'ls':
                 return lsprofile(ui, checkargs, fp)
+            elif profiler == 'flame':
+                return flameprofile(ui, checkargs, fp)
             else:
                 return statprofile(ui, checkargs, fp)
         finally:


More information about the Mercurial-devel mailing list