Archive for June, 2012

The Crap Code Conundrum

Friday, June 29th, 2012 Nigel Jones

Listed below are three statements. Based on my nearly thirty years in the embedded space I can confidently state that: One I have never heard stated. Another I have rarely heard stated, and the third I hear a lot. Here they are in order:

  1. I write crap code.
  2. You know so-and-so. (S)he writes really good code.
  3. This code is complete crap.

If your experience comports with mine, then it leads to what I have coined the ‘crap code conundrum’. In short, crap code is everywhere – but no one admits to or realizes they are writing it! So how can this be? Well I see several possibilities:

  1. In fact a lot of so called crap code is labeled as such because the author did things differently to the way the reader would have done it. I think it’s important to recognize this before summarily dismissing some code. Notwithstanding this, I all too often find myself saying ‘this code is complete crap’ – because it is!
  2. This is related to point 1, and essentially comes down to different people have different ideas about what constitutes good code. For example I think wrapping code in complex macros is an invitation for disaster. Others see it as a perfectly good way of simplifying things. (I’m right :-))
  3. The code started out being pretty good and has degenerated over time because the author hasn’t been allowed the time to perform the necessary refactoring. I think this does explain a lot of the bad code I see.
  4. The folks that write crap code are completely oblivious to the fact they are doing it. Indeed it’s only the self aware / self critical types that would even bother to ask themselves the question ‘is my code any good?’ Indeed, the first step to improving ones code is to ask oneself the question – how can I improve my code?

My gut feel is that point 4 is most likely the main cause. Now if you are so self-absorbed that you wouldn’t even dream to ask yourself the question ‘do I write crap code?’, then I seriously doubt whether you’d be reading this article. However if you have crossed this hurdle, then how can you determine if the code you are writing is any good? Well I took a stab at this a while back with this article . However some of the commenters pointed out that it’s quite easy to write code that has good metrics – yet is still complete crap. So clearly the code metrics approach is part of the story – but not the entire story.

So a couple of weeks ago I found myself in a bar in San Francisco having a beer with Michael Barr and a very smart  guy Steve Loudon. The topic of crap code came up and I posed the question ‘how can you tell code is crap?’ After all I think that crap code is a bit like pornography – you know it when you see it. After a spirited debate, the most pithy statement we could come up with is this:

If it’s hard to maintain, it’s crap.

Clearly there are all sorts of exceptions and qualifications, but at the end of the day I think this statement pretty much says it all. Thus if you are wondering if you write crap code, just ask yourself the question – how hard is this code to maintain? If you don’t like the answer, then it’s time to make a change.

 

 

 

Optimizing for the CPU / compiler

Sunday, June 3rd, 2012 Nigel Jones

It is well known that standard C language features map horribly on to the architecture of many processors. While the mapping is obvious and appalling for some processors (low end PICs, 8051 spring to mind), it’s still not necessarily great at the 32 bit end of the spectrum where processors without floating point units can be hit hard with C’s floating point promotion rules. While this is all obvious stuff, it’s essentially about what those CPUs are lacking. Where it gets really interesting in the embedded space is when you have a processor that has all sorts of specialized features that are great for embedded systems – but which simply do not map on to the C language view of the world. Some examples will illustrate my point.

Arithmetic vs. Logical shifting

The C language does of course have support for performing shift operations. However, these are strictly arithmetic shifts. That is when bits get shifted off the end of an integer type, they are simply lost. Logical shifting, sometimes known as rotation, is different in that bits simply get rotated back around (often through the carry bit but not always). Now while arithmetic shifting is great for, well arithmetic operations, there are plenty of occasions in which I find myself wanting to perform a rotation. Now can I write a rotation function in C – sure – but it’s a real pain in the tuches.

Saturated addition

If you have ever had to design and implement an integer digital filter, I am sure you found yourself yearning for an addition operator that will saturate rather than overflow. [In this form of arithmetic, if the integral type would overflow as the result of an operation, then the processor simply returns the minimum or maximum value as appropriate].  Processors that the designers think might be required to perform digital filtering will have this feature built directly into their instruction sets.  By contrast the C language has zero direct support for such operations, which must be coded using nasty checks and masks.

Nibble swapping

Swapping the upper and lower nibbles of a byte is a common operation in cryptography and related fields. As a result many processors include this ever so useful instruction in their instruction sets. While you can of course write C code to do it, it’s horrible looking and grossly inefficient when compared to the built in instruction.

Implications

If you look over the examples quoted I’m sure you noticed a theme:

  1. Yes I can write C code to achieve the desired functionality.
  2. The resultant C code is usually ugly and horribly inefficient when compared to the intrinsic function of the processor.

Now in many cases, C compilers simply don’t give you access to these intrinsic functions, other than resorting to the inline assembler. Unfortunately, using the inline assembler causes a lot of problems. For example:

  1. It will often force the compiler to not optimize the enclosing function.
  2. It’s really easy to screw it up.
  3. It’s banned by most coding standards.

As a result, the intrinsic features can’t be used anyway. However, there are embedded compilers out there that support intrinsic functions. For example here’s how to swap nibbles using IAR’s AVR compiler:

foo = __swap_nibbles(bar);

There are several things to note about this:

  1. Because it’s a compiler intrinsic function, there are no issues with optimization.
  2. Similarly because one works with standard variable names, there is no particular likelihood of getting this wrong.
  3. Because it looks like a function call, there isn’t normally a problem with coding standards.

This then leads to one of the essential quandaries of embedded systems. Is it better to write completely standard (and hence presumably portable) C code, or should one take every advantage of neat features that are offered by your CPU (and if it is any good), your compiler?

I made my peace with this decision many years ago and fall firmly into the camp of take advantage of every neat feature offered by the CPU / compiler – even if it is non-standard. My rationale for doing so is as follows:

  1. Porting code from one CPU to another happens rarely. Thus to burden the bulk of systems with this mythical possibility seems weird to me.
  2. End users do not care. When was the last time you heard someone extoll the use of standard code in the latest widget? Instead end users care about speed, power and battery life. All things that can come about by having the most efficient code possible.
  3. It seems downright rude not to use those features that the CPU designer built in to the CPU just because some purist says I should not.

Having said this, I do of course understand completely if you are in the business of selling software components (e.g. an AES library), where using intrinsic / specialized instructions could be a veritable pain. However for the rest of the industry I say use those intrinsic functions! As always, let the debate begin.