Implementierung Efficient C Code for ARM Devices
In any development, some degree of “optimization” is almost inevitable in order to develop software which is performant and efficient. When optimizing software, it is crucial to establish your optimization goals and then work within the capabilities and constraints of the tools, the language, the processor and the target system to realize the best possible outcome.
Software engineers don’t just eat pizza and drink coffee! They spend a lot of time developing software. But how do they really spend that time. Surveys show that the greatest portion is spend on optimizing, reviewing and maintaining existing code. The smallest part is spent actually writing new code. So optimization is a major activity for the majority of engineers.
Optimization is a combination of several activities, working towards a variety of goals. You may care about speed, or code size, or data size, or the amount of data processing, or a number of other criteria. These goals are often mutually exclusive. For instance, faster code is typically larger code. The key is to decide on a goal and work consistently towards that.
Coding standards do not often mention optimization. Instead, they concentrate on things like reliability, readability, portability and so on. These are all very admirable goals but none of them address the efficiency of your code. When asked what they themselves really care about, however, engineers report “performance” as their top priority.
There is a key difference between the priorities of coding standards and the priorities of the engineers who actually write the code. So how do we resolve this?
I believe that an engineer should always prioritize the coding standard rules, for example readability, over considerations of performance. Sometimes, though, it is necessary to break those rules in order to achieve some optimization goal. This means that it is extremely important to identify very carefully those areas in which you are to concentrate your optimization efforts.
A good simple rule is that 90% of the execution time is spent in 10% of the code. So, use whatever tools you have to identify that 10% and spend 90% of your time optimizing it. That way, you get the biggest payback.
“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%,” says Donald Knuth (to whom all software engineers should pay serious attention!).
We now consider several areas in which you can optimize your code: Language, Hardware, Tools and Platform.
When writing in almost any high level language, and here we concentrate on C as it is most widely used by far, it is important to remember that “fewer lines of code does not make it faster”. For instance, writing complex expressions on one line is no faster than splitting the same expression over multiple lines, possibly making use of temporary variables to split it over several statements. In fact, short code is sometimes slower.
What is undeniable is that shorter, compressed code is always harder to read, harder to review and harder to maintain.
Be careful of any ambiguity in the language. For instance, compiler writers are free to choose whether the char type is signed or unsigned. And ambiguity sometimes extends to the underlying machine as well. For instance, different hardware architectures will behave differently when asked to shift a 32-bit variable left by more than 32 bits.
The following example results in unpredictable behavior unless the signed-ness of the char type is known at compile-time.
The following results in undefined behavior. It is not actually valid C code but the result depends on which processor the code is executed.