Skip to content

Instantly share code, notes, and snippets.

@jpeyret
Last active May 4, 2023 09:24
Show Gist options
  • Save jpeyret/33739f6cd99f6108ad5046bd47df5a16 to your computer and use it in GitHub Desktop.
Save jpeyret/33739f6cd99f6108ad5046bd47df5a16 to your computer and use it in GitHub Desktop.
filtering a big pycallgraph svg

Filtering down a big pycallgraph svg - using the gvpr utility that's in Graphviz

Step 0. determine where you want to save the necessary temp file.

export pycallgraphcopy=~/temp/pycallgraphcopy.dot

Step 1. hack pycallgraph. Yes, really.

Pycallgraph is great, but it's also not maintained anymore.

  • open <your env>/lib/python2.7/site-packages/pycallgraph/output/graphviz.py

  • add the following lines in the def done:

def done(self):
        source = self.generate()

        self.debug(source)

        fd, temp_name = tempfile.mkstemp()
        with os.fdopen(fd, 'w') as f:
            f.write(source)

        #>>>> this sneaks out a copy before the temp dot file is used
        import shutil
        copytgt = os.getenv("pycallgraphcopy")
        if copytgt:
            shutil.copyfile(temp_name, copytgt)
        #<<<<< thats it here

Step 2 - create a work directory for your scripts

create the file re.filter.txt

\s+"logging
\s+"threading
\s+"unittest
\s+"repr\.Repr
\s+"gettext

This uses a negative -v grep to filter out all the nodes you don't want to see, ** and their descendants**

Step 3 - download the reduce.g script to be used by gvpr

https://gist.github.com/blabber/74b8d9ed59d0b2ad0d7a734113996424

gvpr will run reduce.g to select only children and ancestors of the node you want to select.

Note: I didn't write reduce.g and have no clue how it works.

Step 4 add filterdot.sh below.

Permissions: chmod u+x filterdot.sh

This script will

  • run the grep to filter out the noise like logging calls.
  • fire reduce.g to select all the nodes beneath the node you give as an argument.
  • run dot to generate an svg.

Basically if you ran pycallgraph via unittest but you only want to see what's in MyTestClass.test_i_want you can use that script to only show things that happened there.

Usage:

  • find a way to trigger pycallgraph svg generation.
  • go to the work directory you created in step 2.
  • run filterdot.sh "MyTestClass.test_i_want"
  • open the generated selected.node.svg
#!/usr/bin/env bash
set -u
set -e
# echo "pycallgraphcopy:$pycallgraphcopy:"
node_to_select=$1
egrep -v -f re.filter.txt $pycallgraphcopy > _filtered.dot
#check grep finds the target, but disable auto-exit on error first
set +e
egrep $node_to_select _filtered.dot > /dev/null
notfound=$?
set -e
if (( ! $notfound == 0 )); then
echo "didn't find :$node_to_select: in _filtered.dot"
exit
fi
#
echo lines remaining after filter:
wc -l _filtered.dot
gvpr -f reduce.g -a " \"$node_to_select\" 10" _filtered.dot > _selected.node.dot
#reduce will expand the number of lines
# echo lines selected:
# wc -l _selected.node.dot
dot _selected.node.dot -T svg -o selected.node.svg
echo results output to `realpath selected.node.svg`
echo ''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment