proofofconcept icon indicating copy to clipboard operation
proofofconcept copied to clipboard

visualize static call graph

Open bhpayne opened this issue 4 years ago • 10 comments

To aid in diagnosis of issues, a static call graph of compute.py and controller.py and the other .py files would be useful.

https://en.wikipedia.org/wiki/Call_graph

bhpayne avatar Mar 22 '20 14:03 bhpayne

https://pycallgraph.readthedocs.io/en/master/ is good, but I only care about the functions for which I own the .py file.

sudo pip install pycallgraph
pycallgraph graphviz -- controller.py

https://pycallgraph.readthedocs.org/en/master/

https://pypi.python.org/pypi/pycallgraph/1.0.1

http://pycallgraph.slowchop.com/en/master/ http://pycallgraph.slowchop.com/en/develop/index.html

http://www.thinktoomuch.net/2007/06/06/python-call-graphs/

bhpayne avatar Mar 22 '20 20:03 bhpayne

Problem: running the web app means the controller.py doesn't terminate, so the pycallgraph doesn't process the execution trace

bhpayne avatar Apr 01 '20 01:04 bhpayne

Instead of running the web app and using pycallgraph for that, perhaps use

>>> import controller
>>> controller.index()

https://flask.palletsprojects.com/en/1.1.x/shell/

bhpayne avatar Apr 01 '20 13:04 bhpayne

From @msgoff

an example of middleware in flask: https://stackoverflow.com/questions/42864788/apply-flask-logging-middleware-to-only-one-view

An example of pycall graph as django middleware -- https://vinta.ws/code/tools-for-profiling-your-python-django-project.html

bhpayne avatar Apr 05 '20 00:04 bhpayne

@msgoff suggests using an AST walker, e.g., https://www.mattlayman.com/blog/2018/decipher-python-ast/

bhpayne avatar Apr 13 '20 21:04 bhpayne

Ran https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/introspection/static_call_graph.py and produced PNGs that are too noisy to be useful.

bhpayne avatar Apr 16 '20 15:04 bhpayne

In a Docker container I mounted proofofconcept/v7_pickle_web_interface/flask as /scratch and then ran

appuser@d88280cd47d6:/scratch/introspection$ python dump-ast.py ../compute.py | grep "FuncDef" -A1

to get all the function definitions. Playing with the printed output doesn't scale, so I modified your script to return "tree". https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/introspection/dump_ast.py

I wanted to work with the "tree" variable, so I entered a Python shell and ran

>>> from mypy.errors import CompileError
>>> from mypy.options import Options
>>> from mypy import defaults
>>> from mypy.parse import parse
>>> import dump_ast
>>> pyversion = defaults.PYTHON3_VERSION
>>> tree = dump_ast.dump('../compute.py', pyversion)

From there I was able to find a few useful outputs:

>>> for this_import in tree.imports:
...     print(this_import)

>>> for this_func in tree.defs:
...     print('=============')
...     if str(this_func).startswith('FuncDef'): print(this_func)

The next step would be to get the CallExpr from each "this_func" but I don't know how to do that.

bhpayne avatar Apr 17 '20 02:04 bhpayne

@msgoff suggests looking at https://github.com/pytransitions/transitions/blob/master/examples/Graph%20MIxin%20Demo%20Nested.ipynb

bhpayne avatar Jun 30 '20 13:06 bhpayne

Currently the website https://derivationmap.net/ runs in a Docker container and was developed using Flask to create webpages. If you're familiar with the "model-view-controller" paradigm, I've attempted to implement that in https://github.com/allofphysicsgraph/proofofconcept/tree/gh-pages/v7_pickle_web_interface/flask Specifically, the primary file is https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/controller.py which makes many calls to https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/compute.py when generating webpages.

Both of these files are complicated to navigate. Generating a picture of which webpages depend on which functions would be very useful for my project. I think a solution developed for this issue would be generically applicable to any project that uses Flask and the model-view-controller paradigm.

As an example of what I mean, take a look at the "start_new_derivation" route on line https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/controller.py#L1700 That function calls compute.initialize_derivation() which is defined on line https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/compute.py#L5035 which makes a call to dat = clib.read_db(path_to_db) which is defined in https://github.com/allofphysicsgraph/proofofconcept/blob/gh-pages/v7_pickle_web_interface/flask/common_lib.py#L99

Having a picture of this static call graph would help both with debugging and with assessing the impact of changes to workflow (refactoring).

I've made previous attempts at this task; see https://github.com/allofphysicsgraph/proofofconcept/tree/gh-pages/v7_pickle_web_interface/flask/introspection The files that are named "function_dependence_*" are relevant.

bhpayne avatar Sep 09 '20 12:09 bhpayne

Comments migrated from old Trello board:

  • https://github.com/jrfonseca/gprof2dot
  • http://furius.ca/snakefood/
  • https://ejrh.wordpress.com/2011/12/23/call-graphs-in-python/ and https://ejrh.wordpress.com/2012/01/31/call-graphs-in-python-part-2/

bhpayne avatar Sep 11 '20 19:09 bhpayne