CInt Function Stub Removal ROOT Team Meeting CERN Leandro Franco (Joint work with Diego Marcos)
Modifying CInt?... A.K.A : The Piñata paradigm CInt Newbie Experienced Programmers Goal: Obtain the candies from the piñata... without breaking anybody's head.
Simple Idea ● The dictionaries are big: around 52% of the total library size. ● Why don't we just wipe them off from the face of earth? ● Short answer: we can't do it yet, but we will try. ● Long answer: the whole topic of these slides ;)
First steps ● One good way to shrink the dictionaries is to remove the stub functions. ● Such functions come from the need of having a generic way to call a function in Cint and from the impossibility of doing a proper name mangling to find such function (i.e. Cint must behave as a compiler but doesn't have the means to do so).
Stub Functions ● To be able to solve the name mangling problem a traditional approach was taken: “Any problem in computer science can be solved with another layer of indirection” Wheeler's Law
Stub Functions Compiler/CInt Library function CIntLibrary functionDictionary mangling compiling time pseudo mangling running time mangling compiling time The dictionary could be seen as a bijective function that maps c++ function declarations to a certain string (string which will be associated to the symbol by the compiler)
Stub Functions ● The idea is to avoid that layer of indirection. – We still don't how to do the mangling. ● But we know how to do the demangling (or at least, we know who to call to do it ;) ). function header (X)library (Y) A::A() _ZN1AC1Ev A::HiA() _ZN1A3HiAEv Instead of going from set X to set Y for a given x in X function header (X)library (Y) A::A() _ZN1AC1Ev A::HiA() _ZN1A3HiAEv Go from set Y to set X for all y in Y
Stub Functions ● This approach writes in stone the biggest side effect: – We will need to demangle ALL the symbols in a library just to be able to call 1 function. ● The demangling process might not be too expensive but what happens when we have thousands and thousands of symbols in a library?
Efficiency ● Since we have to demangle all the symbols from the library at least once we could cache this result – Expensive approach: libCore has symbols with an average length of 46 characters when demangled (i.e 614 KB in cache). ● Try to demangle as less as possible. Don't do it more than once or twice and don't even try it if the symbols have been registered. ● I'm not even mentioning the parsing needed between the demangling and the registering.
Are we winning the fight? ● CVS version of ROOT – Libs size: MB – Objects size (dictionaries): MB – Source size (dictionaries):50.37 MB ● Current status of pre-experimental version – Libs size:65.46 MB ( MB, 12%) – Objects size (dict):36.42 MB ( MB, 24%) – Source size (dicti):37.25 MB ( MB, 26%)
In all war sacrifices must be made: space and time overhead Let's start with a “normal” sesion Real time: 0.37 sReal time: s Rootmarks:
First Algorithm: be stupid. Initial attempt: demangle all the symbols in a library for every used class Real time: 0.76 sReal time: s Rootmarks: 184 Spikes due to the silliness of the algorithm. First demangle everything and the register it.
Second Algorithm: don't be so stupid At least remember the classes that have already been registered Real time: 0.77 sReal time: s Rootmarks: Spikes due to the silliness of the algorithm. First demangle everything and the register it.
Third Algorithm: use the RAM Demangle the symbols once and keep them in a cache Real time: 0.69 sReal time: s Rootmarks:
Fourth Algorithm: Axel's idea Keep a pointer to the mangled name and demangle twice (when needed) Real time: 0.68 s Real time: s Rootmarks:
Fifth Algorithm: some tuning A bit of optimization with the structures Real time: 0.56 sReal time: s Rootmarks: 200.1
Algorithms Comparison How much are we willing to pay for this feature??? Demangling takes 15% of the time at startup (100ms). Which means there is still some room for improvement.
Problems so far... a plethora ● Easy ones – ellipsis – parameters by default – free standing functions – weird types like va_list – many more... ● Not so easy: – virtual functions... a real pain in the neck – constructors, destructors (in-charge, deleting, etc) – inline functions – non-member operators –...
Work to be done ● Certain stub functions are not out of the dictionary yet: – Constructors and destructors (Diego is working on it) – Non-member operators – Certain cases for std templates ● Without stubs we can also take the setup_memfunc calls out of the dictionary. ● What else can we take out? – Shadow classes? Show members? Streamers? – Class Inheritance info? typedef? data members info?...?
Future is always bright (dict source) ● CVS Version:50.37MB ● Actual status:37.25MB ( MB, 26.0%) ● No cons, dests:30.09MB ( MB, 40.2%) – Should be there soon enough. ● No memfuncs:17.40MB ( MB, 65.4%) – We still need the info (in a root file for instance). ● No memvars:14.72MB ( MB, 70.7%) ● No inline issue:13.89MB ( MB, 72.4%)
Conclusions ● We have gained a better understanding of C++. ● As my mother used to say: – He who knows not the way, walks with desperation. (fortunately, we finally have an idea of what we are doing and where we want to go) ● A lot of tuning is being done to bring times and memory down to something acceptable. ● We need a considerable amount of time to deal with a myriad of small (and not so small) issues.