changeset 25187:670c1df688fd

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/
author Augie Fackler <augie@google.com>
date Thu, 16 Apr 2015 17:12:33 -0400
parents 80c5b2666a96
children 2773540c3650
files mercurial/dispatch.py
diffstat 1 files changed, 27 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dispatch.py	Tue Apr 28 16:44:37 2015 -0400
+++ b/mercurial/dispatch.py	Thu Apr 16 17:12:33 2015 -0400
@@ -921,6 +921,30 @@
             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 @@
         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 @@
         try:
             if profiler == 'ls':
                 return lsprofile(ui, checkargs, fp)
+            elif profiler == 'flame':
+                return flameprofile(ui, checkargs, fp)
             else:
                 return statprofile(ui, checkargs, fp)
         finally: