Development Techniques for Using Simulation to Remove Risk in Software/Hardware Integration


< Prev Contents Next >

Source Level Configuration

The best way to avoid the problems faced by existing configurable systems is, quite literally, at the source. With the proper infrastructure and tools support, source level configuration can be successful and manageable, and the techniques used are simple and already well known to programmers. For most cases, using the C preprocessor provides all the information a programmer needs. For example,

#if defined(_BUFFERED_IO) && (_BUFFER_SIZE > 0)

...

#else

...

#endif

This is well-established syntax for C and C++ programmers. But the C preprocessor is flexible enough to also be used on linker scripts and assembler files. In the case of Makefiles, the GNU make tool provides its own "include", "if" and "ifdef" primitives that can be used instead.

This is a simple and easy approach that can truly solve the problem. In particular it is possible to apply very fine-grained configuration options to the code. This is particularly appropriate for embedded systems since the vast majority of embedded applications compile into static images, rather than dynamically loading executables. In that context, there are many advantages:

  • Smaller

With source level configuration, the code can be adapted perfectly to the level of functionality the developer requires, no matter how fine-grained. If functionality is not used, then it can simply be removed. If the developer knows, for example, that there will only ever be four threads in the system, then the number of threads supported by the kernel scheduler can be reduced. Or perhaps the programmer may be able to reduce the size of I/O buffers, or even eliminate them altogether. There are many more examples.

As a consequence, code and data can be removed; either explicitly because they were directly dependent on the configuration option in question, or indirectly, because the code/data was used in turn by the code that was removed, and so that code is no longer needed, etc.

The upshot is that both ROM and RAM requirements are reduced - good news for the embedded developer.

Some linkers, such as the GNU linker, are even capable of so-called "selective linking", where unreferenced functions and data can be removed. This contrasts with normal linkers that work on an object file basis if any symbol in an object file is referenced, the whole file is pulled in. But selective linking is still insufficient since it is an "all or nothing" approach only whole functions can be removed. A good example is the printf() function: a large amount of code is needed to format floating-point output (%e, %f and %g format specifiers). But since it is impossible to tell whether floating-point has been used until run-time, the code must always be included. Due to this overhead, on many embedded systems, libraries often provide an alternative that does not support floating-point. But this is just an isolated workaround for the more general problem that can only be solved by source-level configuration.

  • Faster

Of course with the complete removal of unused code and data, everything can be faster. Code no longer has to check its configuration using variables to determine the course of action to take. Code may now be able to fit into instruction caches where it couldn't before. Even the download time of the program will be less, thus accelerating the iterative development and testing cycles.

As a result, code can be more responsive, latencies can be reduced (which aids determinism in a real-time system), and cheaper hardware may be used.

  • Simpler

Simplicity can be a goal in itself - since less code is present, there is less code that can go wrong. By using a minimal configuration in safety critical systems, less code needs to be walked through, verified and tested.

  • Tailored

Embedded systems have many different and varying requirements, and the features required of an operating system vary greatly. Rather than the "one size fits all" approach, developers can choose the exact behavior that fits the application. This can be done at a very fine grain, unlike the relatively coarse grain of existing configurable systems.

For example, most systems come with a general-purpose memory allocator, malloc. But on some real-time systems, it is vital the performance is deterministic, i.e. it must be able to allocate and free memory in a known bounded time. But in other embedded applications, memory may be scarce, so efficient usage of the memory becomes the highest priority. These two goals are not reconcilable with a single malloc implementation. But source level configuration allows the user the choice of which to use, rather than imposing a design to suit all.

  • Compatible with run-time configuration

Of course, you can still return to using global variables to control configuration. In fact, once configuration is in place, adding this is simple - just look for the existing configuration switches. For example, it is easy to change:

#ifdef _BUFFERED_IO

...

#endif

to:

#ifdef _BUFFERED_IO

if (_buffered_io) {

...

}

#endif

or even:

#ifdef _BUFFERED_IO

# ifdef _BUFFERED_IO_SET_AT_RUNTIME

if (_buffered_io) {

# endif

...

# ifdef _BUFFERED_IO_SET_AT_RUNTIME

}

# endif

#endif

Perhaps more significantly, if you already have code that is run-time configurable, by looking for where these variables are tested, it may be easy to add compile-time source code configuration switches using the converse of the above.

Linux, autoconf, and automake
Of course, source code configuration by itself is nothing new. The most prolific example used in modern software is the GNU autoconf and automake system. Indeed since Cygnus Solutions specializes in GNU software, at the outset of the design of eCos there was discussion on whether it was suitable as infrastructure.

However, in common with other existing configuration infrastructures, there are a number of drawbacks:

  1. Every option that is to be set away from the default must be explicitly and individually mentioned on the command-line;
  2. All dependency checking must be done by hand;
  3. There is no easy method or interface for a user to navigate through more than a few configuration options;
  4. In particular, there is no easy way for users to navigate through a hierarchy of options.

Overall, the design goals of autoconf are not the same as that of a source configurable embedded system - efforts are directed at portability between hosts (and UNIX hosts at that), not configuration itself. As a configuration infrastructure, it is neither scalable nor particularly appropriate.

There is also the specific case of the configuration of the Linux Operating System kernel. It provides many options, and even provides a graphical utility to navigate through these options. However, the system is a one-off, and again only does manual dependency checking. And while the large number of options may seem to imply that there is a lot of configurability, in fact the vast majority of options deal simply with whether whole modules should be included or excluded the level of configurability is very coarse-grained.

Benefits of the Open Source revolution
There is an obvious issue with moving towards configurable source code systems - you must provide your source code so that people can configure it! For many commercial organizations the thought of this "value leak" has traditionally been an anathema.

But only software supplied with source can have the benefits of source configuration discussed here. This is comparatively easy for the embedded market since most applications are static. However, if dynamic program execution is required, even in a configurable system, this does restrict choice since it is rarely known what services a program may need.

Of course the obvious solution for many companies will simply be to supply source code with their products when purchased. Or perhaps even supply the source code for an extra fee. But there has been a recent massive surge of interest in open source, and many companies are realizing the tremendous benefits of open source software.

For example, Cygnus Solutions has benefited from eCos being both free and open source as it was mutually beneficial to all concerned - the more things that become open source, the more things can be source configurable. For this reason, source configurable software is likely to be a growth area, and this is why it is important that issues related to source configuration must be explored.


< Prev Contents Next >