def jungleprofiler_wrapped_f(*args, **kwargs): ''' Wrapper that collects time and system usage data on wrapped function f''' # Set up LineProfiler lp = LineProfiler() lp.add_function(f) # Set up MemoryProfiler pass # todo add Memory Profiler # Start Counters if self.t_prof: lp.enable_by_count() if self.m_prof: pass try: t0 = time.time() sio = io.StringIO() # Collects redirected stdout with redirect_stdout(sio): preturn = f(*args, **kwargs) self.stdout = sio.getvalue() t1 = time.time() finally: # Stop Counters if self.m_prof: lp.disable_by_count() if self.m_prof: pass # todo add Memory Profiler # Collect Stats # print('Get Stats: %s' % lp.print_stats()) self.walltime = t1 - t0 return preturn, copy.deepcopy(self)
class ProfilingPanel(Panel): """ Panel that displays profiling information. """ title = _('Profiling') template = 'debug_toolbar_line_profiler/panels/profiling.html' def _unwrap_closure_and_profile(self, func): if not hasattr(func, '__code__'): return self.line_profiler.add_function(func) for subfunc in getattr(func, 'profile_additional', []): self._unwrap_closure_and_profile(subfunc) if func.__closure__: for cell in func.__closure__: target = cell.cell_contents if inspect.isclass(target) and View in inspect.getmro(target): for name, value in inspect.getmembers(target): if name[0] != '_' and inspect.ismethod(value): self._unwrap_closure_and_profile(value) else: self._unwrap_closure_and_profile(target) def process_view(self, request, view_func, view_args, view_kwargs): self.profiler = cProfile.Profile() args = (request,) + view_args 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() return out def add_node(self, func_list, func, max_depth, cum_time=0.1): func_list.append(func) func.has_subfuncs = False if func.depth < max_depth: for subfunc in func.subfuncs(): if (subfunc.stats[3] >= cum_time or (hasattr(self.stats, 'line_stats') and (subfunc.func in self.stats.line_stats.timings))): func.has_subfuncs = True self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) def process_response(self, request, response): if not hasattr(self, 'profiler'): return None # Could be delayed until the panel content is requested (perf. optim.) self.profiler.create_stats() self.stats = DjangoDebugToolbarStats(self.profiler) self.stats.line_stats = self.line_profiler.get_stats() self.stats.calc_callees() root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0) func_list = [] self.add_node(func_list, root, 10, root.stats[3] / 8) self.record_stats({'func_list': func_list})
def wrap(*args, **kwargs): profile = LineProfiler() profile.add_function(f) profile.enable_by_count() result = f(*args, **kwargs) profile.disable_by_count() profile.print_stats(sys.stdout) return result
def profiled_func(*args, **kwargs): line_profiler = LineProfiler() line_profiler.add_function(func) map(lambda x: line_profiler.add_function(x), self.follow) line_profiler.enable_by_count() result = func(*args, **kwargs) line_profiler.disable_by_count() line_profiler.print_stats(stripzeros=True) return result
class Profiler(object): def __init__(self, *args): self.profile = LineProfiler() if len(args) > 0: for func in args: if callable(func): self.add_function(func) def add_function(self, func): self.profile.add_function(func) def __enter__(self): self.profile.enable_by_count() def __exit__(self, type, value, traceback): self.profile.disable_by_count() self.profile.print_stats()
def test_enable_disable(self): lp = LineProfiler() self.assertEqual(lp.enable_count, 0) lp.enable_by_count() self.assertEqual(lp.enable_count, 1) lp.enable_by_count() self.assertEqual(lp.enable_count, 2) lp.disable_by_count() self.assertEqual(lp.enable_count, 1) lp.disable_by_count() self.assertEqual(lp.enable_count, 0) self.assertEqual(lp.last_time, {}) lp.disable_by_count() self.assertEqual(lp.enable_count, 0) with lp: self.assertEqual(lp.enable_count, 1) with lp: self.assertEqual(lp.enable_count, 2) self.assertEqual(lp.enable_count, 1) self.assertEqual(lp.enable_count, 0) self.assertEqual(lp.last_time, {}) with self.assertRaises(RuntimeError): self.assertEqual(lp.enable_count, 0) with lp: self.assertEqual(lp.enable_count, 1) raise RuntimeError() self.assertEqual(lp.enable_count, 0) self.assertEqual(lp.last_time, {})
class ProfilingDebugPanel(DebugPanel): """ Panel that displays the Django version. """ name = 'Profiling' template = 'debug_toolbar/panels/profiling.html' has_content = True def nav_title(self): return _('Profiling') def url(self): return '' 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): __traceback_hide__ = True self.profiler = cProfile.Profile() args = (request,) + view_args 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 add_node(self, func_list, func, max_depth, cum_time=0.1): func_list.append(func) func.has_subfuncs = False if func.depth < max_depth: for subfunc in func.subfuncs(): if (subfunc.stats[3] >= cum_time or (hasattr(self.stats, 'line_stats') and (subfunc.func in self.stats.line_stats.timings))): func.has_subfuncs = True self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) 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() self.stats.calc_callees() root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0) func_list = [] self.add_node(func_list, root, 10, root.stats[3]/8) self.stats_record({'func_list': func_list})
class ProfilingPanel(Panel): """ Panel that displays profiling information. """ title = _('Profiling') template = 'debug_toolbar_line_profiler/panels/profiling.html' def _unwrap_closure_and_profile(self, func): if not hasattr(func, '__code__'): return self.line_profiler.add_function(func) for subfunc in getattr(func, 'profile_additional', []): self._unwrap_closure_and_profile(subfunc) if PY2: func_closure = func.func_closure else: func_closure = func.__closure__ if func_closure: for cell in func_closure: target = cell.cell_contents if hasattr(target, '__code__'): self._unwrap_closure_and_profile(cell.cell_contents) if inspect.isclass(target) and View in inspect.getmro(target): for name, value in inspect.getmembers(target): if name[0] != '_' and inspect.ismethod(value): self._unwrap_closure_and_profile(value) def process_view(self, request, view_func, view_args, view_kwargs): self.view_func = view_func self.profiler = cProfile.Profile() args = (request,) + view_args self.line_profiler = LineProfiler() self._unwrap_closure_and_profile(view_func) signals.profiler_setup.send(sender=self, profiler=self.line_profiler, view_func=view_func, view_args=view_args, view_kwargs=view_kwargs) self.line_profiler.enable_by_count() out = self.profiler.runcall(view_func, *args, **view_kwargs) self.line_profiler.disable_by_count() return out def add_node(self, func_list, func, max_depth, cum_time=0.1): """ add_node does a depth first traversal of the call graph, appending a FunctionCall object to func_list, so that the Django template only has to do a single for loop over func_list that can render a tree structure Parameters: func_list is an array that will have a FunctionCall for each call added to it func is a FunctionCall object that will have all its callees added max_depth is the maximum depth we should recurse cum_time is the minimum cum_time a function should have to be included in the output """ func_list.append(func) func.has_subfuncs = False # this function somewhat dangerously relies on FunctionCall to set its # subfuncs' depth argument correctly if func.depth >= max_depth: return # func.subfuncs returns FunctionCall objects subs = sorted(func.subfuncs(), key=FunctionCall.cumtime, reverse=True) for subfunc in subs: # a sub function is important if it takes a long time or it has # line_stats if (subfunc.cumtime() >= cum_time or (hasattr(self.stats, 'line_stats') and subfunc.func in self.stats.line_stats.timings)): func.has_subfuncs = True self.add_node( func_list=func_list, func=subfunc, max_depth=max_depth, cum_time=subfunc.cumtime()/16) def process_response(self, request, response): if not hasattr(self, 'profiler'): return None # Could be delayed until the panel content is requested (perf. optim.) self.profiler.create_stats() self.stats = DjangoDebugToolbarStats(self.profiler) self.stats.line_stats = self.line_profiler.get_stats() self.stats.calc_callees() func_list = [] root_func = self.stats.get_root_func(self.view_func) if root_func is not None: root_node = FunctionCall(statobj=self.stats, func=root_func, depth=0) self.add_node( func_list=func_list, func=root_node, max_depth=10, cum_time=root_node.cumtime() / 8 ) # else: # what should we do if we didn't detect a root function? It's not # clear what causes this, but there are real world examples of it (see # https://github.com/dmclain/django-debug-toolbar-line-profiler/issues/11) self.record_stats({'func_list': func_list})
class ProfilingPanel(Panel): """ Panel that displays profiling information. """ title = _('Profiling') template = 'debug_toolbar_line_profiler/panels/profiling.html' def _unwrap_closure_and_profile(self, func): if not hasattr(func, '__code__'): return self.line_profiler.add_function(func) for subfunc in getattr(func, 'profile_additional', []): self._unwrap_closure_and_profile(subfunc) if PY2: func_closure = func.func_closure else: func_closure = func.__closure__ if func_closure: for cell in func_closure: target = cell.cell_contents if hasattr(target, '__code__'): self._unwrap_closure_and_profile(cell.cell_contents) if inspect.isclass(target) and View in inspect.getmro(target): for name, value in inspect.getmembers(target): if name[0] != '_' and inspect.ismethod(value): self._unwrap_closure_and_profile(value) def process_view(self, request, view_func, view_args, view_kwargs): self.view_func = view_func self.profiler = cProfile.Profile() args = (request,) + view_args self.line_profiler = LineProfiler() self._unwrap_closure_and_profile(view_func) signals.profiler_setup.send(sender=self, profiler=self.line_profiler, view_func=view_func, view_args=view_args, view_kwargs=view_kwargs) self.line_profiler.enable_by_count() out = self.profiler.runcall(view_func, *args, **view_kwargs) self.line_profiler.disable_by_count() return out def add_node(self, func_list, func, max_depth, cum_time=0.1): """ add_node does a depth first traversal of the call graph, appending a FunctionCall object to func_list, so that the Django template only has to do a single for loop over func_list that can render a tree structure Parameters: func_list is an array that will have a FunctionCall for each call added to it func is a FunctionCall object that will have all its callees added max_depth is the maximum depth we should recurse cum_time is the minimum cum_time a function should have to be included in the output """ func_list.append(func) func.has_subfuncs = False # this function somewhat dangerously relies on FunctionCall to set its # subfuncs' depth argument correctly if func.depth >= max_depth: return # func.subfuncs returns FunctionCall objects subs = sorted(func.subfuncs(), key=FunctionCall.cumtime, reverse=True) for subfunc in subs: # a sub function is important if it takes a long time or it has # line_stats if (subfunc.cumtime() >= cum_time or (hasattr(self.stats, 'line_stats') and subfunc.func in self.stats.line_stats.timings)): func.has_subfuncs = True self.add_node( func_list=func_list, func=subfunc, max_depth=max_depth, cum_time=subfunc.cumtime()/16) def process_response(self, request, response): if not hasattr(self, 'profiler'): return None # Could be delayed until the panel content is requested (perf. optim.) self.profiler.create_stats() self.stats = DjangoDebugToolbarStats(self.profiler) self.stats.line_stats = self.line_profiler.get_stats() self.stats.calc_callees() func_list = [] root_func = self.stats.get_root_func(self.view_func) if root_func is not None: root_node = FunctionCall(statobj=self.stats, func=root_func, depth=0) self.add_node( func_list=func_list, func=root_node, max_depth=10, cum_time=root_node.cumtime() / 8 ) # else: # what should we do if we didn't detect a root function? It's not # clear what causes this, but there are real world examples of it (see # https://github.com/dmclain/django-debug-toolbar-line-profiler/issues/11) self.record_stats({'func_list': func_list})
class ProfilingDebugPanel(DebugPanel): """ Panel that displays the Django version. """ name = 'Profiling' template = 'debug_toolbar/panels/profiling.html' has_content = True def nav_title(self): return _('Profiling') def url(self): return '' 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): __traceback_hide__ = True self.profiler = cProfile.Profile() args = (request, ) + view_args 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 add_node(self, func_list, func, max_depth, cum_time=0.1): func_list.append(func) func.has_subfuncs = False if func.depth < max_depth: for subfunc in func.subfuncs(): if (subfunc.stats[3] >= cum_time or (hasattr(self.stats, 'line_stats') and (subfunc.func in self.stats.line_stats.timings))): func.has_subfuncs = True self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) def process_response(self, request, response): __traceback_hide__ = True if not hasattr(self, 'profiler'): return None self.profiler.create_stats() self.stats = DjangoDebugToolbarStats(self.profiler) if DJ_PROFILE_USE_LINE_PROFILER: self.stats.line_stats = self.line_profiler.get_stats() self.stats.calc_callees() root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0) func_list = [] self.add_node(func_list, root, 10, root.stats[3] / 8) self.record_stats({'func_list': func_list})