You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bazarr/libs/flask_debugtoolbar/panels/profiler.py

119 lines
3.5 KiB

try:
import cProfile as profile
except ImportError:
import profile
import functools
import pstats
from flask import current_app
from flask_debugtoolbar.panels import DebugPanel
from flask_debugtoolbar.utils import format_fname
class ProfilerDebugPanel(DebugPanel):
"""
Panel that displays the time a response took with cProfile output.
"""
name = 'Profiler'
user_activate = True
def __init__(self, jinja_env, context={}):
DebugPanel.__init__(self, jinja_env, context=context)
if current_app.config.get('DEBUG_TB_PROFILER_ENABLED'):
self.is_active = True
def has_content(self):
return bool(self.profiler)
def process_request(self, request):
if not self.is_active:
return
self.profiler = profile.Profile()
self.stats = None
def process_view(self, request, view_func, view_kwargs):
if self.is_active:
func = functools.partial(self.profiler.runcall, view_func)
functools.update_wrapper(func, view_func)
return func
def process_response(self, request, response):
if not self.is_active:
return False
if self.profiler is not None:
self.profiler.disable()
try:
stats = pstats.Stats(self.profiler)
except TypeError:
self.is_active = False
return False
function_calls = []
for func in stats.sort_stats(1).fcn_list:
current = {}
info = stats.stats[func]
# Number of calls
if info[0] != info[1]:
current['ncalls'] = '%d/%d' % (info[1], info[0])
else:
current['ncalls'] = info[1]
# Total time
current['tottime'] = info[2] * 1000
# Quotient of total time divided by number of calls
if info[1]:
current['percall'] = info[2] * 1000 / info[1]
else:
current['percall'] = 0
# Cumulative time
current['cumtime'] = info[3] * 1000
# Quotient of the cumulative time divded by the number of
# primitive calls.
if info[0]:
current['percall_cum'] = info[3] * 1000 / info[0]
else:
current['percall_cum'] = 0
# Filename
filename = pstats.func_std_string(func)
current['filename_long'] = filename
current['filename'] = format_fname(filename)
function_calls.append(current)
self.stats = stats
self.function_calls = function_calls
# destroy the profiler just in case
return response
def title(self):
if not self.is_active:
return "Profiler not active"
return 'View: %.2fms' % (float(self.stats.total_tt)*1000,)
def nav_title(self):
return 'Profiler'
def nav_subtitle(self):
if not self.is_active:
return "in-active"
return 'View: %.2fms' % (float(self.stats.total_tt)*1000,)
def url(self):
return ''
def content(self):
if not self.is_active:
return "The profiler is not activated, activate it to use it"
context = {
'stats': self.stats,
'function_calls': self.function_calls,
}
return self.render('panels/profiler.html', context)