##// END OF EJS Templates
profiling: move profiling code from dispatch.py (API)...
Gregory Szorc -
r29781:2654a0aa default
parent child Browse files
Show More
@@ -0,0 +1,132 b''
1 # profiling.py - profiling functions
2 #
3 # Copyright 2016 Gregory Szorc <gregory.szorc@gmail.com>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import, print_function
9
10 import os
11 import sys
12 import time
13
14 from .i18n import _
15 from . import (
16 error,
17 util,
18 )
19
20 def lsprofile(ui, func, fp):
21 format = ui.config('profiling', 'format', default='text')
22 field = ui.config('profiling', 'sort', default='inlinetime')
23 limit = ui.configint('profiling', 'limit', default=30)
24 climit = ui.configint('profiling', 'nested', default=0)
25
26 if format not in ['text', 'kcachegrind']:
27 ui.warn(_("unrecognized profiling format '%s'"
28 " - Ignored\n") % format)
29 format = 'text'
30
31 try:
32 from . import lsprof
33 except ImportError:
34 raise error.Abort(_(
35 'lsprof not available - install from '
36 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
37 p = lsprof.Profiler()
38 p.enable(subcalls=True)
39 try:
40 return func()
41 finally:
42 p.disable()
43
44 if format == 'kcachegrind':
45 from . import lsprofcalltree
46 calltree = lsprofcalltree.KCacheGrind(p)
47 calltree.output(fp)
48 else:
49 # format == 'text'
50 stats = lsprof.Stats(p.getstats())
51 stats.sort(field)
52 stats.pprint(limit=limit, file=fp, climit=climit)
53
54 def flameprofile(ui, func, fp):
55 try:
56 from flamegraph import flamegraph
57 except ImportError:
58 raise error.Abort(_(
59 'flamegraph not available - install from '
60 'https://github.com/evanhempel/python-flamegraph'))
61 # developer config: profiling.freq
62 freq = ui.configint('profiling', 'freq', default=1000)
63 filter_ = None
64 collapse_recursion = True
65 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
66 filter_, collapse_recursion)
67 start_time = time.clock()
68 try:
69 thread.start()
70 func()
71 finally:
72 thread.stop()
73 thread.join()
74 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
75 time.clock() - start_time, thread.num_frames(),
76 thread.num_frames(unique=True)))
77
78 def statprofile(ui, func, fp):
79 try:
80 import statprof
81 except ImportError:
82 raise error.Abort(_(
83 'statprof not available - install using "easy_install statprof"'))
84
85 freq = ui.configint('profiling', 'freq', default=1000)
86 if freq > 0:
87 statprof.reset(freq)
88 else:
89 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
90
91 statprof.start()
92 try:
93 return func()
94 finally:
95 statprof.stop()
96 statprof.display(fp)
97
98 def profile(ui, fn):
99 """Profile a function call."""
100 profiler = os.getenv('HGPROF')
101 if profiler is None:
102 profiler = ui.config('profiling', 'type', default='ls')
103 if profiler not in ('ls', 'stat', 'flame'):
104 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
105 profiler = 'ls'
106
107 output = ui.config('profiling', 'output')
108
109 if output == 'blackbox':
110 fp = util.stringio()
111 elif output:
112 path = ui.expandpath(output)
113 fp = open(path, 'wb')
114 else:
115 fp = sys.stderr
116
117 try:
118 if profiler == 'ls':
119 return lsprofile(ui, fn, fp)
120 elif profiler == 'flame':
121 return flameprofile(ui, fn, fp)
122 else:
123 return statprofile(ui, fn, fp)
124 finally:
125 if output:
126 if output == 'blackbox':
127 val = 'Profile:\n%s' % fp.getvalue()
128 # ui.log treats the input as a format string,
129 # so we need to escape any % signs.
130 val = val.replace('%', '%%')
131 ui.log('profile', val)
132 fp.close()
@@ -34,6 +34,7 b' from . import ('
34 fileset,
34 fileset,
35 hg,
35 hg,
36 hook,
36 hook,
37 profiling,
37 revset,
38 revset,
38 templatefilters,
39 templatefilters,
39 templatekw,
40 templatekw,
@@ -892,85 +893,6 b' def _dispatch(req):'
892 if repo and repo != req.repo:
893 if repo and repo != req.repo:
893 repo.close()
894 repo.close()
894
895
895 def lsprofile(ui, func, fp):
896 format = ui.config('profiling', 'format', default='text')
897 field = ui.config('profiling', 'sort', default='inlinetime')
898 limit = ui.configint('profiling', 'limit', default=30)
899 climit = ui.configint('profiling', 'nested', default=0)
900
901 if format not in ['text', 'kcachegrind']:
902 ui.warn(_("unrecognized profiling format '%s'"
903 " - Ignored\n") % format)
904 format = 'text'
905
906 try:
907 from . import lsprof
908 except ImportError:
909 raise error.Abort(_(
910 'lsprof not available - install from '
911 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
912 p = lsprof.Profiler()
913 p.enable(subcalls=True)
914 try:
915 return func()
916 finally:
917 p.disable()
918
919 if format == 'kcachegrind':
920 from . import lsprofcalltree
921 calltree = lsprofcalltree.KCacheGrind(p)
922 calltree.output(fp)
923 else:
924 # format == 'text'
925 stats = lsprof.Stats(p.getstats())
926 stats.sort(field)
927 stats.pprint(limit=limit, file=fp, climit=climit)
928
929 def flameprofile(ui, func, fp):
930 try:
931 from flamegraph import flamegraph
932 except ImportError:
933 raise error.Abort(_(
934 'flamegraph not available - install from '
935 'https://github.com/evanhempel/python-flamegraph'))
936 # developer config: profiling.freq
937 freq = ui.configint('profiling', 'freq', default=1000)
938 filter_ = None
939 collapse_recursion = True
940 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
941 filter_, collapse_recursion)
942 start_time = time.clock()
943 try:
944 thread.start()
945 func()
946 finally:
947 thread.stop()
948 thread.join()
949 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
950 time.clock() - start_time, thread.num_frames(),
951 thread.num_frames(unique=True)))
952
953
954 def statprofile(ui, func, fp):
955 try:
956 import statprof
957 except ImportError:
958 raise error.Abort(_(
959 'statprof not available - install using "easy_install statprof"'))
960
961 freq = ui.configint('profiling', 'freq', default=1000)
962 if freq > 0:
963 statprof.reset(freq)
964 else:
965 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
966
967 statprof.start()
968 try:
969 return func()
970 finally:
971 statprof.stop()
972 statprof.display(fp)
973
974 def _runcommand(ui, options, cmd, cmdfunc):
896 def _runcommand(ui, options, cmd, cmdfunc):
975 """Enables the profiler if applicable.
897 """Enables the profiler if applicable.
976
898
@@ -983,39 +905,7 b' def _runcommand(ui, options, cmd, cmdfun'
983 raise error.CommandError(cmd, _("invalid arguments"))
905 raise error.CommandError(cmd, _("invalid arguments"))
984
906
985 if options['profile'] or ui.configbool('profiling', 'enabled'):
907 if options['profile'] or ui.configbool('profiling', 'enabled'):
986 profiler = os.getenv('HGPROF')
908 return profiling.profile(ui, checkargs)
987 if profiler is None:
988 profiler = ui.config('profiling', 'type', default='ls')
989 if profiler not in ('ls', 'stat', 'flame'):
990 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
991 profiler = 'ls'
992
993 output = ui.config('profiling', 'output')
994
995 if output == 'blackbox':
996 fp = util.stringio()
997 elif output:
998 path = ui.expandpath(output)
999 fp = open(path, 'wb')
1000 else:
1001 fp = sys.stderr
1002
1003 try:
1004 if profiler == 'ls':
1005 return lsprofile(ui, checkargs, fp)
1006 elif profiler == 'flame':
1007 return flameprofile(ui, checkargs, fp)
1008 else:
1009 return statprofile(ui, checkargs, fp)
1010 finally:
1011 if output:
1012 if output == 'blackbox':
1013 val = "Profile:\n%s" % fp.getvalue()
1014 # ui.log treats the input as a format string,
1015 # so we need to escape any % signs.
1016 val = val.replace('%', '%%')
1017 ui.log('profile', val)
1018 fp.close()
1019 else:
909 else:
1020 return checkargs()
910 return checkargs()
1021
911
General Comments 0
You need to be logged in to leave comments. Login now