Exploring Rotor and Mono with monograph

by Brian Jepson

Back in February, I was intrigued by Paolo Molaro's
href="http://lists.ximian.com/archives/public/mono-list/2002-February/003128.html">How
does mono _look_ like? post. That post leads to a href="http://people.debian.org/~lupus/mono/">web page containing
visualizations of Mono's class library created with monograph and href="http://www.research.att.com/sw/tools/graphviz/">graphviz.



monograph is a tool that Paolo developed; it generates the raw data
that graphviz uses to generate the images. (monograph is included in
current mono
release
.) After I started
href="http://onjava.com/pub/a/dotnet/2002/03/27/gettingstarted.html">working
with Rotor, Microsoft's shared source CLI, I thought it would be
fun to use monograph to peruse Rotor's base class libraries. I got
sidetracked by some other projects, and went a while without having
the latest version of Mono on my system. However, the href="http://conferences.oreillynet.com/etcon2002/">O'Reilly Emerging
Technology Conference is rapidly approaching, and I wanted to make
sure I have a comprehensive assortment of ECMA CLI implementations on my
laptop. So, I set up three partitions: the latest beta of Windows .NET
Web Server with Visual Studio .NET, FreeBSD 4.5 with Rotor, and
Mandrake 8.2 with Mono (to build Mono, the only things I needed to add
to the stock install of Mandrake 8.2 were href="http://mail.gnome.org/archives/gtk-list/2002-March/msg00522.html">glib
2.0.1 and href="http://www.freedesktop.org/software/pkgconfig/">pkg-config,
both of which I installed in /opt). I still have yet to install DotGNU
Portable.NET
, but it won't be long before I add this to my
assortment.



After I had Rotor and Mono built and running, I downloaded and
installed
graphviz on my Linux system. Then, I copied Rotor's
mscorlib.dll and System.dll over to my Linux partition. Now,
everything was in place for my sinister experiments.
First, I generated a call graph for
System.Net.WebClient.DownloadData():




[bjepson@localhost RotorDLLs]$ monograph -n -o example.ps -c \
./System.dll System.Net.WebClient:DownloadData



Note that I prefixed the DLL name with ./ to explicitly
specify the Rotor DLL I had copied over. Otherwise, monograph might
have picked up Mono's System.dll. The figure I got was convoluted, so I tried limiting the recursion
depth with -d 1:




[bjepson@localhost RotorDLLs]$ monograph -d 1 -n -o example.ps -c \
./System.dll System.Net.WebClient:DownloadData



Figure 1 shows a thumbnail of the output. Click on the thumbnail to
see a larger version.




src="http://www.jepstone.net/images/rotor-callgraph-thumb.png">

Figure 1. Rotor call graph of System.Net.WebClient:DownloadData()



Since monograph generates an intermediate textual representation of
the call graph, I thought it would be interesting to compare two
implementations of the same method. So, I removed the -n
option, which automatically invoked the graphviz neato command, and specified a method that wasn't quite as big as the previous example. This
leaves me with two text documents, mono.txt and rotor.txt:




[bjepson@localhost RotorDLLs]$ monograph -d 1 -o rotor.txt -c \
./mscorlib.dll System.Collections.Hashtable:Add
[bjepson@localhost RotorDLLs]$ monograph -d 1 -o mono.txt -c \
/opt/lib/corlib.dll System.Collections.Hashtable:Add



As you can see, the implementations are quite different (I removed the
Hashtable: prefix from Hashtable's methods to minimize
annoying HTML wrapping problems):




mono.txt:
digraph blah {
node [fontsize=8.0]
edge [len=2,color=red]
"Add(object,object)" -> "Hashtable:PutImpl(object,object,bool)"
"PutImpl(object,object,bool)" -> "ArgumentNullException:.ctor(string)"
"PutImpl(object,object,bool)" -> "Rehash()"
"PutImpl(object,object,bool)" -> "GetHash(object)"
"PutImpl(object,object,bool)" -> "KeyEquals(object,object)"
"PutImpl(object,object,bool)" -> "ArgumentException:.ctor(string)"
}

rotor.txt:
digraph blah {
node [fontsize=8.0]
edge [len=2,color=red]
"Add(object,object)" -> "Hashtable:Insert(object,object,bool)"
"Insert(object,object,bool)" -> "Environment:GetResourceString(string)"
"Insert(object,object,bool)" -> "ArgumentNullException:.ctor(string,string)"
"Insert(object,object,bool)" -> "expand()"
"Insert(object,object,bool)" -> "InitHash(object,uint,int&,int&)"
"Insert(object,object,bool)" -> "KeyEquals(object,object)"
"Insert(object,object,bool)" -> "Environment:GetResourceString(string,object[])"
"Insert(object,object,bool)" -> "ArgumentException:.ctor(string)"
"Insert(object,object,bool)" -> "BCLDebug:Assert(bool,string)"
"Insert(object,object,bool)" -> "InvalidOperationException:.ctor(string)"
}



Figure 2 shows the two call graphs.




src="http://www.jepstone.net/images/rotor-compare-thumb.png">
src="http://www.jepstone.net/images/mono-compare-thumb.png">

Figure 2. Rotor and Mono call graphs, compared.



The beauty of monograph is that you can use it with
an assembly from any of the ECMA CLI implementations. Given
that these implementations are huge, it's helpful
to have a visualization tool that can turn complex relationships
into understandable pictures.

Have you made any cool pictures with monograph? If so, post the link!