Share and share alike
A constant challenge I have found, when teaching or mentoring people, is to avoid making assumptions about what they know. I have found that it is so easy to assume that, because something is obvious to me, it is clearly apparent to everyone else. On numerous occasions I have discovered that this not to be the case. Of course, the best response to this realization is not to treat everyone else as stupid, but try to explain something clearly and then listen to the echo back of the explanation.
In developing software – embedded software in particular – there are certain things that are fundamental, particularly around the conservation of resources. More than once I have been surprised by engineers’ inability to focus on this issue …
Many years ago, I was supervising an inexperienced engineer, who was developing the software for a simple telecommunications device. I do not recall all the details, but broadly it managed two separate flows of data. The code was written in assembly language – that is what we did in those days. She had a problem. Although the basic functionality of the device was in place, she still needed to add some more features and was running out of program memory [ROM]. She sought my help. I was surprised by the problem, as the software did not need to be particularly complex and, by the standards of the day, the available memory seemed to be more than enough.
I looked at the code and quickly saw the problem. She had written code to deal with one communications channel [a UART driver] and then made a second copy of the code to handle the other channel. Nobody had ever explained the idea of shared code to her. All that was required was to ensure that the code was reentrant – i.e. all data was directly or indirectly stored in registers or on the stack – and a single copy would suffice. We both learned a lesson that day. The engineer learned about how shared code worked and I learned that it was not obvious to everyone.
Much more recently, I was involved in the technical support of a customer, who exhibited a similar sounding problem. This time, the code was much more complex and written in C. The device was handling ten channels of data. He wanted to enhance the code and had run out of memory. We gave some advice about compiler optimizations, which helped, but not enough. A more detailed look at the code and a few tweaks and we reduced the code’s memory footprint by nearly 90%. I imagine you can guess what happened. He had 10 copies of the same code, which we could reduce to a single one. Of course, ensuring the C code was reentrant was very straightforward, just requiring the absence of statically stored data.
However, we also caused a problem for this customer. Prior to our “fix”, he found debugging was easy: just a matter of putting a breakpoint on the code for a relevant channel. Now, the shared code would stop on a breakpoint, but it would do it for whatever channel happened to use the code next, which was a little confusing. We demonstrated a debugger which could provide task-aware breakpoints and the problem was solved. He was very happy to buy the tool after the spectacular solution to his problem that we provided. It was a win for all concerned.