Skip to content

Commit

Permalink
Merge pull request #1383 from SpaceFox/issue_1337_profiling
Browse files Browse the repository at this point in the history
Issue 1337 profiling
  • Loading branch information
dralliw committed Aug 20, 2014
2 parents ea228a1 + 27de284 commit 17bb431
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
121 changes: 121 additions & 0 deletions zds/middlewares/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Orignal version taken from http://www.djangosnippets.org/snippets/186/
# Original author: udfalkso
# Modified by: Shwagroo Team and Gun.io

import sys
import os
import re
import hotshot, hotshot.stats
import tempfile
import StringIO

from django.conf import settings

words_re = re.compile( r'\s+' )

group_prefix_re = [
re.compile( "^.*/django/[^/]+" ),
re.compile( "^(.*)/[^/]+$" ), # extract module path
re.compile( ".*" ), # catch strange entries
]


def can_profile(request):
return (settings.DEBUG or (request.user is not None and request.user.is_superuser)) and 'prof' in request.GET


class ProfileMiddleware(object):
"""
Displays hotshot profiling for any view.
http://yoursite.com/yourview/?prof
Add the "prof" key to query string by appending ?prof (or &prof=)
and you'll see the profiling results in your browser.
It's set up to only be available in django's debug mode, is available for superuser otherwise,
but you really shouldn't add this middleware to any production configuration.
WARNING: It uses hotshot profiler which is not thread safe.
"""

def process_request(self, request):
if can_profile(request):
self.tmpfile = tempfile.mktemp()
self.prof = hotshot.Profile(self.tmpfile)

def process_view(self, request, callback, callback_args, callback_kwargs):
if can_profile(request):
return self.prof.runcall(callback, request, *callback_args, **callback_kwargs)

def get_group(self, file):
for g in group_prefix_re:
name = g.findall( file )
if name:
return name[0]

def get_summary(self, results_dict, sum):
list = [ (item[1], item[0]) for item in results_dict.items() ]
list.sort( reverse = True )
list = list[:40]

res = " tottime\n"
for item in list:
res += "%4.1f%% %7.3f %s\n" % ( 100*item[0]/sum if sum else 0, item[0], item[1] )

return res

def summary_for_files(self, stats_str):
stats_str = stats_str.split("\n")[5:]

mystats = {}
mygroups = {}

sum = 0

for s in stats_str:
fields = words_re.split(s);
if len(fields) == 7:
time = float(fields[2])
sum += time
file = fields[6].split(":")[0]

if not file in mystats:
mystats[file] = 0
mystats[file] += time

group = self.get_group(file)
if not group in mygroups:
mygroups[ group ] = 0
mygroups[ group ] += time

return "<pre>" + \
" ---- By file ----\n\n" + self.get_summary(mystats,sum) + "\n" + \
" ---- By group ---\n\n" + self.get_summary(mygroups,sum) + \
"</pre>"

def process_response(self, request, response):
try:
if can_profile(request):
self.prof.close()

out = StringIO.StringIO()
old_stdout = sys.stdout
sys.stdout = out

stats = hotshot.stats.load(self.tmpfile)
stats.sort_stats('time', 'calls')
stats.print_stats()

sys.stdout = old_stdout
stats_str = out.getvalue()

if response and response.content and stats_str:
response.content = "<pre>" + stats_str + "</pre>"

response.content = "\n".join(response.content.split("\n")[:40])

response.content += self.summary_for_files(stats_str)

os.unlink(self.tmpfile)
except:
pass
return response
1 change: 1 addition & 0 deletions zds/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'zds.utils.ThreadLocals',
'zds.middlewares.SetLastVisitMiddleware.SetLastVisitMiddleware',
'zds.middlewares.profile.ProfileMiddleware',
)

ROOT_URLCONF = 'zds.urls'
Expand Down

0 comments on commit 17bb431

Please sign in to comment.