O'Reilly Network    


 Published on The O'Reilly Network (http://www.oreillynet.com/)
 http://www.oreillynet.com/pub/wlg/1345

Exploring Rotor and Mono with monograph

by Brian Jepson
Apr. 29, 2002

Back in February, I was intrigued by Paolo Molaro's How does mono _look_ like? post. That post leads to a web page containing visualizations of Mono's class library created with monograph and 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 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 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 glib 2.0.1 and 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.


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.


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.

Brian Jepson is an O'Reilly editor, programmer, and co-author of Mac OS X Panther for Unix Geeks and Learning Unix for Mac OS X Panther. He's also a volunteer system administrator and all-around geek for AS220, a non-profit arts center in Providence, Rhode Island. AS220 gives Rhode Island artists uncensored and unjuried forums for their work. These forums include galleries, performance space, and publications. Brian sees to it that technology, especially free software, supports that mission. You can follow Brian's blog here.

oreillynet.com Copyright © 2006 O'Reilly Media, Inc.