Skip to content

Instantly share code, notes, and snippets.

@nickvandewiele
Created June 15, 2016 14:34
Show Gist options
  • Save nickvandewiele/4b170e710e8829a60e025de268625301 to your computer and use it in GitHub Desktop.
Save nickvandewiele/4b170e710e8829a60e025de268625301 to your computer and use it in GitHub Desktop.
A standalone script to convert a cProfile CPU-profiling *.prof file into a graph.
import sys
import subprocess
import logging
import pstats
try:
from gprof2dot import PstatsParser, DotWriter, SAMPLES, themes
except ImportError:
logging.warning(
'Trouble importing from package gprof2dot. Unable to create a graph of the profile statistics.')
logging.warning(
'Try getting the latest version with something like `pip install --upgrade gprof2dot`.')
class Tee:
"""A simple tee to create a stream which prints to many streams.
This is used to report the profiling statistics to both the log file
and the standard output.
"""
def __init__(self, *fileobjects):
self.fileobjects=fileobjects
def write(self, string):
for fileobject in self.fileobjects:
fileobject.write(string)
def main(stats_file):
processProfileStats(stats_file)
makeProfileGraph(stats_file)
def processProfileStats(stats_file):
out_stream = Tee(sys.stdout)
stats = pstats.Stats(stats_file, stream=out_stream)
stats.strip_dirs()
print >>out_stream, "Sorted by internal time"
stats.sort_stats('time')
stats.print_stats(25)
stats.print_callers(25)
print >>out_stream, "Sorted by cumulative time"
stats.sort_stats('cumulative')
stats.print_stats(25)
stats.print_callers(25)
stats.print_callees(25)
def makeProfileGraph(stats_file):
"""
Uses gprof2dot to create a graphviz dot file of the profiling information.
This requires the gprof2dot package available via `pip install gprof2dot`.
Render the result using the program 'dot' via a command like
`dot -Tpdf input.dot -o output.pdf`.
"""
# create an Options class to mimic optparser output as much as possible:
class Options:
pass
options = Options()
options.node_thres = 0.8
options.edge_thres = 0.1
options.strip = False
options.show_samples = False
options.root = ""
options.leaf = ""
options.wrap = True
theme = themes['color'] # bw color gray pink
# default "Arial" leads to PostScript warnings in dot (on Mac OS)
theme.fontname = "ArialMT"
parser = PstatsParser(stats_file)
profile = parser.parse()
dot_file = stats_file + '.dot'
output = open(dot_file, 'wt')
dot = DotWriter(output)
dot.strip = options.strip
dot.wrap = options.wrap
if options.show_samples:
dot.show_function_events.append(SAMPLES)
profile = profile
profile.prune(options.node_thres / 100.0, options.edge_thres / 100.0)
if options.root:
rootId = profile.getFunctionId(options.root)
if not rootId:
sys.stderr.write(
'root node ' + options.root + ' not found (might already be pruned : try -e0 -n0 flags)\n')
sys.exit(1)
profile.prune_root(rootId)
if options.leaf:
leafId = profile.getFunctionId(options.leaf)
if not leafId:
sys.stderr.write(
'leaf node ' + options.leaf + ' not found (maybe already pruned : try -e0 -n0 flags)\n')
sys.exit(1)
profile.prune_leaf(leafId)
dot.graph(profile, theme)
output.close()
try:
subprocess.check_call(
['dot', '-Tpdf', dot_file, '-o', '{0}.pdf'.format(dot_file)])
except subprocess.CalledProcessError:
logging.error(
"Error returned by 'dot' when generating graph of the profile statistics.")
logging.info(
"To try it yourself:\n dot -Tpdf {0} -o {0}.pdf".format(dot_file))
except OSError:
logging.error(
"Couldn't run 'dot' to create graph of profile statistics. Check graphviz is installed properly and on your path.")
logging.info(
"Once you've got it, try:\n dot -Tpdf {0} -o {0}.pdf".format(dot_file))
else:
logging.info(
"Graph of profile statistics saved to: \n {0}.pdf".format(dot_file))
if __name__ == "__main__":
stats_file = sys.argv[1]
main(stats_file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment