18-10-2010, 12:10 PM
Autonomic computing.pdf (Size: 251.54 KB / Downloads: 156)
Autonomic computing
Operating Systems and Middleware
Reusable components in embedded systems
Abstract
The paper describes why the software development process in the
embedded world often differs from the academic versions and why
concepts like software reuse is not often seen there. Then it introduces
some solutions that address these problems, namely the feature
oriented domain analysis in form of the CONSUL configuration
support library and the concept of aspect oriented programming in
form of the AspectC++ language.
embedded world often differs from the academic versions and why
concepts like software reuse is not often seen there. Then it introduces
some solutions that address these problems, namely the feature
oriented domain analysis in form of the CONSUL configuration
support library and the concept of aspect oriented programming in
form of the AspectC++ language.
INTRODUCTION
With technology advancing everywhere so called “embedded systems” become more and more important. Embedded systems are computer systems that, unlike a PC for example, are part of a bigger engineering system. Embedded systems control your washing machine, your television set and the air bag in your car. Although the main part of an embedded system is usually just a piece of software, traditional strategies for software engineering typically do not apply. Paradigms like “reusable components”, “object oriented development” or “data abstraction” can not be found often in the embedded area. The reasons for this are many, the main one being cost. The manufacturing of the systems is most often very high volume, and in this case every kilobyte of RAM or ROM matters. The CPUs employed are slow (but well tested and reliable) and the hardware is often very restrained in every aspect, making the software development some kind of a challenge with the result having to exactly fit into the hardware provided strait jacket. Waste is not an option. In terms of languages, embedded system often still employ hand crafted assembler routines or C code at best. Modern software development on the other hand relies on the fact that CPU power and memory is available in abundance, the paradigm being that it's cheaper to add more resources to the hardware than to develop a more restrained software. The languages get more and more high level, relieving the programmer of the hassle of interacting with the hardware directly so that they can concentrate more on the “big picture”. This especially makes reusable components easy, one just implements (or let somebody else implement, like in standard libraries) the most powerful version one can think of and uses this solution for all occurrences of a similar problem. One size fits all. Or should fit all. In practice components often have to be reworked several times until they are truly reusable, but this is outside of the topic of this paper. The following chapters will present some concepts that try to remedy the problem. At first the feature oriented domain analysis will be introduced and an example written for the CONSUL configuration support library will be presented. After that the concept of aspect oriented programming will be explained, with examples in the AspectC++ language. And finally the conclusions chapter will summarize and evaluate the things described in this paper.
One size does not fit all
The example stated in [FESC] to illustrate the point that embedded systems can have pretty specific needs is based on the cosine function, and as this example is just too good and illustrative to pass on it will also be used here. Processors in embedded systems usually do not have a floating point calculation unit and therefore floating point arithmetics can be quite expensive. At the same time CPU power is limited, therefore a high precision cosine calculation function does not always provide the optimal trade-off. There are a few different imaginable scenarios: 1. An exact value is needed, time does not matter 2. Only a rough approximation is needed, but that very quickly 3. The function domain only includes a few discrete values, but those need to be provided fast and in high precision. In modern software engineering all three cases would probably be served by the same function. The compiler will most likely even translate it into a single native processor instruction, in the case of the x86 architecture into an FCOS instruction, which on a Pentium 4 Northwood core only needs a blazing 240 clock cycles in worst case [IA32O]. Considering clocks in the range of several gigahertz this is virtually nothing. For embedded processors whose speed is usually still measured in one or two digit megahertz values, different implementations for the 3 cases become the only option. Case one could be served by an iterative function that returns once the result becomes stable, case 2 can be solved by interpolating between known values and case 3 is an ideal prerequisite for probably the oldest software trick known to mankind: the table lookup. Example source code for all 3 variants can be found in [FESC]. Now, despite those circumstances, component reuse is highly desirable. For once, re-inventing the wheel is never a particularly good idea. It is expensive, valuable time is wasted and the resulting implementation is often not as highly tested as it would be with standard components. A library aimed at code-reuse in embedded systems should therefore provide all 3 implementations. But this already poses some questions: 1. How does one know which implementation suits the problem best? 2. How can several implementations co-exist in one and the same library? One could use some informal description in the function headers to distinguish between the different version and give the functions different names, like CosIterate, CosAverage and CosTable. On first glance this could solve both problems, but even with this very limited example the naming scheme already looks ugly and impractical and the whole method is not feasible for a library with a higher function count. A C programmer of course could counter point one with the software equivalent of a hammer, the preprocessor: #define Cos(x) CosTable(x) This way one can still write code independent from the actual implementation used, but this too is only feasible with a limited amount of functions, as it involves a lot of manual work and care.