Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
00008c06
Commit
00008c06
authored
Oct 20, 2014
by
Matt Drayer
Committed by
Jonathan Piacenti
Aug 20, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mattdrayer/profiler-updates: PEP8/Pylint
parent
ddc979d3
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
112 additions
and
71 deletions
+112
-71
common/djangoapps/profiler/middleware.py
+112
-71
No files found.
common/djangoapps/profiler/middleware.py
View file @
00008c06
...
@@ -112,6 +112,98 @@ class BaseProfilerMiddleware(object):
...
@@ -112,6 +112,98 @@ class BaseProfilerMiddleware(object):
THREAD_LOCAL
.
profiler
=
self
.
profiler_start
()
THREAD_LOCAL
.
profiler
=
self
.
profiler_start
()
return
THREAD_LOCAL
.
profiler
.
runcall
(
callback
,
request
,
*
callback_args
,
**
callback_kwargs
)
return
THREAD_LOCAL
.
profiler
.
runcall
(
callback
,
request
,
*
callback_args
,
**
callback_kwargs
)
def
_generate_console_response
(
self
,
stats_str
,
stats_summary
):
"""
Output directly to the console -- helpful during unit testing or
for viewing code executions in devstack
"""
print
stats_str
print
stats_summary
def
_generate_text_response
(
self
,
stats_str
,
stats_summary
,
response
):
"""
Output the call stats to the browser as plain text
"""
response
[
'Content-Type'
]
=
'text/plain'
response
.
content
=
stats_str
response
.
content
=
"
\n
"
.
join
(
response
.
content
.
split
(
"
\n
"
)[:
40
])
response
.
content
+=
"
\n\n
"
response
.
content
+=
stats_summary
def
_generate_html_response
(
self
,
stats_str
,
stats_summary
,
response
):
"""
Output the call stats to the browser wrapped in HTML tags
Feel free to improve the HTML structure!!!
"""
response
[
'Content-Type'
]
=
'text/html'
response
.
content
=
'<pre>{}{}</pre>'
.
format
(
stats_str
,
stats_summary
)
def
_generate_pdf_response
(
self
,
response
):
"""
Output a pretty picture of the call tree (boxes and arrows)
"""
if
not
which
(
'dot'
):
raise
Exception
(
'Could not find "dot" from Graphviz; please install Graphviz to enable call graph generation'
)
if
not
which
(
'gprof2dot'
):
raise
Exception
(
'Could not find gprof2dot; have you updated your dependencies recently?'
)
command
=
(
'gprof2dot -f pstats {} | dot -Tpdf'
.
format
(
THREAD_LOCAL
.
data_file
.
name
))
process
=
subprocess
.
Popen
(
command
,
shell
=
True
,
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
)
output
=
process
.
communicate
()[
0
]
return_code
=
process
.
poll
()
if
return_code
:
raise
Exception
(
'gprof2dot/dot exited with {}'
.
format
(
return_code
))
response
[
'Content-Type'
]
=
'application/pdf'
response
.
content
=
output
def
_generate_svg_response
(
self
,
response
):
"""
Output a pretty picture of the call tree (boxes and arrows)
"""
# Set up the data file
profile_name
=
'{}_{}'
.
format
(
self
.
profiler_type
(),
time
.
time
())
profile_data
=
'/tmp/{}.dat'
.
format
(
profile_name
)
shutil
.
copy
(
THREAD_LOCAL
.
data_file
.
name
,
profile_data
)
os
.
chmod
(
profile_data
,
0666
)
# Create the output file
profile_svg
=
'/tmp/{}.svg'
.
format
(
profile_name
)
old
=
os
.
path
.
abspath
(
'.'
)
os
.
chdir
(
'/tmp'
)
command
=
'gprof2dot -f pstats {} | dot -Tsvg -o {}'
.
format
(
profile_data
,
profile_svg
)
try
:
output
=
subprocess
.
call
(
command
,
shell
=
True
)
except
Exception
:
# pylint: disable=W0703
output
=
'Error during call to gprof2dot/dot'
os
.
chdir
(
old
)
if
os
.
path
.
exists
(
profile_svg
):
response
[
'Content-Type'
]
=
'image/svg+xml'
f
=
open
(
profile_svg
)
response
.
content
=
f
.
read
()
f
.
close
()
else
:
response
[
'Content-Type'
]
=
'text/plain'
response
.
content
=
output
def
_generate_raw_response
(
self
,
response
):
"""
Output the raw stats data to the browser -- the caller can then
save the information to a local file and do something else with it
Could be used as an integration point in the future for real-time
diagrams, charts, reports, etc.
"""
# Set up the data faile (this is all we do in this particular case)
profile_name
=
'{}_{}'
.
format
(
self
.
profiler_type
(),
time
.
time
())
profile_data
=
'/tmp/{}.dat'
.
format
(
profile_name
)
shutil
.
copy
(
THREAD_LOCAL
.
data_file
.
name
,
profile_data
)
os
.
chmod
(
profile_data
,
0666
)
# Return the raw data directly to the caller/browser (useful for API scenarios)
f
=
open
(
profile_data
)
response
.
content
=
f
.
read
()
f
.
close
()
def
process_response
(
self
,
request
,
response
):
def
process_response
(
self
,
request
,
response
):
"""
"""
Most of the heavy lifting takes place in this base process_response operation
Most of the heavy lifting takes place in this base process_response operation
...
@@ -177,71 +269,21 @@ class BaseProfilerMiddleware(object):
...
@@ -177,71 +269,21 @@ class BaseProfilerMiddleware(object):
if
response
and
response
.
content
and
stats_str
:
if
response
and
response
.
content
and
stats_str
:
stats_summary
=
self
.
summary_for_files
(
stats_str
)
stats_summary
=
self
.
summary_for_files
(
stats_str
)
response_format
=
request
.
GET
.
get
(
'profiler_format'
,
'console'
)
response_format
=
request
.
GET
.
get
(
'profiler_format'
,
'console'
)
# Console format sends the profiler result to stdout, preserving current response content
# All other formats replace response content with the profiler result
if
response_format
==
'console'
:
if
response_format
==
'console'
:
# Send the profiler result to stdout, preserving current response content
self
.
_generate_console_response
(
stats_str
,
stats_summary
)
# All other formats replace response content with the profiler result
print
stats_str
print
stats_summary
elif
response_format
==
'text'
:
elif
response_format
==
'text'
:
response
[
'Content-Type'
]
=
'text/plain'
self
.
_generate_text_response
(
stats_str
,
stats_summary
,
response
)
response
.
content
=
stats_str
response
.
content
=
"
\n
"
.
join
(
response
.
content
.
split
(
"
\n
"
)[:
40
])
response
.
content
+=
"
\n\n
"
response
.
content
+=
stats_summary
elif
response_format
==
'html'
:
elif
response_format
==
'html'
:
response
[
'Content-Type'
]
=
'text/html'
self
.
_generate_html_response
(
stats_str
,
stats_summary
,
response
)
response
.
content
=
'<pre>{}{}</pre>'
.
format
(
stats_str
,
stats_summary
)
elif
response_format
==
'pdf'
:
elif
response_format
==
'pdf'
:
if
not
which
(
'dot'
):
self
.
_generate_pdf_response
(
response
)
raise
Exception
(
'Could not find "dot" from Graphviz; please install Graphviz to enable call graph generation'
)
if
not
which
(
'gprof2dot'
):
raise
Exception
(
'Could not find gprof2dot; have you updated your dependencies recently?'
)
command
=
(
'gprof2dot -f pstats {} | dot -Tpdf'
.
format
(
THREAD_LOCAL
.
data_file
.
name
))
process
=
subprocess
.
Popen
(
command
,
shell
=
True
,
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
)
output
=
process
.
communicate
()[
0
]
return_code
=
process
.
poll
()
if
return_code
:
raise
Exception
(
'gprof2dot/dot exited with {}'
.
format
(
return_code
))
response
[
'Content-Type'
]
=
'application/pdf'
response
.
content
=
output
elif
response_format
==
'svg'
:
elif
response_format
==
'svg'
:
# Set up the data file
self
.
_generate_svg_response
(
response
)
profile_name
=
'{}_{}'
.
format
(
self
.
profiler_type
(),
time
.
time
())
profile_data
=
'/tmp/{}.dat'
.
format
(
profile_name
)
shutil
.
copy
(
THREAD_LOCAL
.
data_file
.
name
,
profile_data
)
os
.
chmod
(
profile_data
,
0666
)
# Create the output file
profile_svg
=
'/tmp/{}.svg'
.
format
(
profile_name
)
old
=
os
.
path
.
abspath
(
'.'
)
os
.
chdir
(
'/tmp'
)
command
=
'gprof2dot -f pstats {} | dot -Tsvg -o {}'
.
format
(
profile_data
,
profile_svg
)
try
:
output
=
subprocess
.
call
(
command
,
shell
=
True
)
except
Exception
:
output
=
'Error during call to gprof2dot/dot'
os
.
chdir
(
old
)
if
os
.
path
.
exists
(
profile_svg
):
response
[
'Content-Type'
]
=
'image/svg+xml'
f
=
open
(
profile_svg
)
response
.
content
=
f
.
read
()
f
.
close
()
else
:
response
[
'Content-Type'
]
=
'text/plain'
response
.
content
=
output
elif
response_format
==
'raw'
:
elif
response_format
==
'raw'
:
# Set up the data faile (this is all we do in this particular case)
self
.
_generate_raw_response
(
response
)
profile_name
=
'{}_{}'
.
format
(
self
.
profiler_type
(),
time
.
time
())
profile_data
=
'/tmp/{}.dat'
.
format
(
profile_name
)
shutil
.
copy
(
THREAD_LOCAL
.
data_file
.
name
,
profile_data
)
os
.
chmod
(
profile_data
,
0666
)
# Return the raw data directly to the caller/browser (useful for API scenarios)
f
=
open
(
profile_data
)
response
.
content
=
f
.
read
()
f
.
close
()
# Clean up the stuff we stuffed into thread_local and then return the response to the caller
# Clean up the stuff we stuffed into thread_local and then return the response to the caller
THREAD_LOCAL
.
profiler_type
=
None
THREAD_LOCAL
.
profiler_type
=
None
THREAD_LOCAL
.
profiler_requested
=
None
THREAD_LOCAL
.
profiler_requested
=
None
...
@@ -265,7 +307,7 @@ class BaseProfilerMiddleware(object):
...
@@ -265,7 +307,7 @@ class BaseProfilerMiddleware(object):
"""
"""
return
MiddlewareNotUsed
()
return
MiddlewareNotUsed
()
def
profiler_stop
(
self
):
def
profiler_stop
(
self
,
stream
):
# pylint: disable=W0613
"""
"""
Parent method -- should be overridden by child
Parent method -- should be overridden by child
"""
"""
...
@@ -331,16 +373,15 @@ class BaseProfilerMiddleware(object):
...
@@ -331,16 +373,15 @@ class BaseProfilerMiddleware(object):
"""
"""
Provide some useful operational info to the caller
Provide some useful operational info to the caller
"""
"""
return
"########## PROFILER HELP ##########
\n\n\n
"
+
\
return
"########## PROFILER HELP ##########
\n\n\n
"
+
\
"Profiler Options (query string params):
\n\n
"
+
\
"Profiler Options (query string params):
\n\n
"
+
\
"profiler_type: hotshot (default), cprofile
\n
"
+
\
"profiler_type: hotshot (default), cprofile
\n
"
+
\
"profiler_mode: normal (default), help
\n
"
+
\
"profiler_mode: normal (default), help
\n
"
+
\
"profiler_sort: time (default) calls, cumulative, file, module, ncalls
\n
"
+
\
"profiler_sort: time (default) calls, cumulative, file, module, ncalls
\n
"
+
\
"profiler_format: console (default), text, html, pdf, svg, raw
\n\n\n
"
+
\
"profiler_format: console (default), text, html, pdf, svg, raw
\n\n\n
"
+
\
"More info:
\n\n
"
+
\
"More info:
\n\n
"
+
\
"https://docs.python.org/2/library/hotshot.html
\n
"
+
\
"https://docs.python.org/2/library/hotshot.html
\n
"
+
\
"https://docs.python.org/2/library/profile.html#module-cProfile
\n
"
"https://docs.python.org/2/library/profile.html#module-cProfile
\n
"
class
HotshotProfilerMiddleware
(
BaseProfilerMiddleware
):
class
HotshotProfilerMiddleware
(
BaseProfilerMiddleware
):
...
@@ -370,7 +411,7 @@ class HotshotProfilerMiddleware(BaseProfilerMiddleware):
...
@@ -370,7 +411,7 @@ class HotshotProfilerMiddleware(BaseProfilerMiddleware):
"""
"""
return
hotshot
.
Profile
(
THREAD_LOCAL
.
data_file
.
name
)
return
hotshot
.
Profile
(
THREAD_LOCAL
.
data_file
.
name
)
def
profiler_stop
(
self
,
stream
):
def
profiler_stop
(
self
,
stream
):
# pylint: disable=W0221
"""
"""
Store profiler data in file and return statistics to caller
Store profiler data in file and return statistics to caller
"""
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment