Template:ROOT/Exercises/Compiled ROOT Macros

Exercise edit

Use the script you've written before and modify it so it can be run as compiled macro via ACLiC.

  • Make sure that both, calling with and without parameter, will still work.
  • Can your script still be interpreted by CINT after you've changed it?
  • How is the performance of the compiled macro for 100 000 000 numbers? What is faster for 5 numbers?
  • Does the script run faster a second time after compiling? How can you enforce recompilation?

Solution edit

All we have to do is adding three lines of code at the beginning that tell the compiler to include the iostream class (which we need for the console printout) and the TRandom class which is a ROOT class. We also set the namespace to std. That's it.

# include <iostream>
# include "TRandom.h"

using namespace std;

void random_mean(Int_t nums)
{
  TRandom *R = new TRandom(time(0));
  Double_t *seed = new Double_t[nums];
  for (Int_t i = 0; i < nums; i++)
  {
    seed[i] = R->Rndm();
  }
  Double_t mean = 0.0;
  for (Int_t i = 0; i < nums; i++)
  {
    mean += seed[i];
  }
  mean /= nums;
  cout << "mean = " << mean << endl;
}

void random_mean()
{
  random_mean(100000000); // on default, take 1E8 numbers
}

Let's run it as compiled macro for 5 numbers. The + after the filename tells ROOT to run it as compiled macro via ACLiC.

root [0] .x random_mean.cc+(5)
Info in <TUnixSystem::ACLiC>: creating shared library /home/tux/Desktop/test/./random_mean_cc.so
mean = 0.264084

It should take about a second until the result appears. In contrast interpreting the macro with CINT&mdah;this is still possible&mdash will only take less than a second:

root [1] .x random_mean.cc(5)
mean = 0.648964

This is because for such a little job as generating five random numbers and computing their mean, the execution time is so ridiculous low that virtually all the time is needed for compilation. However, if we run the compiled macro again, ACLiC is smart enough to realize that it didn't change and will reuse the binaries. Now execution is only a matter of milliseconds:

root [2] .x random_mean.cc+(5)
Info in <ACLiC>: random_mean_cc has been modified and will be reloaded
mean = 0.418168

You can force ACLiC to compile again even if not necessary by appending ++:

root [3] .x random_mean.cc++(5)
Info in <ACLiC>: unmodified script has already been compiled and loaded
Info in <ACLiC>: it will be regenerated and reloaded!
Info in <TUnixSystem::ACLiC>: creating shared library /home/tux/Desktop/test/./random_mean_cc.so
mean = 0.446351

Now see if calling without parameter will still work and how performance of the compiled macro is for a hundred million numbers. (Remember that it took up to a minute to interpret the script. Try it!) To make a fair competition, recompile the code.

root [4] .x random_mean.cc++
Info in <TUnixSystem::ACLiC>: creating shared library /home/tux/Desktop/test/./random_mean_cc.so
mean = 0.500002

This shouldn't have taken longer than two or three seconds. In some sense, the decision of running a macro as interpreted or as compiled code is like deciding whether you should take the train to visit your friend or you should walk. If your friend lives next door, walking will probably be faster than waiting for the next train to come. But if he happens to live in the next town, the train will be hundred or thousand times faster and the few minutes waiting for it don't account for much.