From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=0.5 required=5.0 tests=BAYES_00,TO_NO_BRKTS_PCNT autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,ca9eef4d5e2078ea,start X-Google-Attributes: gid103376,public From: gwinn@res.ray.com (Joe Gwinn) Subject: Beware: Rep spec on an enumeration type causes code explosion Date: 1997/12/05 Message-ID: X-Deja-AN: 295667436 Organization: Raytheon Electronic Systems Newsgroups: comp.lang.ada Date: 1997-12-05T00:00:00+00:00 List-Id: We just ran into a real zinger with the Green Hills Ada95 compiler (Solaris host, 68060 target, VxWorks 5.2 target OS), although it appears that the issue may be common to all Ada95 compilers. The symptom at presentation was that the code was at least two orders of magnitude too slow, although it did appear to work correctly, and didn't crash. This system is supposed to run at 64 Hz (with 50% CPU load), but was barely making 4 Hz (at 96% CPU load) while doing a fraction of the full workload, so we are at least a factor of 30 too slow, and more likely a factor of 100 too slow. As they say, this is a problem. Projects have died for less. After the usual round of pointless finger-pointing (and helpful suggestions that we recode the whole thing in C), we built an interrupt-driven system execution profiler and used it to figure out what the hell was going on. Basically, it was spending all of its time in VxWorks, because the Ada RTE was calling on VxWorks at an astounding rate. This was in turn due to two things, the handling of enumeration types, and the registration and deregistration of user-defined exception handlers at every turn. Exception handlers. We were declaring a number of exception handlers at the beginning of each and every module, so every time the module was entered, the context had to be saved, and every time the module was exited, the context was popped off the exception stack and discarded, regardless of if an exception was ever raised. This was easily solved; now, only tasks declare exception handlers, not modules. Enumeration Types. This is the zinger. A 29-line Ada95 program expanded into 1,090 lines of assembly code, a static expansion ratio of 38:1, not the usual 3:1 or 4:1. In this 1,090 lines of assembly, there were multiple calls to the Ada RTE routine "_rts_holey_enumeration" (or the like), which is reported to handle enumeration types that may contain gaps in the mapping sequence, or whose base value (zero or one) isn't known at compile time. At first, we though that the bloat was caused by the use of subranges of enumeration types, but soon discovered that the real problem was caused by the use of representation specifications on enumeration types, and that use of subranges appears to be irrelevant. We have now removed the bulk of the rep specs on enumeration types, just trusting for now that the compiler will always start enumerations at zero, just like C/C++. Ada95 does not specify the base value of an enumeration, so compilers vary. We were using rep specs to govern the representation of Ada records used to generate and understand messages exchanged with display consoles coded in C++. This idiom is used extensively. For portability, we will eventually change the code to remove all ungoverned enumerations. The code now runs something like ten times faster. Fortunately, this one wasn't too hard to fix. Profiling and digging continues; we haven't heard the last of performance problems. Memory Management. The Ada Runtime System makes extensive calls to the C functions malloc() and free(), a cause for worry. Variable-block allocators such as malloc and free are generally unsuited for nonstop heavy use, and will generally either leak memory or fragment their memory pool, causing the application to run slower and slower until it eventually jams. The use of free() in a realtime system is generally forbidden; it's OK to allocate a bunch of memory during startup, and explicitly manage it yourself during operation, but it is not OK to use malloc and free for realtime memory management. The claim is that Wind River's version of malloc/free is stable in realtime use. It's hard to see how this could be true. This will need further research. Summary. One wonders where the other beartraps are. Some compiler gurus seemed to know all about this one, long before we blundered into it, but for some reason could not give timely advance warning. It would have saved considerable travail and fright, and deprived the just-do-it-in-C crowd of a horror story. In the early 1990s, when implementing a communications core in Ada83, we had all manner of problems with similar beartraps. You simply could not tell from the manuals and books which idioms would blow up on you. One assumes that the compiler writers knew what they struggled with, but that information was never published in a useable form, one assumes for PC reasons. The then solution was to try to stay in the Pascal subset of Ada, and to read the generated assembly code to detect code explosions. Ugly, but effective. Not that there was a practical alternative. Even so, we reimplemented the core three or four times before we achieved a stable and reasonable Ada to assembly code expansion ratio. In communications cores, performance is very much the issue, so it was possible to spend that kind of effort getting it just right. Not all projects can afford this. The good news was that the resulting code ported to a new compiler without provoking another code explosion, implying that the explosions were properties of Ada83 the language, and were not due to the vagaries of design of this or that compiler. (Generics did cause problems though.) As the descendant of Ada83, one would expect some of the same behaviour from Ada95, plus the usual new-compiler and new-language teething effects. Question. Is there an Ada95 FAQ or the like, full of suitably dire warnings? I have seen very useful and widely used published books of such things for C and C++, but have never seen anything like it for Ada95. If there isn't yet one, perhaps we should develop one, for our mutual protection. I suppose that the writers of Ada95 compilers know where they struggled with Ada95, as well as Ada83 before it. If it was hard for them to write, it will likely generate lots of code. Joe Gwinn