ROOT, Python, and .NET February 25, 2007Posted by gordonwatts in computers.
Nothing is ever fast enough, except when it takes too long to code…
I’ve long been a fan of the python language. As I’ve said previously, I think C++ is a dead language: there is very little research going on and proposed language improvements are quite limited. Languages like Python, C#, and Java (along with others) are all adding features at an impressive rate that, I think, make them much more productive languages.
I’ve used python for years. And I’ve used ROOT for years. Finally, Wim, down at LBNL, married the two. Previously, the only way to use ROOT was the C++ interpreter, called CINT, bundled with ROOT. With pyROOT, however, one could use python. It was fantastic. I wrote lots of analysis code in python. And I got it done so much faster.
Only one problem — it is slow! The interface between python and ROOT has a fair amount of work to do. Further, it is quite flexible and must make a number of decisions at runtime. The result is that each time you call into ROOT from python some extra processing must occur.
I’m also a big fan of C#. However, calling into real C++ code (i.e. ROOT) from C# is difficult. You have to leave the interpreted world (i.e. the CLR) and go into the C++ world. Other than writing managed C++ this is a big pain. I’ve often generated small stubs of code to enable some small project. It occurred to me just before going on vacation to Vancouver that this process could be automated: ROOT includes full class meta-data.
Add to this there is now an implementing of Python 2.4 on the CLR — IronPython. I could do a apples-to-apples comparison: normal python vs CLR python!
So, that is what I did on my short vacation trip to Vancouver, while Paula was asleep. I wrote some code that would automatically produce wrapper files for a small set of ROOT classes. Enough to create a file, fill a histogram, and close the file. And then I timed them with ROOT’s TStopwatch class. Here are the results:
Raw C++: 7.2 seconds
C#: 11.3 seconds
Raw Python: 143 seconds
IronPython: 64 seconds
Wow — IronPython is a x2 faster. Note this is a statement about how one moves from the python to the C++ world — not the overall speed of IronPython. But it is interesting. Here we are going from Python -> .NET CLR -> C++ and it is x2 faster than going from Python -> C++. Now, I’m willing to bet you good money the reason for this difference is the Python implementation of the ROOT interface is much more flexible than the .NET one I’ve created: the regular python interface has so-called late-binding. That is — it can handle any object you give to it, my .NET translation can only handle objects that were previously converted. If pyROOT implemented that method that I suspect it would be hugely faster than it is now. Hmmm — one can build .NET objects on the fly – I wonder what it would be like if one automated that translation? That is a kind-a cool idea, isn’t it?🙂
If you are curious about the IronPython source code, here it is:
clr.AddReferenceToFileAndPath(“G:\\users\\gwatts\\Documents\\Visual Studio 2005\\Projects\\ROOT Class Interface Maker\\Test – TH1F\\bin\\Release\\ROOTDotNet.dll”)
from ROOT import TFile, TH1F, TStopwatch
sw = TStopwatch ()
f = TFile (“bogus.root”, “RECREATE”, “”, 1)
h = TH1F (“hi”, “there”, 10, 0.0, 10.0)
for i in xrange(100000000):
f.Write(“0”, 0, 0)
Those of you how know pyROOT will note that other than the first two lines the code is basically the same (note: I’ve not implemented default arguments, which is why every single argument is spelled out).
Now, the only thing left in this proof-of-principle is that I can open the file I wrote out, grab the TH1F object, and see if I can get the contents of bin #9. This is complex because TFile::Get returns an anonymous TObject and it has to be turned into a TH1F interface. This is tough in .NET because it doesn’t support multiple inheritance, something that ROOT takes full advantage of.