Tuesday, June 27, 2006

Mind your struct's!

This should be elementary to seasoned C programmers but one rule of thumb is, in a struct, one should arrange the fields based on the size of their types in reverse order. This would typically lead to a more compact struct which can be crucial to an embedded system with limited memory. To illustrate, struct_a below is a struct similar to what I've found in a library provided by a partner of my company. One the other hand, struct_b is the same struct but with its fields "properly ordered". In addition, the array arr_a also appears in similar fashion in the partner's library.

#include

struct struct_a {
short f1;
char f2;
int f3;
char f4;
};

struct struct_b {
int f3;
short f1;
char f2;
char f4;
};

struct struct_a arr_a[32];
struct struct_b arr_b[32];

int main() {
printf("sizeof(struct_a):%d\n", sizeof(struct struct_a));
printf("sizeof(struct_b):%d\n", sizeof(struct struct_b));
printf(" sizeof(arr_a):%d\n", sizeof(arr_a));
printf(" sizeof(arr_b):%d\n", sizeof(arr_b));
return 0;
}
Compiling the code above using the GNUARM toolchain and running it the ARM simulator in GDB, we get this output:

sizeof(struct_a):12
sizeof(struct_b):8
sizeof(arr_a):384
sizeof(arr_b):256
Simply by reordering the fields, we could save 4 bytes in the struct and 128 bytes from the array above. Another example is given below. Again struct_a is something found in the library and struct_b is an optimized version of the struct.

#include

struct struct_a {
short f1;
int f2;
char f3;
char f4;
short f5;
char f6;
short f7;
short f8[3];
};

struct struct_b {
int f2;
short f8[3];
short f1;
short f7;
short f5;
char f3;
char f4;
char f6;
};

struct struct_a arr_a[32];
struct struct_b arr_b[32];

int main() {
printf("sizeof(struct_a):%d\n", sizeof(struct struct_a));
printf("sizeof(struct_b):%d\n", sizeof(struct struct_b));
printf(" sizeof(arr_a):%d\n", sizeof(arr_a));
printf(" sizeof(arr_b):%d\n", sizeof(arr_b));
return 0;
}
The output of the program compiled through GNUARM toolchain is given below.

sizeof(struct_a):24
sizeof(struct_b):20
sizeof(arr_a):768
sizeof(arr_b):640

Again, we could save 4 bytes from the struct and 128 bytes from the array. Note that struct_b above has a short array with 3 elements as a field. Why it was not made the first field of struct_b? After all it is bigger than an int. It has something to do with int alignment on ARM. Try it out and see.

Friday, June 23, 2006

Using interrupts for super responsive tasks?

I read an interesting article at Embedded.com titled "A data-centric OS for MCUs using a real-time publisher-subscriber-mechanism: Part1" and it is very interesting. Typically, in embedded system, you would use a preemptive OS which run tasks based on task priorities on a predefined timeslice. This article, however, proposes a publish-and-subscribe task model using interrupts and interrupt priorities. So no OS in the traditional sense. Basically, each task is an interrupt handler.

A task can be a consumer or a producer. The producer task would trigger an interrupt through software when an interesting event occurs. The consumer task would subscribe to that event by registering an interrupt handler as the event call back function. The interrupt priorities would be used to decide which event handler would be called in the event that many event handlers are eligible to run. Nested interrupt is also enabled.

The interrupt controller we are using for our SoC supports up to 64 interrupt sources that can also be programmatically triggered. It also has 16 interrupt priorities with programmable interrupt handler each to play with. It would be interesting to see how the suggested technique in the article could be mapped to it.