From dfee3848866f2193576d2bdd44f0c8bcd10c63a4 Mon Sep 17 00:00:00 2001
From: Dave McLain
Date: Thu, 21 Apr 2011 20:12:42 -0500
Subject: Creating a profiling panel from the version panel for basic stuff
---
debug_toolbar/panels/profiling.py | 59 +++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100644 debug_toolbar/panels/profiling.py
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
new file mode 100644
index 0000000..302f444
--- /dev/null
+++ b/debug_toolbar/panels/profiling.py
@@ -0,0 +1,59 @@
+import sys
+
+import django
+from django.conf import settings
+from django.template.loader import render_to_string
+from django.utils.translation import ugettext_lazy as _
+
+import debug_toolbar
+from debug_toolbar.panels import DebugPanel
+
+
+class VersionDebugPanel(DebugPanel):
+ """
+ Panel that displays the Django version.
+ """
+ name = 'Profiling'
+ has_content = True
+
+ def nav_title(self):
+ return _('Versions')
+
+ def nav_subtitle(self):
+ return 'Django %s' % django.get_version()
+
+ def url(self):
+ return ''
+
+ def title(self):
+ return _('Versions')
+
+ def content(self):
+ versions = {}
+ for app in settings.INSTALLED_APPS + ['django']:
+ name = app.split('.')[-1].replace('_', ' ').capitalize()
+ __import__(app)
+ app = sys.modules[app]
+ if hasattr(app, 'get_version'):
+ get_version = app.get_version
+ if callable(get_version):
+ version = get_version()
+ else:
+ version = get_version
+ elif hasattr(app, 'VERSION'):
+ version = app.VERSION
+ elif hasattr(app, '__version__'):
+ version = app.__version__
+ else:
+ continue
+ if isinstance(version, (list, tuple)):
+ version = '.'.join(str(o) for o in version)
+ versions[name] = version
+
+ context = self.context.copy()
+ context.update({
+ 'versions': versions,
+ 'paths': sys.path,
+ })
+
+ return render_to_string('debug_toolbar/panels/versions.html', context)
--
cgit v1.2.3
From 3929bf2066e108695546e2dd8db14579a8710126 Mon Sep 17 00:00:00 2001
From: Dave McLain
Date: Fri, 22 Apr 2011 01:24:57 -0500
Subject: first pass at a profiler panel
---
debug_toolbar/panels/profiling.py | 169 ++++++++++++++++++++++++++++++--------
1 file changed, 136 insertions(+), 33 deletions(-)
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index 302f444..af7137f 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -1,15 +1,120 @@
-import sys
-
import django
from django.conf import settings
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
-
+from django.utils.safestring import mark_safe
import debug_toolbar
from debug_toolbar.panels import DebugPanel
+import sys
+import cProfile
+from pstats import Stats, f8, func_std_string
+from cStringIO import StringIO
+from django.conf import settings
+from colorsys import hsv_to_rgb
+
+class DjangoDebugToolbarStats(Stats):
+ __root = None
+
+ def get_root_func(self):
+ if self.__root is None:
+ for func, (cc, nc, tt, ct, callers) in self.stats.iteritems():
+ if len(callers) == 0:
+ self.__root = func
+ 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 VersionDebugPanel(DebugPanel):
+class FunctionCall(object):
+ def __init__(self, statobj, func, depth=0, stats=None, css_id='djDebugProfileCall_0', hsv=(0,0.5,1)):
+ self.statobj = statobj
+ self.func = func
+ if stats:
+ self.stats = stats
+ else:
+ self.stats = statobj.stats[func][:4]
+ self.depth = depth
+ self.id = css_id
+ self.hsv=hsv
+
+ def parent_classes(self):
+ return self.parent_classes
+
+ def background(self):
+ print self.hsv
+ r,g,b = hsv_to_rgb(*self.hsv)
+ return 'rgb(%f%%,%f%%,%f%%)' %(r*100, g*100, b*100)
+
+ def func_std_string(self): # match what old profile produced
+ func_name = self.func
+ if func_name[:2] == ('~', 0):
+ # special case for built-in functions
+ name = func_name[2]
+ if name.startswith('<') and name.endswith('>'):
+ return '{%s}' % name[1:-1]
+ else:
+ return name
+ else:
+ file_name, line_num, method = self.func
+ if file_name.startswith(settings.PROJECT_ROOT):
+ file_name='PROJECT' + file_name[len(settings.PROJECT_ROOT):]
+ idx = file_name.find('/site-packages/')
+ if idx > -1:
+ file_name=file_name[idx+14:]
+ return "%s:%d(%s)" % (file_name, line_num, method)
+
+ def subfuncs(self):
+ i=0
+ h,s,v = self.hsv
+ count = len(self.statobj.all_callees[self.func])
+ for func, stats in self.statobj.all_callees[self.func].iteritems():
+ i += 1
+ h1 = h + (i/count)/(self.depth+1)
+ if stats[3] == 0:
+ s1 = 0
+ else:
+ s1 = s*(stats[3]/self.stats[3])
+ yield FunctionCall(self.statobj,
+ func,
+ self.depth+1,
+ stats=stats,
+ css_id=self.id + '_' + str(i),
+ hsv=(h1,s1,1))
+
+ def as_row(self):
+ cc, nc, tt, ct = self.stats
+ if nc != cc:
+ c = str(nc) + '/' + str(cc)
+ else:
+ c = str(nc)
+
+ if nc != 0:
+ ttdivnc = tt/nc
+ else:
+ ttdivnc = 0
+
+ if cc == 0:
+ ctdivcc = 0
+ else:
+ ctdivcc = ct/cc
+ indent = 5*self.depth
+ funcstr = self.func_std_string()
+ out = """
+
%(c)s |
+ %(tt)8.3f (%(ttdivnc)8.3f) |
+ %(ct)8.3f (%(ctdivcc)8.3f) |
+ %(funcstr)s |
+ """ % locals()
+ return mark_safe(out)
+
+
+class ProfilingDebugPanel(DebugPanel):
"""
Panel that displays the Django version.
"""
@@ -17,43 +122,41 @@ class VersionDebugPanel(DebugPanel):
has_content = True
def nav_title(self):
- return _('Versions')
-
- def nav_subtitle(self):
- return 'Django %s' % django.get_version()
+ return _('Profiling')
def url(self):
return ''
def title(self):
- return _('Versions')
+ return _('Profiling')
- def content(self):
- versions = {}
- for app in settings.INSTALLED_APPS + ['django']:
- name = app.split('.')[-1].replace('_', ' ').capitalize()
- __import__(app)
- app = sys.modules[app]
- if hasattr(app, 'get_version'):
- get_version = app.get_version
- if callable(get_version):
- version = get_version()
- else:
- version = get_version
- elif hasattr(app, 'VERSION'):
- version = app.VERSION
- elif hasattr(app, '__version__'):
- version = app.__version__
- else:
- continue
- if isinstance(version, (list, tuple)):
- version = '.'.join(str(o) for o in version)
- versions[name] = version
+ 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)
+
+ def process_response(self, request, response):
+ self.profiler.create_stats()
+ self.stats = DjangoDebugToolbarStats(self.profiler)
+ return response
+ def add_node(self, func_list, func, max_depth, cum_time=0.1):
+ func_list.append(func)
+ if func.depth < max_depth:
+ for subfunc in func.subfuncs():
+ if subfunc.stats[3] >= cum_time:
+ self.add_node(func_list, subfunc, max_depth, cum_time=cum_time)
+
+ def content(self):
+
+ 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)
context = self.context.copy()
context.update({
- 'versions': versions,
- 'paths': sys.path,
+ 'func_list': func_list,
})
- return render_to_string('debug_toolbar/panels/versions.html', context)
+ return render_to_string('debug_toolbar/panels/profiling.html', context)
--
cgit v1.2.3
From 38019ea2f5222ac97a7c5b67074a8a3b2ecf1ba0 Mon Sep 17 00:00:00 2001
From: David Cramer
Date: Fri, 22 Apr 2011 13:07:41 -0700
Subject: Kill off requirement of PROJECT_ROOT and clean up lint violations in
profiling panel
---
debug_toolbar/panels/profiling.py | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index af7137f..465a0a3 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -1,16 +1,10 @@
-import django
-from django.conf import settings
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
-import debug_toolbar
from debug_toolbar.panels import DebugPanel
-import sys
import cProfile
-from pstats import Stats, f8, func_std_string
-from cStringIO import StringIO
-from django.conf import settings
+from pstats import Stats
from colorsys import hsv_to_rgb
class DjangoDebugToolbarStats(Stats):
@@ -62,8 +56,6 @@ class FunctionCall(object):
return name
else:
file_name, line_num, method = self.func
- if file_name.startswith(settings.PROJECT_ROOT):
- file_name='PROJECT' + file_name[len(settings.PROJECT_ROOT):]
idx = file_name.find('/site-packages/')
if idx > -1:
file_name=file_name[idx+14:]
--
cgit v1.2.3
From 5fc8d35d17b691727c08e9c2b55aa655f516850f Mon Sep 17 00:00:00 2001
From: David Cramer
Date: Fri, 22 Apr 2011 13:08:44 -0700
Subject: Remove print statement
---
debug_toolbar/panels/profiling.py | 1 -
1 file changed, 1 deletion(-)
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index 465a0a3..97f4865 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -41,7 +41,6 @@ class FunctionCall(object):
return self.parent_classes
def background(self):
- print self.hsv
r,g,b = hsv_to_rgb(*self.hsv)
return 'rgb(%f%%,%f%%,%f%%)' %(r*100, g*100, b*100)
--
cgit v1.2.3
From 249247f9c7a5027d444471526859ee86c06a1f1a Mon Sep 17 00:00:00 2001
From: David Cramer
Date: Fri, 22 Apr 2011 14:47:36 -0700
Subject: Initial refactor of toggline so that profiling matches sql
---
debug_toolbar/panels/profiling.py | 70 +++++++++++++++++++++++----------------
1 file changed, 42 insertions(+), 28 deletions(-)
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index 97f4865..d0ea2c1 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -1,3 +1,5 @@
+from __future__ import division
+
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
@@ -26,7 +28,7 @@ class DjangoDebugToolbarStats(Stats):
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, css_id='djDebugProfileCall_0', hsv=(0,0.5,1)):
+ def __init__(self, statobj, func, depth=0, stats=None, id=0, parent_ids=[], hsv=(0,0.5,1)):
self.statobj = statobj
self.func = func
if stats:
@@ -34,8 +36,9 @@ class FunctionCall(object):
else:
self.stats = statobj.stats[func][:4]
self.depth = depth
- self.id = css_id
- self.hsv=hsv
+ self.id = id
+ self.parent_ids = parent_ids
+ self.hsv = hsv
def parent_classes(self):
return self.parent_classes
@@ -58,7 +61,15 @@ class FunctionCall(object):
idx = file_name.find('/site-packages/')
if idx > -1:
file_name=file_name[idx+14:]
- return "%s:%d(%s)" % (file_name, line_num, method)
+
+ file_path, file_name = file_name.rsplit('/', 1)
+
+ return mark_safe('{0}/{1} in {3}({2})'.format(
+ file_path,
+ file_name,
+ line_num,
+ method,
+ ))
def subfuncs(self):
i=0
@@ -75,35 +86,38 @@ class FunctionCall(object):
func,
self.depth+1,
stats=stats,
- css_id=self.id + '_' + str(i),
+ id=str(self.id) + '_' + str(i),
+ parent_ids=self.parent_ids + [self.id],
hsv=(h1,s1,1))
- def as_row(self):
+ def count(self):
+ return self.stats[1]
+
+ def tottime(self):
+ return self.stats[2]
+
+ def cumtime(self):
cc, nc, tt, ct = self.stats
- if nc != cc:
- c = str(nc) + '/' + str(cc)
- else:
- c = str(nc)
-
- if nc != 0:
- ttdivnc = tt/nc
- else:
- ttdivnc = 0
-
+ return self.stats[3]
+
+ def tottime_per_call(self):
+ cc, nc, tt, ct = self.stats
+
+ if nc == 0:
+ return 0
+
+ return tt/nc
+
+ def cumtime_per_call(self):
+ cc, nc, tt, ct = self.stats
+
if cc == 0:
- ctdivcc = 0
- else:
- ctdivcc = ct/cc
- indent = 5*self.depth
- funcstr = self.func_std_string()
- out = """
- %(c)s |
- %(tt)8.3f (%(ttdivnc)8.3f) |
- %(ct)8.3f (%(ctdivcc)8.3f) |
- %(funcstr)s |
- """ % locals()
- return mark_safe(out)
+ return 0
+
+ return ct/cc
+ def indent(self):
+ return 16 * self.depth
class ProfilingDebugPanel(DebugPanel):
"""
--
cgit v1.2.3
From a3e8ce8eb1c4e2d1482a22d3a7e0dba7f4ff3201 Mon Sep 17 00:00:00 2001
From: David Cramer
Date: Fri, 22 Apr 2011 14:59:59 -0700
Subject: Basic support for toggling everywhere correctly
---
debug_toolbar/panels/profiling.py | 2 ++
1 file changed, 2 insertions(+)
(limited to 'debug_toolbar/panels/profiling.py')
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index d0ea2c1..68aafb7 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -147,9 +147,11 @@ class ProfilingDebugPanel(DebugPanel):
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:
+ func.has_subfuncs = True
self.add_node(func_list, subfunc, max_depth, cum_time=cum_time)
def content(self):
--
cgit v1.2.3