diff options
| author | Dave McLain | 2011-04-26 14:39:01 -0500 |
|---|---|---|
| committer | Dave McLain | 2011-04-26 14:46:07 -0500 |
| commit | cf82001f197288c9816c2d7adcc09c08205cfa42 (patch) | |
| tree | 1f62e181c376c63e0e7b895db6ecf764fe8da673 | |
| parent | a3e8ce8eb1c4e2d1482a22d3a7e0dba7f4ff3201 (diff) | |
| download | django-debug-toolbar-cf82001f197288c9816c2d7adcc09c08205cfa42.tar.bz2 | |
Integrating line_profiler
| -rw-r--r-- | debug_toolbar/panels/profiling.py | 52 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/profiling.html | 19 |
2 files changed, 57 insertions, 14 deletions
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py index 68aafb7..53e333e 100644 --- a/debug_toolbar/panels/profiling.py +++ b/debug_toolbar/panels/profiling.py @@ -5,6 +5,14 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe from debug_toolbar.panels import DebugPanel +try: + from line_profiler import LineProfiler, show_func + DJ_PROFILE_USE_LINE_PROFILER = True +except ImportError: + DJ_PROFILE_USE_LINE_PROFILER = False + + +from cStringIO import StringIO import cProfile from pstats import Stats from colorsys import hsv_to_rgb @@ -20,13 +28,6 @@ class DjangoDebugToolbarStats(Stats): break return self.__root - def print_call_tree_node(self, function, depth, max_depth, cum_filter=0.1): - self.print_line(function, depth=depth) - if depth < max_depth: - for called in self.all_callees[function].keys(): - if self.stats[called][3] >= cum_filter: - self.print_call_tree_node(called, depth+1, max_depth, cum_filter=cum_filter) - class FunctionCall(object): def __init__(self, statobj, func, depth=0, stats=None, id=0, parent_ids=[], hsv=(0,0.5,1)): self.statobj = statobj @@ -39,6 +40,7 @@ class FunctionCall(object): self.id = id self.parent_ids = parent_ids self.hsv = hsv + self._line_stats_text = None def parent_classes(self): return self.parent_classes @@ -118,6 +120,18 @@ class FunctionCall(object): def indent(self): return 16 * self.depth + + def line_stats_text(self): + if self._line_stats_text is None: + lstats = self.statobj.line_stats + if self.func in lstats.timings: + out = StringIO() + fn, lineno, name = self.func + show_func(fn, lineno, name, lstats.timings[self.func], lstats.unit, stream=out) + self._line_stats_text = out.getvalue() + else: + self._line_stats_text = False + return self._line_stats_text class ProfilingDebugPanel(DebugPanel): """ @@ -135,14 +149,34 @@ class ProfilingDebugPanel(DebugPanel): def title(self): return _('Profiling') + def _unwrap_closure_and_profile(self, func): + if not hasattr(func, 'func_code'): + return + self.line_profiler.add_function(func) + if func.func_closure: + for cell in func.func_closure: + if hasattr(cell.cell_contents, 'func_code'): + self._unwrap_closure_and_profile(cell.cell_contents) + def process_view(self, request, view_func, view_args, view_kwargs): self.profiler = cProfile.Profile() args = (request,) + view_args - return self.profiler.runcall(view_func, *args, **view_kwargs) + if DJ_PROFILE_USE_LINE_PROFILER: + self.line_profiler = LineProfiler() + self._unwrap_closure_and_profile(view_func) + self.line_profiler.enable_by_count() + out = self.profiler.runcall(view_func, *args, **view_kwargs) + self.line_profiler.disable_by_count() + else: + self.line_profiler = None + out = self.profiler.runcall(view_func, *args, **view_kwargs) + return out def process_response(self, request, response): self.profiler.create_stats() self.stats = DjangoDebugToolbarStats(self.profiler) + if DJ_PROFILE_USE_LINE_PROFILER: + self.stats.line_stats = self.line_profiler.get_stats() return response def add_node(self, func_list, func, max_depth, cum_time=0.1): @@ -150,7 +184,7 @@ class ProfilingDebugPanel(DebugPanel): func.has_subfuncs = False if func.depth < max_depth: for subfunc in func.subfuncs(): - if subfunc.stats[3] >= cum_time: + if subfunc.stats[3] >= cum_time or (subfunc.func in self.stats.line_stats.timings): func.has_subfuncs = True self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) diff --git a/debug_toolbar/templates/debug_toolbar/panels/profiling.html b/debug_toolbar/templates/debug_toolbar/panels/profiling.html index ebc91cc..ef42230 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/profiling.html +++ b/debug_toolbar/templates/debug_toolbar/panels/profiling.html @@ -4,10 +4,10 @@ <thead> <tr> <th>{% trans "Call" %}</th> - <th>{% trans "TotTime" %}</th> - <th>{% trans "Per" %}</th> <th>{% trans "CumTime" %}</th> <th>{% trans "Per" %}</th> + <th>{% trans "TotTime" %}</th> + <th>{% trans "Per" %}</th> <th>{% trans "Count" %}</th> </tr> </thead> @@ -25,12 +25,21 @@ <span class="stack">{{ call.func_std_string }}</span> </div> </td> - <td>{{ call.tottime|floatformat:3 }}</td> - <td>{{ call.tottime_per_call|floatformat:3 }}</td> <td>{{ call.cumtime|floatformat:3 }}</td> <td>{{ call.cumtime_per_call|floatformat:3 }}</td> + <td>{{ call.tottime|floatformat:3 }}</td> + <td>{{ call.tottime_per_call|floatformat:3 }}</td> <td>{{ call.count }}</td> </tr> + {% if call.line_stats_text %} + <tr> + <td colspan='6'> + <pre style='font-family:Courier, monospace'> + {{ call.line_stats_text }} + </pre> + </td> + </tr> + {% endif %} {% endfor %} </tbody> -</table> +</table>
\ No newline at end of file |
