{"id":248,"date":"2012-01-03T19:40:00","date_gmt":"2012-01-03T23:40:00","guid":{"rendered":"http:\/\/ryepup.unwashedmeme.com\/blog\/?p=248"},"modified":"2012-01-03T23:42:20","modified_gmt":"2012-01-04T03:42:20","slug":"visualizing-call-graphs-in-lisp-using-swank-and-graphviz","status":"publish","type":"post","link":"http:\/\/ryepup.unwashedmeme.com\/blog\/2012\/01\/03\/visualizing-call-graphs-in-lisp-using-swank-and-graphviz\/","title":{"rendered":"Visualizing call graphs in lisp using swank and graphviz"},"content":{"rendered":"\n<p>Last week I was doing some cleanup work (short holiday weeks are great for paying off technical debt), and was deleting some supposedly unused code. This was a pretty tedious process of running functions like <code>slime-who-calls<\/code> and <code>slime-who-references<\/code>, running <code>git grep -i<\/code> on the command line, and undefining functions in just the right order. <\/p>\n<p> I&#8217;ve seen a lot of articles recently on static analysis of code, and spent some time playing with the introspection features of <a href=\"http:\/\/common-lisp.net\/project\/slime\/\">slime<\/a> to identify unused code (short holiday weeks are also great for following a tangents). I ended up with a slow mudball of code that worked pretty well. <\/p>\n<p> Warning, large images coming up. <\/p>\n<p> The code itself is up on <a href=\"https:\/\/github.com\/AccelerationNet\/static-analysis\/blob\/master\/static-analysis.lisp\">github<\/a>, but there&#8217;s no ASDF system yet, so you have to load it manually: <\/p>\n<pre class=\"example\">(require :iterate)\n(require :alexandria)\n(require :swank)\n(load \"~\/lisp\/static-analysis\/static-analysis.lisp\")\n(in-package :static-analysis)\n<\/pre>\n<p> An truncated example: <\/p>\n<pre class=\"example\">STATIC-ANALYSIS&gt; (call-graph-&gt;dot :alexandria )\ndigraph g{\nsubgraph clusterG982{\nlabel=\"PACKAGE STATIC-ANALYSIS\"\nG983 [label=\"ENSURE-PACKAGE-LIST\"]\n}\nsubgraph clusterG949{\nlabel=\"PACKAGE ALEXANDRIA.0.DEV\"\n...\n}\nG983 -&gt; G995\n...\nG951 -&gt; G950\n}\nNIL\n<\/pre>\n<p> Here&#8217;s what it actually looks like: <\/p>\n<p> <img decoding=\"async\" src=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-alexandria-graph.png\"  alt=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-alexandria-graph.png\" \/> <\/p>\n<p> The code currently scans all loaded code, and puts functions from each package in it&#8217;s own graphviz subgraph. The graph for an entire package for all loaded code isn&#8217;t really that useful, so I made another function to narrow it down. Here I&#8217;m specifying the list of packages to render, and the list of functions to show. <\/p>\n<pre class=\"example\">STATIC-ANALYSIS&gt; (-&gt;dot (function-call-graph '(:alexandria) '(alexandria:rotate)))\ndigraph g{\nsubgraph clusterG1109{\nlabel=\"PACKAGE ALEXANDRIA.0.DEV\"\nG1040 [label=\"ROTATE-HEAD-TO-TAIL\"]\nG1049 [label=\"SAFE-ENDP\"]\nG1054 [label=\"CIRCULAR-LIST-ERROR\"]\nG1051 [label=\"PROPER-LIST-LENGTH\"]\nG1042 [label=\"ROTATE-TAIL-TO-HEAD\"]\nG1041 [label=\"ROTATE\"]\n}\nG1040 -&gt; G1051\nG1051 -&gt; G1049\nG1051 -&gt; G1054\nG1042 -&gt; G1051\nG1041 -&gt; G1040\nG1041 -&gt; G1042\n}\nNIL\n<\/pre>\n<p> <img decoding=\"async\" src=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-alexandria-rotate.png\"  alt=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-alexandria-rotate.png\" \/> <\/p>\n<p> Some systems have very complicated call graphs. At work we do a lot with <a href=\"http:\/\/clsql.b9.com\/\">clsql<\/a>, and the overall call graph even from one function can get complicated quick: <\/p>\n<p> <img decoding=\"async\" src=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-clsql.png\"  alt=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-clsql.png\" \/> <\/p>\n<p> So I added a depth param to keep the graph smaller, let&#8217;s say 3: <\/p>\n<pre class=\"example\">STATIC-ANALYSIS&gt; (-&gt;dot\n (function-call-graph '(:clsql-sys :clsql-sqlite3)\n                      '(clsql:map-query)\n                      2))\n<\/pre>\n<p> <img decoding=\"async\" src=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-clsql-limited.png\"  alt=\"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-content\/uploads\/2012\/01\/wpid-clsql-limited.png\" \/> <\/p>\n<p> Anyhoo, a fun toy, and I had a fun time writing it.  <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week I was doing some cleanup work (short holiday weeks are great for paying off technical debt), and was deleting some supposedly unused code. This was a pretty tedious process of running functions like slime-who-calls and slime-who-references, running git grep -i on the command line, and undefining functions in just the right order. I&#8217;ve [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15,44],"tags":[],"class_list":["post-248","post","type-post","status-publish","format-standard","hentry","category-lisp","category-org2blog"],"_links":{"self":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/248","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/comments?post=248"}],"version-history":[{"count":9,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/248\/revisions"}],"predecessor-version":[{"id":259,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/248\/revisions\/259"}],"wp:attachment":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/media?parent=248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/categories?post=248"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/tags?post=248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}